研究 Git:用二分查找定位回归提交

历史提交很多时,逐个检查成本高。

edyang · 2015-03-15

历史提交很多时,逐个检查成本高。只要能稳定判断好坏,就可以用二分缩小范围。

本文使用Git 2.x 与独立演示仓库。Git(分布式版本管理)保存提交对象和引用,工作区、暂存区与提交历史不是同一份状态。每次操作先判断它改变哪个区域,再决定是否适合当前协作情境。

1. 从现象推到机制

bisect 在已知正常与已知异常之间选择中间提交,根据判断排除一半区间。判定规则必须稳定且与环境变化解耦。某个版本无法构建时应区分不可判定,不要误报为业务失败。

研究 Git:用二分查找定位回归提交的处理、反馈与观察关系

图中的四个节点分别表示已知边界、中间版本、稳定复现、原因分析。顺着实线检查输入如何变成输出,再沿虚线核对反馈条件。图示表达的是本文讨论的关系,不是实测曲线或现场截图。

2. 最小实现与输入条件

先准备一个只检查该缺陷的小脚本,固定数据与依赖。每次切换提交后重新生成必要产物,结束时恢复原分支状态。

1
2
3
4
5
git bisect start
git bisect bad <bad_commit>
git bisect good <good_commit>
# 每轮复现后执行 git bisect good 或 bad
git bisect reset

示例在没有私人资料的临时仓库执行。先看 status、diff 与 log,再运行改变状态的命令;共享历史优先新增提交表达修复,不用改写历史掩盖已经发生的变化。

3. 用对照区分原因

下表列出需要主动改变的条件。预期行为来自机制分析,复现时还需记录运行环境和原始输出,不能将预期当作已经测得的结果。

改变的条件 需要验证的行为
复现规则随机失败 二分结论可能被误导
旧提交依赖不再可用 需要标为无法判断或修复环境
定位到首个异常提交 还需理解它如何改变行为

对照 1:复现规则随机失败

二分结论可能被误导。观察时记录相同提交的重复判定。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。

对照 2:旧提交依赖不再可用

需要标为无法判断或修复环境。观察时记录构建失败与缺陷现象区别。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。

对照 3:定位到首个异常提交

还需理解它如何改变行为。观察时记录该提交实际差异与机制。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。

4. 适用条件与取舍

找到引入问题的提交不代表责任归因。需求变更、数据变化和后续依赖也可能参与,修复要围绕行为与证据。

一次正常运行只覆盖了这组输入。继续扩展前,应把上面的异常对照保留下来,尤其关注“定位到首个异常提交”这一分支。后续方案若改变了图中任意一处依赖,原来的判断就要重新验证,不能仅凭界面相似或返回值相同沿用结论。

同月延伸

参考资料

  1. Pro Git 第二版
  2. Git 2.2.0 版本说明