Command Reference

git bisect

通过二分法定位引入 bug 的提交,是排查回归问题时最有价值的高级命令之一。

适合谁看
  • 已经会基本提交和分支操作的开发者
  • 想理解命令边界与风险的人
前置知识
  • 知道工作区、暂存区、提交的基本关系
  • 能读懂 `git status` 和简单历史图
常见风险
  • 误把本地整理命令用到共享历史
  • 在没确认恢复路径前直接继续改写历史

git bisect 的目标不是读历史,而是自动缩小范围,帮你找到“哪次提交第一次把问题引进来”。

基本流程

git bisect start
git bisect bad
git bisect good <good-commit>

然后 Git 会不断把你切到中间提交,你每次判断:

  • git bisect good
  • git bisect bad

直到定位到问题提交。

适合什么问题

  • 某个 bug 明确是最近引入的
  • 你能清楚判断“这个提交状态是好还是坏”
  • 历史范围较大,不适合人肉一个个翻

风险点

  • 过程中会频繁切换提交
  • 如果测试步骤不稳定,结论也会不稳
  • 结束后记得 git bisect reset

最实用的心智模型

把它理解成“让 Git 代替你做回归排查里的二分搜索”,而不是普通日志查看命令。

这条命令在流程里解决什么问题

git bisect 是一个纯只读的诊断工具,不修改任何提交、引用或历史。它的作用是帮你快速缩小范围,定位"哪一次提交第一次引入了这个 bug"。它不会重塑历史,也不会移动引用。

典型用例

  • 发现回归 bug 后,用 git bisect 在大量提交中快速定位问题源头。
  • 结合 git bisect run 自动运行测试脚本,实现无人值守的二分排查。
  • 在排查性能退化或 UI 异常时,用二分法缩小范围,避免逐个人工检查。

图例理解

只读排查命令的作用面bisect 不修改仓库任何状态,只输出一个结论:哪个提交是第一个出问题的。
输入
已知的好提交已知的坏提交
结果
问题提交 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

自动化排查的优势

  • 几十个甚至上百个提交范围也能在几分钟内完成
  • 排查逻辑可复用,团队成员可以共享测试脚本
  • 脚本可以结合 curlpytestcargo 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 提交"可能根本不是问题源头
  • 排查结果完全不可信

纠正方法

  1. 重置重来
git bisect reset  # 回到原始 HEAD
git bisect start  # 重新开始
git bisect bad HEAD
git bisect good <correct-good-commit>
  1. 使用 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,否则会留在中间提交状态。