如何使用git bisect?

IAd*_*ter 416 git git-bisect

我读过一些文章说这git bisect很棒,但我不是母语,我不明白为什么它很棒.

你能否在一些代码示例上展示一下它的惊人之处?它就像svn blame

Syl*_*sne 610

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

... --- 0 --- 1 --- 2 --- 3 --- 4* --- 5 --- current
Run Code Online (Sandbox Code Playgroud)

您知道您的程序在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
Run Code Online (Sandbox Code Playgroud)

执行此命令后,git将签出提交.在我们的例子中,它将被提交3.您需要构建程序,并检查是否存在回归.如果存在回归,或者不存在回归,您还需要告知git此修订的状态.git bisect badgit bisect good

我们假设回归是在提交中引入的4.然后在这个版本中没有回归,我们告诉它git.

$ make
$ make test
... ... ...
$ git bisect good
Bisecting: 0 revisions left to test after this (roughly 1 step)
[< ... sha ... >] 5
Run Code Online (Sandbox Code Playgroud)

然后它将签出另一个提交.无论是45(如只有两个提交).我们假设它被选中了5.在构建之后,我们测试程序并看到回归存在.然后我们告诉它git:

$ make
$ make test
... ... ...
$ git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[< ... sha ... >] 4
Run Code Online (Sandbox Code Playgroud)

我们测试了最后一次修订4.由于它是引入回归的那个,我们告诉它git:

$ make
$ make test
... ... ...
$ git bisect bad
< ... sha ... > is the first bad commit
< ... commit message ... >
Run Code Online (Sandbox Code Playgroud)

在这个简单的情况下,我们只需要测试3个版本(3,4,5),而不是4( ,1,2,).3 4这是一个小胜利,但这是因为我们的历史是如此之小.如果搜索范围是N次提交,我们应该期望git bisect用线性搜索测试1 + log2 N次提交而不是大约N/2次提交.

一旦找到引入回归的提交,您就可以研究它以找到问题.完成此操作后,您git bisect reset将在使用git bisect命令之前将所有内容重新置于原始状态.

  • ...一旦你完成了,你输入`git bisect reset`将所有东西都放回到最近的提交中 (34认同)
  • 堆栈上最令人敬畏的答案之一.非常好清楚.我一直在做手工这个过程里,只是一种选择一个好的和坏之间的任意中间点提交,然后再一个和好/坏取决于它是否是好/坏本身之间.哈哈,直到今天我从来没有听说过这个git子命令,这一直是一个巨大的痛苦...哈哈哈 (14认同)
  • 我在这里要反对,这是对bisect的一个很好的解释,但实际上并没有帮助我使用它.特别是因为我已经设法找到一个好的提交,我现在在那个分支上.从这个位置来看,这个解释完全没有帮助.例如,如何指定坏分支而不检查它 (3认同)
  • 您可以使用`git bisect bad <rev> [<rev> ...]`将特定修订标记为坏(或者使用`git bisect good <rev> [<rev> ...]`).`rev`可以是任何修订标识符,如分支名称,标记,提交哈希(或提交哈希的唯一前缀),... (3认同)
  • @Nemoden,是的,它可以,基本上它对任何类型的项目都有用.您只需要将"make test"步骤替换为"部署网站并重现问题" (3认同)

Cir*_*四事件 146

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
Run Code Online (Sandbox Code Playgroud)

当然,假设如果测试脚本./test是git跟踪的,那么它在二分期间的某些早期提交中不会消失.

我发现很多时候你只需PATH要从树中复制树内脚本,并且可能玩类似变量,然后从那里运行它就可以逃脱.

当然,如果测试基础设施test依赖于旧提交,那么就没有解决方案,您将不得不手动完成任务,决定如何逐个测试提交.

更多提示

在bisect之后保持第一次失败的提交而不是回到master:

git bisect reset HEAD
Run Code Online (Sandbox Code Playgroud)

start+初始badgood一次性:

git bisect start KNOWN_BAD_COMMIT KNOWN_GOOD_COMMIT~
Run Code Online (Sandbox Code Playgroud)

是相同的:

git checkout KNOWN_BAD_COMMIT
git bisect start
git bisect bad
git bisect good KNOWN_GOOD_COMMIT
Run Code Online (Sandbox Code Playgroud)

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

git bisect log
Run Code Online (Sandbox Code Playgroud)

样本输出:

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
Run Code Online (Sandbox Code Playgroud)

在git log上显示好的和坏的refs以获得更好的时间概念:

git log --decorate --pretty=fuller --simplify-by-decoration master
Run Code Online (Sandbox Code Playgroud)

这只显示具有相应引用的提交,这会减少噪声,但确实包括类型的自动生成的引用:

refs/bisect/good*
refs/bisect/bad*
Run Code Online (Sandbox Code Playgroud)

告诉我们哪些提交标记为好或坏.

如果你想玩这个命令,请考虑这个测试回购.

失败很快,成功很慢

