- 已经会基本提交和分支操作的开发者
- 想理解命令边界与风险的人
Command Reference
git bisect
通过二分法定位引入 bug 的提交,是排查回归问题时最有价值的高级命令之一。
- 知道工作区、暂存区、提交的基本关系
- 能读懂 `git status` 和简单历史图
- 误把本地整理命令用到共享历史
- 在没确认恢复路径前直接继续改写历史
git bisect 的目标不是读历史,而是自动缩小范围,帮你找到“哪次提交第一次把问题引进来”。
基本流程
git bisect start
git bisect bad
git bisect good <good-commit>
然后 Git 会不断把你切到中间提交,你每次判断:
git bisect goodgit bisect bad
直到定位到问题提交。
适合什么问题
- 某个 bug 明确是最近引入的
- 你能清楚判断“这个提交状态是好还是坏”
- 历史范围较大,不适合人肉一个个翻
风险点
- 过程中会频繁切换提交
- 如果测试步骤不稳定,结论也会不稳
- 结束后记得
git bisect reset
最实用的心智模型
把它理解成“让 Git 代替你做回归排查里的二分搜索”,而不是普通日志查看命令。
这条命令在流程里解决什么问题
git bisect 是一个纯只读的诊断工具,不修改任何提交、引用或历史。它的作用是帮你快速缩小范围,定位"哪一次提交第一次引入了这个 bug"。它不会重塑历史,也不会移动引用。
典型用例
- 发现回归 bug 后,用
git bisect在大量提交中快速定位问题源头。 - 结合
git bisect run自动运行测试脚本,实现无人值守的二分排查。 - 在排查性能退化或 UI 异常时,用二分法缩小范围,避免逐个人工检查。
图例理解
已知的好提交已知的坏提交
问题提交 hash排查日志
bisect 是只读操作,不会影响仓库历史、引用或工作区。结束后必须运行 git bisect reset 恢复正常状态。
git bisect run 自动化排查
当你要排查的范围很大、手动判断太慢时,git bisect run 是最强大的武器——它接受一个脚本,自动在每一个中间提交上执行,根据脚本返回值判断 good/bad。
编写测试脚本
脚本返回值的约定:
- 0 = good(当前提交没问题)
- 1-127 = bad(当前提交有 bug)
- 125 = skip(无法判断,跳过)
- >127 = 中止 bisect
#!/bin/bash
# test-bug.sh - 自动测试脚本
make clean && make || exit 125 # 构建失败,跳过
./run-tests --filter "user_login" || exit 1 # 测试失败,标记 bad
exit 0 # 测试通过,标记 good
完整自动化流程
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
git bisect run ./test-bug.sh
运行完毕后,Git 会自动输出第一个 bad 提交:
<commit-hash> is the first bad commit
commit <hash>
Author: ...
Date: ...
fix: update user login validation
自动化排查的优势
- 几十个甚至上百个提交范围也能在几分钟内完成
- 排查逻辑可复用,团队成员可以共享测试脚本
- 脚本可以结合
curl、pytest、cargo test等各种测试手段
git bisect skip 跳过无法测试的提交
在二分查找过程中,某些提交可能因为构建失败、依赖不兼容或环境问题而无法测试:
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
# Git 切换到中间提交,但构建失败了
git bisect skip
skip 会让 Git 跳过当前提交,尝试其他中间点。但需要注意:跳过太多提交会导致结果不够精确,Git 可能只能给出一个"可疑范围"而非精确的单个提交。
批量 skip
# 跳过 v1.1.0 到 v1.2.0 之间的所有提交
git bisect skip v1.1.0..v1.2.0
误标 good/bad 的后果与纠正
二分查找完全依赖你手动标记的准确性。如果不小心标错了:
标错了会怎样
# 假设当前提交实际上是 good,但你误标为 bad
git bisect bad # ❌ 错误标记
这会导致:
- Git 缩小错误的范围
- 最终找到的"第一个 bad 提交"可能根本不是问题源头
- 排查结果完全不可信
纠正方法
- 重置重来:
git bisect reset # 回到原始 HEAD
git bisect start # 重新开始
git bisect bad HEAD
git bisect good <correct-good-commit>
- 使用 bisect log 检查历史:
git bisect log
# 输出类似:
# git bisect start
# git bisect good abc1234
# git bisect bad def5678
# git bisect good 9ab0123
# git bisect bad 4cd5678
通过日志可以回溯每一步的标记,确认哪一步标错了。
bisect 日志与状态输出解读
bisect log
git bisect log
输出完整的 bisect 操作历史,可以保存后复用:
git bisect log > bisect-log.txt
# 下次可以直接回放:
git bisect replay bisect-log.txt
bisect visualize
git bisect visualize
# 或
git bisect view
用 git log 或图形工具(gitk)查看当前剩余的候选提交范围,帮助理解 bisect 进展。
bisect progress info
每次标记 good/bad 后,Git 会输出类似信息:
Bisecting: 12 revisions left to test after this (roughly 4 steps)
[abc1234] fix: optimize database query
这告诉你:
- 还有多少个提交待排查
- 大概还需要几步
- 当前切到了哪个提交
特殊情况与边界
- bisect 过程中会频繁切换 HEAD,如果有未提交的工作区改动,会拒绝切换。可以先
git stash保存。 - 如果中间的某个提交无法测试(比如构建失败),用
git bisect skip跳过。 git bisect run <script>可以自动执行测试脚本,脚本返回 0 = good,返回 1-127 = bad。- 结束后必须运行
git bisect reset,否则会留在中间提交状态。