Git:提交前用 diff --check 找出空白错误和冲突标记

116 次浏览3 条回复

提交前想做一层不依赖语言工具链的检查,可以先跑 git diff --check。它会检查这次改动新引入的空白错误,也能提示残留的冲突标记;发现问题时返回非零状态,放进脚本或 CI 都比较顺手。

环境:Git 2.39+;Linux 或 macOS;Bash;需要 mktemp。下面只操作新建的临时仓库:

set -eu

repo=$(mktemp -d)
trap 'rm -rf -- "$repo"' EXIT

git init -q -b main "$repo"
git -C "$repo" config user.name "Diff Check Demo"
git -C "$repo" config user.email "[email protected]"
printf 'clean line\n' >"$repo/note.txt"
git -C "$repo" add note.txt
git -C "$repo" commit -qm 'initial'

printf 'line with trailing spaces   \n' >"$repo/note.txt"

if git -C "$repo" diff --check; then
  printf 'expected worktree check to fail\n' >&2
  exit 1
fi

git -C "$repo" add note.txt
if git -C "$repo" diff --cached --check; then
  printf 'expected staged check to fail\n' >&2
  exit 1
fi

未暂存的改动用 git diff --check,已经 git add 的内容则用 git diff --cached --check。它不是格式化器,也不会检查没有变化的旧代码;适合做一道很快的提交前检查。项目调整过 core.whitespace 时,判定规则也会跟着配置变化。

补一个 CI 里容易漏掉的点:干净 checkout 上直接跑 git diff --check,比较的是工作区和索引,通常没有内容可查。要显式给提交范围。

例如 Git 2.39+,runner 已经拉到目标分支基线提交时:

git diff --check "$BASE_SHA"...HEAD

这里 BASE_SHA 应该是目标分支的提交,浅克隆场景还得先确保该提交可用。只检查当前这个提交,也可以用 git show --check --format= HEAD。

ZiorLv1#1

补一个 CI 里容易漏掉的点:干净 checkout 上直接跑 git diff --check,比较的是工作区和索引,通常没有内容可查。要显式给提交范围。

例如 Git 2.39+,runner 已经拉到目标分支基线提交时:

git diff --check "$BASE_SHA"...HEAD

这里 BASE_SHA 应该是目标分支的提交,浅克隆场景还得先确保该提交可用。只检查当前这个提交,也可以用 git show --check --format= HEAD。

这个 CI 口径还要补一个边界:git diff --check 只看 diff,不会扫未跟踪文件。比如构建步骤生成了一个带行尾空格的 generated.txt,即使检查返回 0 也不会报。若 CI 确实要把这类文件纳入检查,可以在一次性 runner 里先跑 git add -N -- generated.txt(只登记路径,不把内容放进暂存区),再跑 git diff --check;如果生成物不该入库,记得最后清掉这个 intent-to-add 状态,别让检查过程改变提交内容。

拿它做 pre-commit hook 时,最好只检查索引。部分暂存文件里,工作区可能还有这次不准备提交的空白错误;裸跑 git diff --check 不但没检查暂存内容,还可能被这些无关改动拦住。

环境是 Git 2.39+ 和 POSIX shell,最小 hook 可以写成:

#!/bin/sh
exec git diff --cached --check

放到 .git/hooks/pre-commit 后加执行权限即可。团队要跟踪 hook 文件的话,也可以放进 .githooks/pre-commit,再在仓库里执行 git config core.hooksPath .githooks。这样部分暂存时,检查范围和真正要提交的快照是一致的。