有时:

  • 失败发生得很快,例如第一次测试中断之一
  • 成功需要一段时间,例如破损的测试通过,以及我们不关心的所有其他测试

对于那些情况,例如假设失败总是在5秒内发生,如果我们懒得使测试更具体,我们可以使用timeout如下:

#!/usr/bin/env bash
timeout 5 test-command
if [ $? -eq 1 ]; then
  exit 1
fi
Run Code Online (Sandbox Code Playgroud)

这可以在timeout退出124失败时test-command退出1.

魔术退出状态

git bisect run 退出状态有点挑剔:

  • 任何高于127的东西都会导致二分失败,例如:

    git bisect run failed:
    exit code 134 from '../test -aa' is < 0 or >= 128
    
    Run Code Online (Sandbox Code Playgroud)

    特别是,C assert(0)导致a 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"
Run Code Online (Sandbox Code Playgroud)

在git 2.16.1上测试过.

  • @thebjorn你有一点:据我所知,测试必须在PATH中的外部可执行文件中,或者在repo中的未跟踪文件中.在许多情况下,这是可能的:将测试放在一个单独的文件中,包括必要的测试样板和精心设计的`test_script` +模块化测试套件,并在分割时从单独的文件中运行它.修复时,将测试合并到主测试套件中. (7认同)
  • 当恢复/平分回到先前/坏的修订版(没有新编写的测试版)时,git如何知道保持新测试不会消失? (6认同)
  • 'git bisect run' 有很多方法会出错 - 例如,查看一个好的提交是如何被一个坏的合并逆转的。它进出,又进又出,只有最后一个“出”是坏的。但是,您始终可以手动执行“git bisect”。因为它是一个二等分,所以只需要几个步骤 - 例如 1024 次提交 10 步。 (2认同)

Geo*_*ale 113

TL; DR

开始:

$ git bisect start
$ git bisect bad
$ git bisect good <goodcommit>
Run Code Online (Sandbox Code Playgroud)

Bisecting: X revisions left to test after this (roughly Y steps)

重复:

问题仍然存在?

  • 是: $ git bisect bad
  • 没有: $ git bisect good

结果:

<abcdef> is the first bad commit
Run Code Online (Sandbox Code Playgroud)

完成时:

git bisect reset
Run Code Online (Sandbox Code Playgroud)

  • 确保你是你的git repo的根,或者你会得到一个奇怪的"你需要从工作树的顶层运行这个命令." 错误. (2认同)

Nic*_*cks 38

只是补充一点:

我们可以指定文件名或路径 git bisect start,以防我们知道错误来自特定文件.例如,假设我们知道导致回归的更改位于com/workingDir目录中,然后我们可以运行.git bisect start com/workingDir这意味着只会检查更改此目录内容的提交,这会使事情变得更快.

此外,如果很难判断特定提交是好还是坏,您可以运行git bisect skip,这将忽略它.鉴于有足够的其他提交,git bisect将使用另一个来缩小搜索范围.


Nab*_*med 12

$ 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).如果在commit v1.3中存在回归,则将其设置为新的"坏"点,即(Good - > v1.0和Bad - > v1.3)

$ git bisect bad
Run Code Online (Sandbox Code Playgroud)

或类似地,如果提交v1.3没有错误,你将它设置为新的'好点'即(*好 - > v1.3和坏 - > v1.6).

$ git bisect good
Run Code Online (Sandbox Code Playgroud)


Von*_*onC 5

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

Git 2.7(2015 年第四季度)引入了新git bisect选项。

 git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
                  [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]
Run Code Online (Sandbox Code Playgroud)

随着文档添加:

有时,您不是在寻找引入破坏的提交,而是在寻找导致其他“旧”状态和“新”状态之间发生变化提交

例如,您可能正在寻找引入特定修复程序的提交。
或者您可能正在寻找第一个提交,其中源代码文件名最终全部转换为您公司的命名标准。管他呢。

在这种情况下,使用术语“好”和“坏”来指代“变更前的状态”和“变更后的状态”可能会非常混乱。

因此,您可以分别使用术语“ old”和“ new”来代替“ good”和“ bad”。
(但请注意,您不能在单个会话中将“ good”和“ bad”与“ old”和“ new”混合使用。)

在这种更一般的用法中,您提供git bisect了一个new具有某些属性的 " old" 提交和一个没有该属性的 " " 提交。

每次git bisect检出提交时,您测试该提交是否具有以下属性:
如果具有,则将该提交标记为“ new”;否则,将其标记为“ old”。

当二分完成后,git bisect将报告哪个提交引入了该属性。


请参阅Matthieu Moy ( ) 的commit 06e6a74commit 21b55e3commit fe67687(2015 年 6 月 29 日。 请参阅Antoine Delaite ( ) 的commit 21e5cfd(2015 年 6 月 29 日(由Junio C Hamano合并-- --提交 22dd6eb,2015 年 10 月 5 日)moy
CanardChouChinois
gitster