如何使用git二等分?

iezvtpos  于 2022-11-27  发布在  Git
关注(0)|答案(7)|浏览(99)

我看过一些文章说git bisect很棒,但是我不明白为什么它很棒。
有人能用一些代码示例来演示一下吗:
1.如何使用?
1.就像svn blame一样吗?

7rfyedvj

7rfyedvj1#

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将 checkout 一个commit。在我们的例子中,它将是commit 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

然后它会 checkout 另一个提交。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 + log 2N个提交,而不是用线性搜索测试大约N / 2个提交。
一旦你找到了导致回归的提交,你就可以研究它来找到问题所在。一旦完成了这个工作,你就可以使用git bisect reset命令把所有东西都恢复到使用git bisect命令之前的原始状态。

f87krz0w

f87krz0w2#

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所依赖的测试基础设施在旧的提交上中断,那么就没有解决方案,您将不得不手动地做一些事情,决定如何一个一个地测试提交。
然而我发现使用这种自动化通常是有效的,并且可以为积压的任务中的较慢测试节省大量时间,在那里您可以让它运行一夜,并且可能在第二天早上发现您的bug,这是值得一试的。

更多提示

在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_GOOD_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日志上显示好的和坏的引用,以便更好地了解时间:

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

Magic退出状态

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上测试。

x3naxklr

x3naxklr3#

TL;DR

开始日期:

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

lp0sw83n4#

再补充一点:
我们可以指定git bisect start的文件名或路径,以防我们知道bug来自特定的文件。例如,假设我们知道导致回归的更改在com/workingDir目录下,那么我们可以运行git bisect start com/workingDir这意味着只有更改了该目录内容的提交才会被检查,这会使操作更快。
另外,如果很难判断某个提交是好是坏,你可以运行git bisect skip,它会忽略它。如果有足够多的其他提交,git bisect会使用另一个来缩小搜索范围。

sqserrrh

sqserrrh5#

$ git bisect ..基本上是一个 * 用于调试的Git工具 *。'Git Bisect'通过检查自上次(已知)工作提交以来的提交来进行调试。它使用二分搜索来检查所有提交,找到引入回归/bug的提交。
$ git bisect start #开始平分
$ git bisect bad #声明当前提交(v1.5)具有回归/设置“坏”点
$ git bisect good v1.0 #将其作为最后一次正常工作提交(无回归)
提到'bad'和'good'点将帮助git bisect(折半搜索)挑选中间的元素(commit v1.3)。如果在提交v1.3时出现回归,则将其设置为新的'bad'点,即(Good -〉v1.0 and Bad -〉v1.3

$ git bisect bad

或者类似地,如果提交v1.3是无错误的,你将把它设置为新的“好点”,即(*Good -〉v1.3 and Bad -〉v1.6)。

$ git bisect good
ifmq2ha2

ifmq2ha26#

注意:术语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“。
(But请注意,不能在单个会话中将“good“和“bad“与“old“和“new“混合使用。)
在这个更一般的用法中,你可以为git bisect提供一个“new“提交,它有一些属性,而一个“old“提交没有这个属性。
每次git bisect checkout 一个提交时,测试该提交是否具有以下属性:
如果是,则将提交标记为“new“;否则,将其标记为“old“。
当二分完成后,git bisect将报告哪个提交引入了该属性。
请参见Matthieu Moy ( moy )commit 06e6a74commit 21b55e3commit fe67687(2015年6月29日)。
2015年6月29日,第15话(英语:15话)。
(由Junio C Hamano -- gitster --合并到commit 22dd6eb,2015年10月5日)
请务必使用Git 2.39(2022年第四季度)来实现git bisect run:它包括修复bisect-helper中的一个回归,该回归错误地将提供给“git bisect run”(man)的命令的参数视为帮助程序的参数。
请参见commit e9011b6commit 464ce0acommit 58786d7(2022年11月10日),作者为Đoàn Trần Công Danh ( sgn )
(2022年11月23日,由Junio C Hamano -- gitster --commit e3d40fb中合并)
第1001章:使用OPT_SUBCOMMAND解析子命令
报告人:卢卡什医生
签署人:段陈公丹
签署人:泰勒·布劳
到目前为止,我们正在使用OPT_CMDMODE,解析子命令,即使找到了该命令,它也将继续解析更多选项。
当我们运行“git bisect run“(man)时,如果命令需要--log--no-log参数,或者“--bisect-...“参数之一,bisect--helper可能会错误地认为这些选项是bisect--helper的选项。
我们可以通过在从git-bisect.sh调用时传递“--“并跳过bisect--helper中的“--“来解决这些问题。
但是,它可能会干扰用户的“--“。
让我们使用OPT_SUBCOMMAND解析子命令,因为该API是为此特定用例而生的。

p5fdfcr1

p5fdfcr17#

git二等分退出状态
Ciro Santilli的2014 answer将它们称为“神奇的退出状态”
它们在Git 2.36(Q2 2022)中的使用方式略有不同:一个不太常见的错误是编写一个脚本来运行“git bisect“(man),而不使其可执行,在这种情况下,所有的测试都将退出,并返回126或127个错误代码,即使是标记为好的修订版。
尝试识别这种情况并尽早停止迭代。
参见René Scharfe ( rscharfe )commit 48af1fdcommit ba5bb81commit 8efa2accommit 80c2e96(2022年1月18日)。
(2022年3月6日由Junio C Hamano -- gitster --合并至commit e828747
第1001章:在退出代码126和127上仔细检查运行命令
签署人:勒内·沙夫
当无法执行或找不到运行命令时,shell将分别返回退出代码126或127。
由于历史原因,允许有效的运行命令返回这些代码,以指示错误的修订。
这意味着打字错误可能导致假的二等分运行,在整个距离上运行,并最终报告无效结果。
最好的解决方案是保留退出代码126和127,如71b0251(二等分运行:,2007年10月26日,Git v1.5.4-rc 0--merge)(二等分运行:如果脚本退出代码为125,则“跳过”当前提交。,2007-10-26)对125执行了此操作,并在获得它们时中止bisect run
不过,这可能对那些依赖于说明126和127可以用于糟糕修订的文档的人来说不方便。
此修补程序使用的解决方法是在已知良好的修订版上运行该命令,如果仍然得到相同的错误代码,则中止。
这会为使用退出代码126和127的脚本的运行添加一个步骤,但仍支持它们,但有一个例外:如果命令无法识别(手动标记的)已知良好的版本,则无法使用该命令。
使用低退出代码的运行命令不受影响。
在执行缺失命令两次和三次校验(第一步,已知良好的修订版本,并返回第一步的修订版本)后,报告打字错误。
请参阅examples

相关问题