如何使用git bisect?

时间:2011-01-17 12:22:35

标签: git git-bisect

我读过一些文章说git bisect很棒。但是,我不是母语人士,我无法理解为什么它很棒。

有人可以用一些代码示例演示:

  1. 如何使用它?
  2. 是否就像svn blame

6 个答案:

答案 0 :(得分:571)

git bisect背后的想法是在历史记录中执行二进制搜索以找到特定的回归。想象一下,您有以下开发历史:

... --- 0 --- 1 --- 2 --- 3 --- 4* --- 5 --- current

您知道您的程序在current修订版中无法正常运行,并且它正在修订0。因此,可能会在其中一个提交中引入回归12345current

您可以尝试检查每个提交,构建它,检查回归是否存在。如果有大量提交,这可能需要很长时间。这是线性搜索。我们可以通过二进制搜索做得更好。这就是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

然后检查另一个提交。 45(因为只有两次提交)。我们假设它选择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个版本(345)而不是4(1234)。这是一个小胜利,但这是因为我们的历史是如此之小。如果搜索范围是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 +初始badgood

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

查看到目前为止测试的内容(通过手动goodbadrun):

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-command1退出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)

TL; DR

开始:

$ 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)

注意:术语goodbad并不是唯一可用于标记具有或不具有特定属性的提交的术语。

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 06e6a74commit 21b55e3commit fe67687Matthieu Moy (moy)(2015年6月29日)。
请参见commit 21e5cfdAntoine Delaite (CanardChouChinois)(2015年6月29日)。
(由Junio C Hamano -- gitster --commit 22dd6eb中合并,2015年10月5日)