sem 使用教程:只看某个文件变化怎么传参?附常见命令
一篇实用上手文,讲清 `sem` 的基本使用方式,重点解释只看单文件变化时为什么要用 `sem diff -- path/to/file`,并补充 `diff / entities / blame / log / impact / context / verify` 等常见命令。
如果你已经把 sem 装到本机,最该先记住的一件事就是:sem diff 基本沿用了 git diff 的传参习惯。
这件事很重要,因为很多人第一次用 sem 时,会把它当成一个全新的命令行工具去记参数。其实没必要。当前版本的 sem diff --help 已经写得很直接:它支持 git diff syntax,参数里可以传 git refs, files, or pathspecs,也支持 -- paths 这种写法。
所以,如果你的问题是:
我只想看某一个文件的变化,怎么传?
最稳妥的答案就是这一条:
sem diff -- src/foo.ts
为什么这里要写 --
因为在 git diff 的世界里,-- 前面的内容更像版本范围、提交参数或者别的选项,-- 后面的内容才明确表示“这是路径”。
既然 sem diff 明说兼容 git diff 的参数风格,那你就应该按 Git 的脑子来用它。这样最不容易歧义,也最不容易在分支名、commit 和文件路径之间撞车。
我本机直接做了一个最小验证:在临时 Git 仓库里同时改两个文件,然后执行 sem diff -- a.ts,输出只保留了 a.ts 的语义变化。这不是猜测,是实际跑过的。
最常用的几条 sem diff 命令
如果你只是日常用 sem 看改动,先记住下面几条就够了。
看当前工作区里所有未提交改动:
sem diff
只看某个文件的未提交改动:
sem diff -- src/foo.ts
只看已暂存的改动:
sem diff --staged
只看已暂存里某个文件的改动:
sem diff --staged -- src/foo.ts
看一个提交范围里的改动:
sem diff HEAD~1..HEAD
看一个提交范围里某个文件的改动:
sem diff HEAD~1..HEAD -- src/foo.ts
同时筛多个文件也一样:
sem diff -- src/foo.ts src/bar.ts
sem diff src/foo.ts 能不能用
当前版本里,这种写法也是能跑的:
sem diff src/foo.ts
但我不建议你把它当成长期习惯。
原因很简单。今天这个参数也许能被正确理解成文件路径,明天你在一个更复杂的命令里混进了分支名、commit range,或者路径刚好和别的名字撞上,就容易产生歧义。
所以我的建议一直很简单:
只要你在按“路径过滤”思路用 sem diff,就默认写成 -- 路径。
也就是:
sem diff -- src/foo.ts
而不是:
sem diff src/foo.ts
前者更像 Git,也更稳。
再补一组高频 diff 用法
如果你不只是“看一下改动”,而是想把 sem 真的塞进日常工作流,那下面这些也很常用。
看某个提交本身的变化:
sem diff --commit HEAD
看更细一点的实体内联变化:
sem diff -v -- src/foo.ts
输出成 JSON,方便喂给脚本、工具链或者 AI:
sem diff --format json -- src/foo.ts
输出成 Markdown,适合贴到文档或评论区:
sem diff --format markdown HEAD~1..HEAD -- src/foo.ts
只分析某几种扩展名:
sem diff --file-exts .ts .tsx
在别的仓库目录里直接执行:
sem diff -C /path/to/repo -- src/foo.ts
除了 diff,这些命令也很常用
如果你把 sem 只当成一个“更聪明的 diff”,其实只用到它一半能力。下面这几条,才是它和普通 Git 工具真正拉开差距的地方。
列出一个文件里的语义实体:
sem entities src/foo.ts
如果你要拿给脚本处理,也可以直接出 JSON:
sem entities src/foo.ts --json
看一个文件里每个实体最后是谁改的:
sem blame src/foo.ts
追某个函数、类或者方法在 Git 历史里的演化:
sem log someEntity
如果同名实体不止一个,最好显式带上文件路径:
sem log someEntity --file src/foo.ts
如果你还想看每次演化里的内容差异:
sem log someEntity --file src/foo.ts -v
看改动一个实体会影响到谁:
sem impact someEntity --file src/foo.ts
只看它直接依赖了什么:
sem impact someEntity --file src/foo.ts --deps
只看谁依赖它:
sem impact someEntity --file src/foo.ts --dependents
只看受影响的测试:
sem impact someEntity --file src/foo.ts --tests
给某个实体抽一份 token budget 受控的上下文,适合喂给 AI:
sem context someEntity --file src/foo.ts --budget 4000
检查函数签名变化有没有把调用方搞坏,尤其适合改完参数列表以后跑一遍:
sem verify --diff
如果你要全量扫当前代码库:
sem verify
这个工具到底是怎么用的
如果你不是只想解决“单文件过滤”这个点,而是想知道 sem 平时该怎么上手,我会这样理解它:
sem 不是替代 Git 的版本控制,而是给 Git 的 diff 增加一层语义视角。
普通 git diff 更擅长告诉你:哪一行变了、哪几行被删了、哪几行被加了。
而 sem diff 更擅长告诉你:哪个函数变了、哪个类、方法、变量定义变了,以及这些变化在代码结构上意味着什么。
如果你平时 review 代码时最烦“几十行 patch 里看不出核心改动点”,那 sem 的价值就很明显。
我对这个工具的建议用法
如果你刚装好 sem,别一上来就把全部命令都背下来。先把 diff 用顺手。
我建议顺序是这样的:
- 先跑
sem diff,感受一下它和普通git diff的区别 - 接着学会用
-- 路径只盯某个文件 - 再加上
-v、--format json、--format markdown这些实用输出方式 - 然后开始用
entities、blame、log理解代码结构和历史 - 最后把
impact、context、verify --diff这些命令接进 review 和重构流程
对大多数人来说,真正高频的还是这几类:看当前改动、看 staged 改动、看某个提交范围里某个文件的改动、看某个实体的历史、看签名改动有没有波及调用方。
把这几条跑顺了,sem 基本就已经能进你的日常工作流了。
最后给一个最短答案
如果你看到这里,只想拿一句能直接复制的结论,那就是:
sem diff -- 你的文件路径
比如:
sem diff -- lib/main.dart
sem diff -- src/foo.ts
sem diff HEAD~1..HEAD -- src/foo.ts
一句话总结就是:sem diff 可以按 Git 的 pathspec 方式传路径。只看某个文件时,优先写 -- 文件路径,这是当前最稳、最不容易歧义的用法。