我读过一些文章说git bisect
很棒。但是,我不是母语人士,我无法理解为什么它很棒。
有人可以用一些代码示例演示:
svn blame
?答案 0 :(得分:571)
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
将签出提交。在我们的例子中,它将被提交3
。您需要构建程序,并检查是否存在回归。如果存在回归,您还需要使用git
告诉git bisect bad
此版本的状态,如果不存在,则需要git bisect good
。
让我们假设回归是在提交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 reset
命令之前,使用git bisect
将所有内容重新置于原始状态。
答案 1 :(得分:130)
git bisect run
自动bisect 如果您的自动./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_BAD_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上显示好的和坏的引用以获得更好的时间概念:
git log --decorate --pretty=fuller --simplify-by-decoration master
这只显示具有相应引用的提交,它可以减少噪声,但确实包含类型为自动生成的引用:
refs/bisect/good*
refs/bisect/bad*
告诉我们哪些提交标记为好或坏。
如果你想玩这个命令,请考虑this test repo。
有时:
对于这些情况,例如假设失败总是在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
后,此工作正常。
git bisect run failed:
exit code 134 from '../test -aa' is < 0 or >= 128
对退出状态有点挑剔:
127以上的任何内容都会导致二分失败,例如:
assert(0)
特别是,C SIGABRT
会导致git bisect skip
并以状态134退出,非常烦人。
125是魔术,并使用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"
。
所以你可能想要使用类似的东西:
{{1}}
在git 2.16.1上测试。
答案 2 :(得分:108)
$ git bisect start
$ git bisect bad
$ git bisect good <goodcommit>
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
答案 3 :(得分:37)
再补充一点:
我们可以指定git bisect start
的文件名或路径,以防我们知道错误来自特定文件。
例如,
假设我们知道导致回归的变化是在com / workingDir中
然后我们可以运行git bisect start com/workingDir
这意味着
只检查更改了此目录内容的提交,并且
这使事情变得更快。
此外,如果很难判断特定提交是好还是坏,那么你
可以运行git bisect skip
,这将忽略它。鉴于有足够的其他
提交,git bisect将使用另一个来缩小搜索范围。
答案 4 :(得分:11)
$ git bisect ..
基本上是用于调试的 Git工具。 'Git Bisect'通过执行上一次(已知)工作提交后的提交进行调试。它使用二进制搜索来完成所有这些提交,以获得引入回归/错误的那个。
$ git bisect start
#Starting bisect
$ git bisect bad
#表示当前提交(v1.5)具有回归/设置'坏'点
$ git bisect good v1.0
#提及最后一次良好的工作提交(没有回归)
这提到'坏'和'好'点将有助于 git bisect (二分搜索)选择中间元素(commit v1.3)。如果在提交v1.3中存在回归,则将其设置为新的“坏”点,即(良好 - &gt; v1.0和Bad - &gt;&gt; v1.3 )
$ git bisect bad
或类似地,如果提交v1.3没有错误,您将其设置为新的“好点”即(*好 - &gt; v1.3和坏 - >&gt; v1.6)。
$ git bisect good
答案 5 :(得分:1)
注意:术语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
将报告引入该属性的提交。
请参见commit 06e6a74的commit 21b55e3,commit fe67687,Matthieu Moy (moy
)(2015年6月29日)。
请参见commit 21e5cfd的Antoine Delaite (CanardChouChinois
)(2015年6月29日)。
(由Junio C Hamano -- gitster
--在commit 22dd6eb中合并,2015年10月5日)