订单折扣以前四舍五入,现在有一笔少了一分钱。你知道上个发布版本是对的,可这中间合了好几轮代码。先找一笔每次都能复现的订单,定下判断方法,再让 git bisect 帮你挑要检查的提交。
这篇用两个版本标签 v1.8.0 和 v1.9.0 做示例。跟着自己的仓库操作时,换成你确认过的标签或提交哈希。
先把两头测明白
同一组输入、同一套配置和数据,在旧版本跑出预期,在新版本确实出错。两次测出来都一样,就先回头看看环境和复现条件。比如旧版用的是本地配置,新版走测试服,两头的结果还不能用来标记代码好坏。
我会在单独的工作目录里做。bisect 中途要反复切提交,另开一个 worktree 可以让正在写的代码留在原目录。以下命令在仓库目录运行,../order-bisect 应当是一个未被占用的路径。
git worktree add --detach ../order-bisect v1.9.0
cd ../order-bisect
git bisect start v1.9.0 v1.8.0
顺序是先坏后好。Git 会把这个临时目录切到某个候选提交。用同一笔订单测一次,结果正确就运行 git bisect good,复现问题就运行 git bisect bad。碰到旧提交缺依赖、这一轮根本跑不起来,标成 git bisect skip。跳过的版本太多,Git 可能只能给一组候选。
有个固定判定,就让脚本跑
假设前面已经确认,这个问题跟 config/order.properties 里的舍入配置绑定,而且好版本里那一行固定写成 discount.rounding=HALF_UP。只在这个简化例子里,我们可以直接检查配置。
把脚本放在临时工作目录的上一级,保存为 bisect-order.sh。以下用 POSIX shell,Windows 上可以用 Git Bash,脚本用 LF 换行。
#!/bin/sh
if ! git cat-file -e HEAD:config/order.properties 2>/dev/null; then
exit 125
fi
git grep -G -q -e '^discount[.]rounding=HALF_UP[[:space:]]*$' HEAD -- config/order.properties
case $? in
0) exit 0 ;;
1) exit 1 ;;
*) exit 128 ;;
esac
从正在二分的临时目录执行。已经手动标过几次的话,脚本会接着找。
git bisect run sh ../bisect-order.sh
0 表示好,1 表示坏,125 跳过当前提交。示例用 128 中止意外错误。换成实际的业务测试时,最好把“断言失败”和“测试没跑起来”分开。一个 Maven 命令退出非零,可能只是依赖仓库连不上。脚本如果把这种情况也标成坏,Git 就会顺着错误标记继续缩小范围。
找到第一条坏提交,再看它改了什么
看到 first bad commit 后,先用 git show 提交哈希 看差异。回到那笔订单,再测一下它和前一个可测的好版本。范围里有合并提交时,分别看父提交和合并后的变化。某个问题出现过、修过又出现,拆成更小的版本区间再找,省得把两次回归搅在一起。
保留定位记录,再收起临时目录。下面在 order-bisect 内运行前两条。确认临时目录没有要保留的修改之后,回到原仓库目录执行最后一条。
git bisect log > ../bisect-order.log
git bisect reset
# 回到原仓库目录后执行
git worktree remove ../order-bisect
如果手上还没有能稳定重现的测试,可以先从数据库行为开始补一个。Spring Boot 的 SQL,直接用 MySQL 测一遍
参考资料
上个版本还好好的,用 Git 找出哪次改坏了
https://java.li/archives/git-bisect-find-regression
评论