登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  软件教程

Git bisect 怎样自动运行回归脚本

来源:17golang原创

时间:2026-10-15 01:59:05 482浏览 收藏

Git bisect 可以把“逐个提交回退测试”变成二分查找,但前提是回归脚本必须用退出码告诉 Git 当前提交属于哪一类。最小规则是:退出码 0 表示当前提交正常,1–127 中除 125 以外的值表示当前提交异常,125 表示当前提交暂时无法测试,应跳过;其它返回码会让这次自动二分中止。

官方地址:https://git-scm.com/docs/git-bisect

这篇只解决 git bisect run 的回归脚本和返回码,不讨论二分算法实现。你可以把自己的构建命令、单元测试或接口回归命令替换到示例中。

先把回归脚本写成一个稳定的开关

我通常把脚本放在仓库外部,避免 bisect 切换提交时把脚本本身一起切走。脚本只做三件事:准备当前提交、区分“无法测试”和“测试失败”、把真正的测试退出码原样交回给 Git。

#!/bin/sh
set -u

# 构建失败通常说明当前提交无法在这轮环境中测试,交给 bisect 跳过。
if ! make test-binary; then
  exit 125
fi

# 回归命令返回 0 表示通过,非 0 表示当前提交仍有问题。
./test-regression --case login-cache
status=$?

# 保留真实测试结果,不能把失败统一改成 125。
exit "$status"

这里的关键不是脚本使用了 make,而是把“构建失败”和“回归失败”分开。构建环境缺少依赖时继续把提交判成 bad,会把环境问题误认为代码回归;但回归用例失败必须保留非零状态,否则 Git 会把坏提交当成好提交。

原创开发工具界面说明图,展示 Git bisect 的 bad、good 范围与 run 脚本入口
图1:Git bisect 启动与回归脚本入口的操作示意图,不是运行截图。

从仓库终端启动自动二分

操作路径可以固定为“仓库终端 → 标记 bad/good 范围 → 执行 run 脚本”。假设当前版本已经确认有问题,较早的提交没有问题:

# 在仓库终端标出有问题的当前版本和已知正常的旧版本。
git bisect start HEAD v1.8.0

# 让 Git 自动切换中间提交,并把脚本作为每轮判定器。
git bisect run "$HOME/bin/check-login-cache.sh"

如果你不想依赖脚本的可执行权限,也可以显式交给 shell:

# 用 sh 执行脚本,适合脚本文件没有执行权限的情况。
git bisect run sh "$HOME/bin/check-login-cache.sh"

执行后,Git 会在每个候选提交上运行一次脚本。脚本输出的日志可以帮助定位问题,但真正决定二分方向的是退出码,不是终端里的文字。

返回码怎样告诉 Git 当前提交好坏

可以把返回码当成一个很小的协议。脚本作者只要稳定遵守这个协议,Git 就能自动推进;如果把进程错误、权限错误和测试失败混成一个超出范围的值,二分会提前停止。

脚本返回码Git 的判断适合表达的情况
0good/old构建完成且回归通过
1–124、126–127bad/new构建完成但回归失败
125skip当前提交不可测试,例如依赖或构建条件不满足
其它值abort脚本自身异常,需先修复环境或脚本

126 和 127 本来常见于“找到但不可执行”和“命令不存在”的 shell 错误。Git 文档仍把它们视为当前提交的 bad 范围;如果你的目标是表达“不能判断”,请显式返回 125,不要让任意命令错误偶然充当 skip。

原创结果面板说明图,展示 Git bisect 回归脚本返回码与 good、bad、skip、abort 的关系
图2:回归脚本返回码与二分状态的结果示意图,不是运行截图。

把构建、测试和清理拼成一个可复用脚本

真实项目往往需要先安装依赖、构建,再执行一个窄回归。建议让每个阶段的含义保持清楚:构建条件缺失返回 125,测试不通过返回测试本身的非零码,临时修改在退出前清理。

#!/bin/sh
set -u

# 旧提交可能缺少当前构建所需条件,不能把环境问题当成代码回归。
if ! ./scripts/prepare-bisect-env.sh; then
  exit 125
fi

# 用临时文件记录测试结果,便于清理后仍返回原始状态。
result=0
./scripts/run-regression.sh || result=$?

# 不让临时产物影响下一个提交的测试。
./scripts/clean-bisect-env.sh || exit 125

# 原样返回测试结果:0 是通过,非 0 是失败。
exit "$result"

注意 set -e 的副作用:它可能让脚本在你还没有把失败分类前直接退出。需要捕获测试状态时,用 command || result=$? 这样的写法把状态保存下来,再执行清理。

二分结束后怎样确认脚本确实生效

自动运行结束时,Git 会给出它认为的首个异常提交或提示存在无法测试的提交。此时先保留终端日志,再退出 bisect 状态:

# 查看本次二分记录,确认每轮使用的判定结果。
git bisect log

# 结束 bisect 并回到开始前的分支位置。
git bisect reset

如果日志里出现连续的 skip,优先检查脚本是否把普通测试失败错误地改成了 125。如果立即 abort,检查脚本的命令路径、执行权限和未预期的退出码;如果所有提交都被判为 good 或 bad,则重新确认起点本身是否标记反了。

常见设置问题与回退方法

脚本明明失败,却没有定位到坏提交

先在当前提交上单独执行脚本,再用 echo $? 查看退出码。测试失败应是非零且不为 125;如果脚本最后一行是日志命令,可能覆盖了真正测试的返回值。

每轮都显示无法测试

把构建、依赖下载、服务启动等前置动作逐个执行。只有“当前提交无法在本轮条件下判断”才返回 125。如果网络或服务环境是偶发的,应该先让测试环境稳定,而不是用 skip 掩盖波动。

需要停止时怎么回退

使用 git bisect reset 结束当前会话;它不会修改提交历史。修好脚本后重新执行 git bisect start 和 git bisect run,不要在同一个含糊的返回码协议上继续跑。

结语

Git bisect 自动化的核心是返回码契约:0 表示通过,普通非零表示回归失败,125 专门表示跳过,异常协议值则让流程中止。把构建条件、回归结果和清理动作拆开后,脚本既能自动推进,也能在出问题时留下可解释的日志。

相关问题

  • git bisect run 可以直接运行命令吗? 可以,命令或脚本只要遵守退出码约定即可。
  • 为什么不能把所有失败都返回 125? 125 是跳过当前提交;这样做会丢失真正的 bad 证据。
  • 二分完成后必须 reset 吗? 建议执行,便于清理 bisect 状态并回到原来的分支位置。
声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>