我读了一些文章,说git bisect
很棒。 然而,我不明白它为什么很棒。
请有经验的人给出一些代码示例来演示:
- 如何使用它?
- 它只是像
svn blame
吗?
我读了一些文章,说git bisect
很棒。 然而,我不明白它为什么很棒。
请有经验的人给出一些代码示例来演示:
svn blame
吗?git bisect
的思想是在历史记录中执行二分查找,以查找特定的回归。想象一下您有以下的开发历史:
... --- 0 --- 1 --- 2 --- 3 --- 4* --- 5 --- 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 bisect bad
告诉git
此修订版的状态,如果回归存在,或用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
命令之前的原始状态。git bisect bad <rev> [<rev>...]
命令将特定的提交标记为有问题的(或者使用 git bisect good <rev> [<rev>...]
将其标记为好的)。其中,rev
可以是任意的提交标识符,如分支名称、标签、提交哈希值(或其唯一前缀),等等。 - Sylvain Defresnegit bisect reset
将所有内容还原到最近的提交状态。 - peetonngit 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
依赖的测试基础设施在旧提交上出现问题,则没有解决方案,您将不得不手动处理,逐个决定如何测试提交。
然而,我发现使用这种自动化通常有效,并且对于慢速测试位于任务后备中的情况可以节省大量时间,您可以让它在夜间运行,并可能在第二天早上确定您的错误,这值得一试。
在二分后保留在第一个失败的提交上,而不是返回到master
:
git bisect reset HEAD
start
+ 初始的坏
和好
一次完成:
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 日志中显示好的和坏的引用,以更好地了解时间概念:
git log --decorate --pretty=fuller --simplify-by-decoration master
这只显示具有相应引用的提交,从而大大减少了噪音,但包括以下类型的自动生成的引用:
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上进行测试。
bisect run
特别有用。这样,我就可以让它在后台运行,或者如果它占用太多资源而需要过夜时,我也不会失去任何大脑上下文切换的时间。 - Ciro Santilli OurBigBook.com$ git bisect start
$ git bisect bad
$ git bisect good <goodcommit>
或者
$ git bisect start
$ git bisect good
$ git bisect bad <badcommit>
二分:测试此后还剩下X个修订版本要测试(大约需要Y个步骤)
问题仍然存在吗?
$ git bisect bad
$ git bisect good
<abcdef> is the first bad commit
git bisect reset
git bisect good
命令进入下一个提交。 - Geoffrey Hale补充一点:
在使用 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(二分查找)选择中间元素(提交v1.3)。如果回归在提交v1.3中存在,则将其设置为新的“坏点”,即(Good -> v1.0 and Bad -> v1.3)
$ git bisect bad
或者类似地,如果提交版本v1.3没有错误,您将将其设置为新的“好点”,即(*Good -> v1.3 and Bad -> v1.6)。
$ git bisect good
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
将报告引入该属性的提交。
moy
) 在 2015 年 6 月 29 日提交)以及 提交 21e5cfd(由 Antoine Delaite (CanardChouChinois
) 在 2015 年 6 月 29 日提交)。gitster
-- 在 2015 年 10 月 5 日的 提交 22dd6eb 合并)
git bisect run
:它包括修复了在 bisect-helper
中的回归错误,该错误错误地将给定给 'git bisect run
' 命令的参数作为辅助程序的参数。 (man)
请参见 提交 e9011b6、提交 464ce0a、提交 58786d7(2022年11月10日)由Đoàn Trần Công Danh (sgn
)提交。gitster
--进行合并)
目前,我们正在使用
bisect--helper
:使用OPT_SUBCOMMAND
解析子命令报告人:Lukáš Doktor
签名作者:Đoàn Trần Công Danh
签名作者:Taylor Blau
OPT_CMDMODE
解析子命令,即使找到命令,它仍将继续解析更多选项。当我们运行期望--log
或--no-log
参数或其中一个"--bisect-...
"参数的命令时,例如"git bisect run
"(man),bisect--helper
可能会错误地认为这些选项是bisect--helper
的选项。在从git-bisect.sh
调用时通过传递"--
"并在bisect--helper
中跳过该"--
"可以解决这些问题。但是,它可能会干扰用户的"--
"。让我们使用OPT_SUBCOMMAND
解析子命令,因为该API是为此特定用例而生的。git bisect 退出状态
Ciro Santilli在他2014年的回答中将它们称为“魔法退出状态”。
它们将在Git 2.36(2022年第二季度)中略有不同的使用方式:一个不太常见的错误是编写一个脚本来提供给 "git bisect
"(man) 运行,但没有使其可执行,在这种情况下,即使是标记为好的修订版本也会出现126或127错误代码。
请查看提交 48af1fd, 提交 ba5bb81, 提交 8efa2ac, 提交 80c2e96 (2022年1月18日) 由René Scharfe (rscharfe
)提交。
(由Junio C Hamano -- gitster
--合并于提交 e828747, 2022年3月6日)
bisect--helper
:在退出代码126和127上双重检查运行命令签名作者:René Scharfe
当运行命令无法执行或找到时,shell 分别返回退出代码 126 或 127。bisect run
。请参见示例。