当一段较长的提交历史里出现回归,并且已有命令能判断当前版本是否正常时,git bisect run 可以把二分查找自动化。测试脚本的退出码就是判定协议:0 表示正常,1 到 127(除 125)表示异常,125 表示当前提交无法测试;其他退出码会中止本次查找。
环境:Git 2.39+、Bash;Linux 或 macOS。下面的示例只在新建的临时目录中运行,不会改动现有仓库。
先构造一段包含回归的历史,并给已知正常、已知异常的两端打标签:
tmp="$(mktemp -d)"
cd "$tmp"
git init -b main
git config user.name "Bisect Demo"
git config user.email "demo@example.invalid"
printf 'mode=fast\n' > app.conf
git add app.conf
git commit -m 'good: use fast mode'
printf 'note=baseline\n' > notes.txt
git add notes.txt
git commit -m 'docs: add baseline note'
git tag known-good
printf 'mode=slow\n' > app.conf
git commit -am 'refactor: change processing mode'
printf 'note=follow-up\n' >> notes.txt
git commit -am 'docs: add follow-up note'
printf 'note=release\n' >> notes.txt
git commit -am 'docs: add release note'
git tag known-bad
再创建判定脚本。这里把 mode=fast 当作正常状态,grep 的退出码恰好符合 bisect 的判定协议:
cat > check.sh <<'EOF'
#!/usr/bin/env bash
grep -qx 'mode=fast' app.conf
EOF
chmod +x check.sh
git bisect start known-bad known-good
git bisect run ./check.sh
git bisect reset
运行过程中 Git 会反复检出中间提交并执行脚本,最后报告 first bad commit;示例中会定位到修改 app.conf 的提交。git bisect reset 会恢复开始二分前检出的分支。
在真实项目中,可以把 ./check.sh 换成单元测试、编译检查或最小复现脚本。需要特别区分三种结果:功能断言失败应返回普通非零值;提交因为缺少生成物等原因无法判断时返回 125;网络中断、测试环境损坏等基础设施故障不应伪装成回归,可以返回 128 让查找停止。开始前也应保持工作区干净,避免反复切换提交时混入本地修改。