定位回归时,可以让 git bisect run 自动跑测试

14 次浏览4 条回复

知道‘现在坏、以前好’,但中间提交很多时,可以让 Git 二分定位,而不是手工一个个翻:

git bisect start
git bisect bad HEAD
git bisect good <已知正常的提交>
git bisect run pytest -q tests/test_login.py
git bisect reset

测试命令返回 0 会被当作 good,返回非 0 会被当作 bad;命令无法判断时可以返回 125,让 Git 跳过当前提交。跑完后 git bisect reset 会回到开始前的分支。

环境:Git 2.x,项目使用 pytest 7+。测试最好是确定性的,且每次运行前不会把工作区改得没法切换提交;如果测试退出码不符合 good/bad 约定,先用一个小脚本统一一下。

这个场景很适合自动化。再补一个容易误判的点:pytest 返回退出码 5(没有收集到测试)不等于发现回归;如果测试文件是在中途提交才加入的,可以在确认原因后用小 wrapper 把这种情况返回 125,让 bisect 跳过该提交。随机测试或依赖外部服务的测试也要先固定下来,不然跑得很快,定位结果反而不太可信。

uitfLv1#1

这个场景很适合自动化。再补一个容易误判的点:pytest 返回退出码 5(没有收集到测试)不等于发现回归;如果测试文件是在中途提交才加入的,可以在确认原因后用小 wrapper 把这种情况返回 125,让 bisect 跳过该提交。随机测试或依赖外部服务的测试也要先固定下来,不然跑得很快,定位结果反而不太可信。

这个退出码 5 的提醒很关键。可以用一个小 wrapper 把它明确映射成 bisect 的跳过码:

pytest -q tests/test_login.py
rc=$?
if [ "$rc" -eq 5 ]; then
  exit 125
fi
exit "$rc"

不过最好先确认项目里退出码 5 确实代表“没有收集到测试”,否则可能把真实失败跳过去。其余退出码原样返回,git bisect run 才能区分 good、bad 和 skip。

ZiorLv1#2

这个退出码 5 的提醒很关键。可以用一个小 wrapper 把它明确映射成 bisect 的跳过码:

pytest -q tests/test_login.py
rc=$?
if [ "$rc" -eq 5 ]; then
  exit 125
fi
exit "$rc"

不过最好先确认项目里退出码 5 确实代表“没有收集到测试”,否则可能把真实失败跳过去。其余退出码原样返回,git bisect run 才能区分 good、bad 和 skip。

还要留意工作区污染:git bisect run 在不同提交间切换时,未跟踪或被忽略的生成文件不会自动消失。测试如果读到这些残留,结果就可能飘。最好让构建产物进隔离目录,或在每轮测试前清理并确认脚本不会改动被 bisect 管理的文件,不然最后定位到的可能只是环境残留。

别熬夜啦Lv1#3

还要留意工作区污染:git bisect run 在不同提交间切换时,未跟踪或被忽略的生成文件不会自动消失。测试如果读到这些残留,结果就可能飘。最好让构建产物进隔离目录,或在每轮测试前清理并确认脚本不会改动被 bisect 管理的文件,不然最后定位到的可能只是环境残留。

还有一个边界:git bisect run 只看退出码,不知道“环境没准备好”和“代码回归”的区别。跨到较老的提交时,如果依赖没装好、配置缺失,测试的非 0 也可能被记成 bad。wrapper 最好把这类前置条件失败映射成 125;只有测试明确失败时才原样返回非 0,这样定位结果会稳不少。