当回归夹在一串提交中时,逐个 checkout 验证会很慢。git bisect 用二分查找缩小范围,git bisect run 还能反复执行同一个判定脚本,自动找出首个失败提交。
环境:Git 2.39+;Linux 或 macOS;Bash;示例还使用 coreutils 的 cut。下面只操作新建的临时仓库。
set -Eeuo pipefail
root=$(mktemp -d)
repo="$root/demo"
git init -b main "$repo"
git -C "$repo" config user.name "Bisect Demo"
git -C "$repo" config user.email "demo@example.invalid"
# 前三个提交正常,从 limit=4 开始视为回归。
for value in 1 2 3 4 5; do
printf 'limit=%s\n' "$value" >"$repo/app.conf"
git -C "$repo" add app.conf
git -C "$repo" commit -m "set limit to $value"
done
cat >"$repo/check.sh" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
value=$(cut -d= -f2 app.conf)
test "$value" -lt 4
EOF
chmod +x "$repo/check.sh"
# HEAD 已知失败,HEAD~4 已知正常。
git -C "$repo" bisect start HEAD HEAD~4
git -C "$repo" bisect run ./check.sh
# 此时 HEAD 停在首个失败提交,应显示 set limit to 4。
git -C "$repo" show -s --format='%h %s' HEAD
git -C "$repo" bisect reset
rm -rf -- "$root"
判定脚本返回 0 代表正常,返回 1 到 127(125 除外)代表失败;当前提交无法可靠测试时可返回 125,Git 会跳过它。脚本应尽量确定、快速,并避免依赖波动的网络服务,否则一次偶发失败就可能把搜索带到错误区间。
实际仓库中,边界也可以直接写标签或提交哈希,例如 git bisect start v2.4.1 v2.4.0。无论成功还是中断,最后都应执行 git bisect reset,恢复开始二分前的分支与工作区位置。