
检查前的工作区里有个改动行尾多了空格。执行 git diff --check,终端指出了行号;换成只暂存的修改,命令却干净退出。再放一个未跟踪文件进去,仍然没有提示。命令名里的 check 容易让人以为仓库已被全面扫描,实际检查对象取决于 git diff 展示的那部分差异。
以下结果来自 tools/verify-git-diff-check-whitespace.py:脚本在系统临时目录初始化仓库、提交基线,再分别制造几种差异;退出时临时目录自动清除。原始输出保存在 tools/git-diff-check-whitespace.log。本机 Git 为 2.50.1(Apple Git-155)。没有在博客仓库里制造这些改动。
空输出不等于暂存区干净
先看一个误读:暂存了文件,就认为普通 git diff --check 已经检查过它。实验里,未暂存的新行末尾有三个空格,普通命令报告 trailing whitespace,退出码是 2。把这份改动加入 index 后,普通命令退出码变为 0;换成 --cached 才再次报告同一行。
$ git diff --check
exit: 2
stdout: work.txt:2: trailing whitespace.
+new line
stderr: (empty)
$ git diff --check
exit: 0
stdout: (empty)
stderr: (empty)
$ git diff --cached --check
exit: 2
stdout: work.txt:2: trailing whitespace.
+new line
stderr: (empty)
$ git diff HEAD --check
exit: 2
stdout: work.txt:2: trailing whitespace.
+new line
stderr: (empty)
这条输出变化没有清掉空白问题:差异视角从工作区与 index 之间,切到了 index 与当前提交之间。普通 git diff 默认看前一段;git diff --cached(也可写 --staged)看后一段。准备提交时,只跑普通形式会漏掉已经暂存的空白错误。若想同时覆盖两种已跟踪改动,可以依次跑:
git diff --check
git diff --cached --check
脚本中两条命令各自的输出分开记录,避免把「工作区已检查」误记成「待提交内容已全部检查」。还有一种写法是 git diff HEAD --check:实验里它在改动已暂存时仍报告同一行,因为比较端点回到了当前提交。这个写法把已跟踪文件的暂存与未暂存差异放进同一个比较,适合需要检查整体待提交补丁时使用;若需要判断问题来自哪一层,分开运行两条命令更容易定位。
新文件根本没进入这份差异
第二个误读是把未跟踪文件也算进 git diff --check。实验创建 untracked.txt,内容末尾有空格,普通命令仍然返回 0、没有输出。Git 的普通差异视图不会把未跟踪文件作为补丁内容,因此 --check 无从检查它。忽略文件也不在这个命令的默认差异里。
单纯把命令换成 git diff --cached --check 仍覆盖不到未跟踪文件:新文件先要被加入 index,才能进入暂存差异。可以用 git status --short 看是否仍有 ?? 项;这些路径若也要纳入提交前检查,需要先决定是否跟踪,再检查已暂存差异,或用单独的文件扫描工具处理未跟踪内容。不要为让检查通过而盲目 git add -A,那会改变暂存范围,也可能把不该提交的本地文件加进去。检查结果要和状态列表一起看:如果状态里还留着未跟踪路径,空白检查的空输出并没有覆盖它。常见做法是在编辑器保存时处理新文件格式,或者明确地把目标文件加入暂存区后再检查;具体采用哪种,要服从仓库的提交约定。若目录里有生成物或本地数据,先确认忽略与跟踪边界,比扩大暂存范围更稳妥。
旧空白和新空白不是一回事
第三个误读是把 --check 当成全文件格式审计。基线提交里的 legacy.txt 已有一行尾随空格;只改动下一行时,检查没有提示。它盯的是差异里新增的内容,不会因为文件某个未改动位置存在历史空白就报错。要清理旧文件,需专门扫描文件内容,不能靠一次差异检查补做历史清理。
新加的缩进行也有边界:实验写入「空格后接制表符」,--check 报 space before tab in indent。这种情况和行尾空格一样,属于实际识别到的空白错误。别把它泛化成「所有空格和 Tab 混用都会被报错」;本次没有验证每一种缩进配置,也没有穷举 core.whitespace 的自定义规则。
最后还要看命令作用于哪一组提交。git diff HEAD --check 可以比较工作区内容与 HEAD,把已暂存和未暂存的跟踪文件变化放在同一对比里;它仍不会自动纳入未跟踪文件,也不会扫描没有差异的旧内容。检查某个提交之间的差异,则应明确指定比较范围。命令退出成功只说明这次选定的差异中没有被识别出的空白错误,不是仓库整洁证明。
我会把 git diff --check 当作补丁检查,不当作全仓库 lint。准备提交时至少分别检查工作区差异和暂存差异;超出差异范围的内容,另设相应扫描。看到空输出,先确认检查范围,再把它当结论。