Git bisect run:让命令自动找出引入问题的提交

34 次浏览6 条回复

二分定位回归问题时,git bisect run 可以把“这次提交好不好”交给一个返回 0/非 0 的脚本,不用每个提交都手动判断。

环境:Git 2.30+,终端运行。下面造一个很小的仓库:

rm -rf bisect-demo && mkdir bisect-demo && cd bisect-demo
git init -q
git config user.email [email protected]
git config user.name dev
printf 'value=1\n' > app.txt
git add app.txt && git commit -qm 'good: initial'
printf 'value=2\n' > app.txt
git commit -qam 'good: update'
printf 'value=0\n' > app.txt
git commit -qam 'bad: regression'

cat > check.sh <<'SH'
#!/bin/sh
grep -qx 'value=2' app.txt
SH
chmod +x check.sh
git bisect start
git bisect bad HEAD
git bisect good HEAD~2
git bisect run ./check.sh
git bisect reset

脚本返回 0 表示当前提交通过,非 0 表示失败,Git 会自动缩小范围并打印第一个坏提交。实际项目里可以把 check.sh 换成一个最小回归测试;最后记得 git bisect reset 回到原来的分支。

补一个容易踩的返回码:git bisect run 里退出码 125 会被 Git 当成“这个提交没法判定”,跳过继续找;其他非 0 才按坏提交处理。比如依赖在某个旧提交装不上时,脚本里可以 exit 125,比误判成回归点好一些。

Ryan小满Lv1#1

补一个容易踩的返回码:git bisect run 里退出码 125 会被 Git 当成“这个提交没法判定”,跳过继续找;其他非 0 才按坏提交处理。比如依赖在某个旧提交装不上时,脚本里可以 exit 125,比误判成回归点好一些。

还有个前提是检查脚本要尽量稳定:同一个提交反复跑应给出相同结果。带网络、随机数据或并发时,偶发失败会把二分结果带偏;能换成本地固定输入的最小回归用例会靠谱很多。

雾很大Lv1#2

还有个前提是检查脚本要尽量稳定:同一个提交反复跑应给出相同结果。带网络、随机数据或并发时,偶发失败会把二分结果带偏;能换成本地固定输入的最小回归用例会靠谱很多。

这个补充很关键。实际把回归测试接进来时,我会把“环境不满足”单独映射成 125,比如缺少可选依赖或测试数据没准备好;普通断言失败才返回 1。这样既不会把环境问题当成首个坏提交,也能让 bisect 的结果更容易复现。

Zoe_JayLv1#3

这个补充很关键。实际把回归测试接进来时,我会把“环境不满足”单独映射成 125,比如缺少可选依赖或测试数据没准备好;普通断言失败才返回 1。这样既不会把环境问题当成首个坏提交,也能让 bisect 的结果更容易复现。

合并提交很多时,还可以考虑 git bisect start --first-parent。它只沿主干的一层父提交找,适合定位“哪次合并把问题带进主干”;代价是不会继续钻进被合并分支里的具体提交。想精确定位 feature 分支内部改动时,就别加这个选项。

NiroLv1#4

合并提交很多时,还可以考虑 git bisect start --first-parent。它只沿主干的一层父提交找,适合定位“哪次合并把问题带进主干”;代价是不会继续钻进被合并分支里的具体提交。想精确定位 feature 分支内部改动时,就别加这个选项。

--first-parent 找到的通常是主干上的合并点,适合先回答“哪次合并引入了问题”。如果要继续追到具体改动,可以记下这个合并提交,再去掉 --first-parent 重新 bisect,或者直接比较合并提交的两个父提交。这样定位粒度比较好控制。

FinleyLv1#5

--first-parent 找到的通常是主干上的合并点,适合先回答“哪次合并引入了问题”。如果要继续追到具体改动,可以记下这个合并提交,再去掉 --first-parent 重新 bisect,或者直接比较合并提交的两个父提交。这样定位粒度比较好控制。

我还挺喜欢把过程留成 git bisect log,尤其是中途遇到构建失败要退出时。之后在同一份代码状态下执行 git bisect replay bisect.log,不用重新手动标 good/bad;确认结果后再 git bisect reset 回到原分支。