掌握 git bisect 的二分查找算法,用最少的步骤从几百个提交中精确定位引入 Bug 的那个提交。

Bisect — 用二分法从几百个提交中找到罪魁祸首

线上出了 Bug,你知道上周还是好的,但中间有 200 个提交,逐个排查?太慢了。

git bisect二分查找算法,只需要 log₂(200) ≈ 8 次就能定位到引入问题的那个提交。


一、什么是 Bisect?

Bisect 的原理很简单:

1
2
3
4
5
6
7
已知:提交 A 是好的,提交 Z 是有 Bug 的

第 1 步:跳到中间提交 M,测试 → 有 Bug → Bug 在 A~M 之间
第 2 步:跳到 A~M 的中间 H,测试 → 没 Bug → Bug 在 H~M 之间
第 3 步:跳到 H~M 的中间 K,测试 → 有 Bug → Bug 在 H~K 之间
...
最终:定位到引入 Bug 的提交
提交数量逐个排查bisect
100 个最多 100 次最多 7 次
500 个最多 500 次最多 9 次
1000 个最多 1000 次最多 10 次

二、基本用法

手动二分查找

1
2
3
4
5
6
7
8
9
10
11
12
# 1. 启动 bisect
git bisect start

# 2. 标记当前版本为"坏的"(有 Bug)
git bisect bad

# 3. 标记一个已知"好的"版本(没 Bug 的时候)
git bisect good abc1234

# Git 自动跳到中间提交
# Bisecting: 50 revisions left to test after this (roughly 6 steps)
# [def5678] feat: 添加搜索功能

测试并标记

Git 跳到中间提交后,你测试一下,告诉它结果:

1
2
3
4
5
# 如果当前版本有 Bug
git bisect bad

# 如果当前版本没 Bug
git bisect good

Git 会继续跳到下一个中间提交,重复这个过程,直到找到第一个”坏”的提交:

1
2
3
4
5
6
# abc1234 is the first bad commit
# commit abc1234
# Author: John Doe
# Date: Mon Jun 1 10:00:00 2026
#
# feat: 重构用户模块

结束 bisect

1
2
# 回到 bisect 之前的状态
git bisect reset

三、完整操作流程

场景:首页崩溃了,上周还是好的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 1. 启动 bisect
git bisect start

# 2. 当前版本是坏的
git bisect bad

# 3. 找到上周没问题的提交
git log --oneline
# a1b2c3d (HEAD) feat: xxx ← 坏的
# ...中间 200 个提交...
# x9y8z7w fix: 修了个样式 ← 上周的,确认是好的

git bisect good x9y8z7w

# Git 跳到中间:
# Bisecting: 100 revisions left (roughly 7 steps)
# [m5n6o7p] feat: 添加缓存功能

# 4. 测试当前页面... 崩溃了
git bisect bad

# Git 继续二分:
# Bisecting: 50 revisions left (roughly 6 steps)
# [q1r2s3t] refactor: 优化数据层

# 5. 测试... 正常
git bisect good

# Git 继续二分...
# ...重复 5-6 次...

# 6. 最终定位:
# abc1234 is the first bad commit
# commit abc1234
# Author: 张三
# Date: Wed Jun 4 15:30:00 2026
#
# refactor: 重构数据处理逻辑

# 7. 查看这个提交改了什么
git show abc1234

# 8. 结束 bisect
git bisect reset

四、自动化 bisect

如果 Bug 可以通过命令检测(如测试失败),可以让 bisect 自动运行,完全不需要手动测试。

用测试脚本自动判定

1
2
3
# 一行命令:自动 bisect,用 npm test 判定好坏
git bisect start HEAD abc1234 --
git bisect run npm test

执行过程:

1
2
3
4
5
6
7
8
Bisecting: 100 revisions left
running npm test
...测试通过... → 自动标记 good
Bisecting: 50 revisions left
running npm test
...测试失败... → 自动标记 bad
...
abc1234 is the first bad commit

用自定义脚本

1
2
3
4
5
6
7
8
9
10
11
12
# 创建检测脚本
cat > check_bug.sh << 'EOF'
#!/bin/bash
# 检查某个函数是否存在
grep -q "processPayment" src/payment.js
# 返回 0 = good(函数存在),返回 1 = bad(函数不存在)
EOF
chmod +x check_bug.sh

# 自动 bisect
git bisect start HEAD abc1234
git bisect run ./check_bug.sh

脚本返回值规则

返回值含义
0当前版本是”好的”
1-124126-127当前版本是”坏的”
125当前版本无法测试(跳过)
>127中止 bisect

自动化 bisect 的优势

  • 完全不需要人工参与
  • 判定结果客观准确
  • 适合回归测试(之前通过的测试突然失败了)

五、常用选项

用 Tag 标记好坏

1
2
3
4
# 用版本号代替 commit hash,更直观
git bisect start
git bisect bad HEAD
git bisect good v1.2.0 ← v1.2.0 是好的,当前是坏的

跳过无法测试的版本

有时候中间某个提交编译都过不了,没法测试:

1
2
# 标记为"跳过"
git bisect skip

查看 bisect 日志

1
2
# 查看 bisect 过程中每一步的判定
git bisect log

重放 bisect 日志

1
2
3
4
5
# 保存日志
git bisect log > bisect.log

# 下次用日志重放(不用重新手动标记)
git bisect replay bisect.log

六、注意事项

bisect 期间的注意事项

  1. bisect 过程中不要手动切换分支,Git 会自动管理 HEAD
  2. 如果需要修改代码来测试,先 git stash,测试完再 git stash pop
  3. 一定记得 git bisect reset 回到正常状态
  4. “好”和”坏”的提交之间必须是连续的线性历史,中间不能有 merge 分叉

什么时候适合用 bisect?

1
2
3
4
5
6
7
8
9
10
11
提交太多,手动排查不现实?
└── bisect ✅

Bug 可以通过命令自动检测?
└── bisect run ✅ (全自动)

Bug 只表现在视觉上(UI 问题)?
└── bisect 手动模式(需要人眼看)

需要跨分支定位问题?
└── 不适合 bisect(bisect 在同一分支上工作)

总结:Bisect 速查卡

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──────────────────────────────────────────────────────────┐
│ Git Bisect 速查 │
├────────────────┬─────────────────────────────────────────┤
│ 启动 │ git bisect start │
│ 标记坏的 │ git bisect bad [commit] │
│ 标记好的 │ git bisect good [commit] │
│ 跳过无法测试的 │ git bisect skip │
│ 结束并恢复 │ git bisect reset │
├────────────────┼─────────────────────────────────────────┤
│ 自动 bisect │ git bisect run <command> │
│ 查看 bisect 日志 │ git bisect log │
│ 重放日志 │ git bisect replay <file> │
└────────────────┴─────────────────────────────────────────┘