[英]How to use git bisect?
我读过一些文章说git bisect
很棒。 但是,我不是母语人士,我不明白为什么它很棒。
有人可以用一些代码示例进行演示:
svn blame
一样吗? git bisect
背后的想法是在历史中执行二分搜索以找到特定的回归。 假设您有以下开发历史:
... --- 0 --- 1 --- 2 --- 3 --- 4* --- 5 --- current
您知道您的程序在current
修订版中无法正常运行,并且它在0
修订版中运行。 所以回归是在提交的一个可能引入1
, 2
, 3
, 4
, 5
, current
。
您可以尝试检查每个提交,构建它,检查是否存在回归。 如果有大量提交,这可能需要很长时间。 这是一个线性搜索。 我们可以通过二分搜索做得更好。 这就是git bisect
命令所做的。 在每一步,它都试图将可能有问题的修订数量减少一半。
您将使用如下命令:
$ git stash save
$ git bisect start
$ git bisect bad
$ git bisect good 0
Bisecting: 2 revisions left to test after this (roughly 2 steps)
[< ... sha ... >] 3
执行此命令后, git
将检出提交。 在我们的例子中,它将是 commit 3
。 您需要构建您的程序,并检查是否存在回归。 您还需要告诉git
此修订的状态,如果存在回归,则使用git bisect bad
如果不存在,则使用git bisect good
。
让我们假设回归是在 commit 4
中引入的。 然后这个版本中不存在回归,我们告诉它git
。
$ make
$ make test
... ... ...
$ git bisect good
Bisecting: 0 revisions left to test after this (roughly 1 step)
[< ... sha ... >] 5
然后它会检出另一个提交。 4
或5
(因为只有两次提交)。 假设它选择了5
。 在构建之后,我们测试程序并看到回归存在。 然后我们告诉它git
:
$ make
$ make test
... ... ...
$ git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[< ... sha ... >] 4
我们测试最后一个修订版4
。 由于它是引入回归的那个,我们告诉它git
:
$ make
$ make test
... ... ...
$ git bisect bad
< ... sha ... > is the first bad commit
< ... commit message ... >
在这种简单的情况下,我们只需要测试 3 个版本( 3
, 4
, 5
)而不是 4 个( 1
, 2
, 3
, 4
)。 这是一个小小的胜利,但这是因为我们的历史太小了。 如果搜索范围是 N 次提交,我们应该期望使用git bisect
测试 1 + log2 N 次提交,而不是使用线性搜索测试大约 N / 2 次提交。
找到引入回归的提交后,您可以研究它以找到问题。 完成此操作后,在使用git bisect
命令之前,您可以使用git bisect reset
将所有内容恢复到原始状态。
git bisect run
自动二等分如果您有一个自动./test
脚本的退出状态为 0 如果测试正常,您可以使用bisect run
自动找到错误:
git checkout KNOWN_BAD_COMMIT
git bisect start
# Confirm that our test script is correct, and fails on the bad commit.
./test
# Should output != 0.
echo $?
# Tell Git that the current commit is bad.
git bisect bad
# Same for a known good commit in the past.
git checkout KNOWN_GOOD_COMMIT
./test
# Should output 0.
echo $?
# After this, git automatically checks out to the commit
# in the middle of KNOWN_BAD_COMMIT and KNOWN_GOOD_COMMIT.
git bisect good
# Bisect automatically all the way to the first bad or last good rev.
git bisect run ./test
# End the bisect operation and checkout to master again.
git bisect reset
这当然假设如果测试脚本./test
是 git 跟踪的,它不会在二分期间的某个较早的提交中消失。
我发现很多时候你可以通过从树中复制树内脚本,并可能使用PATH
的变量,然后从那里运行它来逃脱。
当然,如果test
依赖的测试基础设施因旧提交而中断,则没有解决方案,您将不得不手动做事,一一决定如何测试提交。
然而,我发现使用这种自动化通常是有效的,并且可以为您积压的任务中较慢的测试节省大量时间,您可以让它在一夜之间运行,并且可能在第二天早上发现您的错误,这是值得的尝试。
在 bisect 之后保持第一个失败的提交,而不是回到master
:
git bisect reset HEAD
start
+ 一开始的bad
和good
:
git bisect start KNOWN_BAD_COMMIT KNOWN_GOOD_COMMIT~
是相同的:
git checkout KNOWN_BAD_COMMIT
git bisect start
git bisect bad
git bisect good KNOWN_GOOD_COMMIT
看看迄今测试(手动good
和bad
或run
):
git bisect log
示例输出:
git bisect log
git bisect start
# bad: [00b9fcdbe7e7d2579f212b51342f4d605e53253d] 9
git bisect bad 00b9fcdbe7e7d2579f212b51342f4d605e53253d
# good: [db7ec3d602db2d994fe981c0da55b7b85ca62566] 0
git bisect good db7ec3d602db2d994fe981c0da55b7b85ca62566
# good: [2461cd8ce8d3d1367ddb036c8f715c7b896397a5] 4
git bisect good 2461cd8ce8d3d1367ddb036c8f715c7b896397a5
# good: [8fbab5a3b44fd469a2da3830dac5c4c1358a87a0] 6
git bisect good 8fbab5a3b44fd469a2da3830dac5c4c1358a87a0
# bad: [dd2c05e71c246f9bcbd2fbe81deabf826c54be23] 8
git bisect bad dd2c05e71c246f9bcbd2fbe81deabf826c54be23
# bad: [c536b1b7242d5fcf92cd87e9a534bedb1c0c9c05] 7
git bisect bad c536b1b7242d5fcf92cd87e9a534bedb1c0c9c05
# first bad commit: [c536b1b7242d5fcf92cd87e9a534bedb1c0c9c0
在 git log 上显示好的和坏的 refs 以获得更好的时间概念:
git log --decorate --pretty=fuller --simplify-by-decoration master
这仅显示具有相应 ref 的提交,这大大降低了噪音,但确实包括以下类型的自动生成的 ref:
refs/bisect/good*
refs/bisect/bad*
它告诉我们哪些提交被标记为好或坏。
如果您想使用该命令,请考虑此测试存储库。
有时:
对于这些情况,例如假设失败总是在 5 秒内发生,如果我们懒得像我们真正应该的那样使测试更具体,我们可以使用timeout
如下所示:
#!/usr/bin/env bash
timeout 5 test-command
if [ $? -eq 1 ]; then
exit 1
fi
这是有效的,因为timeout
退出124
而test-command
失败退出1
。
git bisect run
对退出状态有点挑剔:
高于 127 的任何值都会使平分失败,例如:
git bisect run failed: exit code 134 from '../test -aa' is < 0 or >= 128
特别是,C assert(0)
导致SIGABRT
并以状态 134 退出,非常烦人。
125 很神奇,它使运行被git bisect skip
。
这样做的目的是帮助跳过由于无关原因而损坏的构建。
有关详细信息,请参阅man git-bisect
。
所以你可能想使用类似的东西:
#!/usr/bin/env bash
set -eu
./build
status=0
./actual-test-command || status=$?
if [ "$status" -eq 125 ] || [ "$status" -gt 127 ]; then
status=1
fi
exit "$status"
在 git 2.16.1 上测试。
$ git bisect start
$ git bisect bad
$ git bisect good <goodcommit>
或者
$ git bisect start
$ git bisect good
$ git bisect bad <badcommit>
Bisecting: X revisions left to test after this (roughly Y steps)
问题还存在吗?
$ git bisect bad
$ git bisect good
<abcdef> is the first bad commit
git bisect reset
再补充一点:
我们可以指定git bisect start
的文件名或路径,以防我们知道错误来自特定文件。 例如,假设我们知道导致回归的更改在 com/workingDir 目录中,那么我们可以运行git bisect start com/workingDir
这意味着只会检查更改此目录内容的提交,这使得事情更快。
此外,如果很难判断特定提交是好是坏,您可以运行git bisect skip
,它会忽略它。 鉴于有足够多的其他提交,git bisect 将使用另一个来缩小搜索范围。
$ git bisect ..
基本上是一个用于调试的Git 工具。 “Git Bisect”通过检查自上次(已知)工作提交以来的先前提交进行调试。 它使用二进制搜索来遍历所有这些提交,以找到引入回归/错误的提交。
$ git bisect start
# 开始二等分
$ git bisect bad
# 说明当前提交(v1.5)具有回归/设置“坏”点
$ git bisect good v1.0
# 提到它最后一个好的工作提交(没有回归)
提到“坏”和“好”点将有助于git bisect (二进制搜索)选择中间元素(commit v1.3)。 如果在提交 v1.3 时存在回归,您会将其设置为新的“坏”点,即( Good -> v1.0 和 Bad -> v1.3 )
$ git bisect bad
或者类似地,如果提交 v1.3 没有错误,您将其设置为新的“好点”,即(*Good -> v1.3 and Bad -> v1.6)。
$ git bisect good
注意: good
和bad
的不是唯一可以用来标记带有或不带有特定属性的提交的术语。
Git 2.7(2015 年第四季度)引入了新的git bisect
选项。
git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]
随着文档添加:
有时,您不是在寻找引入破坏的提交,而是在寻找导致其他“旧”状态和“新”状态之间发生变化的提交。
例如,您可能正在寻找引入特定修复的提交。
或者您可能正在寻找源代码文件名最终全部转换为您公司的命名标准的第一次提交。 管他呢。在这种情况下,使用“好”和“坏”这两个术语来指代“更改前的状态”和“更改后的状态”可能会非常混乱。
因此,您可以分别使用术语“
old
”和“new
”来代替“good
”和“bad
”。
(但请注意,您不能在一次会话中将“good
”和“bad
”与“old
”和“new
”混在一起。)在这种更一般的用法中,您为
git bisect
提供具有某些属性的“new
”提交和不具有该属性的“old
”提交。每次
git bisect
检查一次提交时,您都会测试该提交是否具有以下属性:
如果是,则将提交标记为“new
”; 否则,将其标记为“old
”。当二分完成后,
git bisect
将报告哪个提交引入了该属性。
请参阅Matthieu Moy ( moy
) 的commit 06e6a74 、 commit 21b55e3 、 commit fe67687 (2015 年 6 月 29 日) 。
请参阅Antoine Delaite ( CanardChouChinois
) 的commit 21e5cfd (2015 年 6 月 29 日) 。
(由Junio C gitster
合并-- gitster
-- in commit 22dd6eb ,2015 年 10 月 5 日)
git 平分退出状态
Ciro Santilli的 2014 年回答将它们称为“神奇的退出状态”
它们与 Git 2.36(2022 年第二季度)的使用略有不同:一个不太常见的错误是编写脚本来提供“ git bisect
” ( man )运行而不使其可执行,在这种情况下,所有测试都将以 126 退出或 127 个错误代码,即使在标记为良好的修订版上也是如此。
尝试识别这种情况并尽早停止迭代。
请参阅René Scharfe ( rscharfe
)的commit 48af1fd 、 commit ba5bb81 、 commit 8efa2ac 、 commit 80c2e96 (2022 年 1 月 18 日)。
(由Junio C Hamano -- gitster
--在提交 e828747中合并,2022 年 3 月 6 日)
bisect--helper
:在退出代码 126 和 127 上仔细检查运行命令签字人:René Scharfe
当无法执行或找不到运行命令时,shell 分别返回退出代码 126 或 127。
但是,出于历史原因,允许有效的运行命令返回这些代码以及指示错误的修订。这意味着拼写错误会导致 go 在整个距离上的虚假二分运行,并最终报告无效结果。
最好的解决方案是保留退出代码 126 和 127,例如71b0251 (Bisect run: , 2007-10-26, Git v1.5.4-rc0 -- merge )(Bisect run: "skip" current commit if script exit code is 125., 2007-10-26) 为 125 做了,当我们得到它们时中止
bisect run
。
不过,对于那些依赖说明 126 和 127 可用于错误修订的文档的人来说,这可能会带来不便。此补丁使用的解决方法是在已知良好的版本上运行命令,如果我们仍然得到相同的错误代码,则中止。
这为使用退出代码 126 和 127 的脚本运行增加了一个步骤,但仍然支持它们,但有一个例外:它不适用于无法识别(手动标记的)已知良好修订版的命令。使用低退出代码的运行命令不受影响。
执行两次缺少的命令和三次检查(第一步,已知良好的修订并返回到第一步的修订)后,会报告错别字。
请参阅示例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.