我读了一些文章说那git bisect
太好了。但是,我不是母语人士,而且我不明白为什么它很棒。
有人可以用一些代码示例进行演示:
- 如何使用它?
- 就像
svn blame
吗?
我读了一些文章说那git bisect
太好了。但是,我不是母语人士,而且我不明白为什么它很棒。
有人可以用一些代码示例进行演示:
svn blame
吗?Answers:
背后的想法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
将检出提交。在我们的例子中,它将是commit 3
。您需要构建程序,并检查是否存在回归。您还需要git
通过git bisect bad
是否存在回归来告知此修订的状态git bisect good
。
让我们假设回归是在commit中引入的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
可以是任何修订标识符,例如分支名称,标记,提交哈希(或提交哈希的唯一前缀),...
git bisect reset
将所有内容放回最近的提交中
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
-like变量并从那里运行来逃脱。
当然,如果test
依赖的测试基础结构中断了较早的提交,则没有解决方案,您将必须手动进行操作,决定如何逐个测试提交。
但是我发现使用这种自动化通常可以工作,并且可以节省大量的时间,可以节省积压的任务中的较慢测试,您可以让它整夜运行,并且有可能在第二天早上发现错误,这是值得的尝试。
在二等分之后停留在第一个失败的提交,而不是返回到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_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 log上显示好坏参考以获得更好的时间观念:
git log --decorate --pretty=fuller --simplify-by-decoration master
这仅显示带有相应ref的提交,这将大大降低噪声,但确实包括类型为自动生成的ref:
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)
导致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"
在git 2.16.1上测试。
test_script
+模块化测试套件的必要测试样板,并在二等分的同时从单独的文件运行它。修复后,将测试合并到主测试套件中。
bisect run
当测试需要很长时间才能完成时,我发现它特别有用,而且我很确定测试系统不会中断。这样,我可以让它在后台运行,如果占用过多资源,则可以整夜运行,而不会浪费任何大脑上下文切换时间。
$ 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
git bisect good
以转到下一个提交。
$ git bisect ..
基本上是用于调试的Git工具。“ Git Bisect”通过遍历自上次(已知)工作提交以来的先前提交进行调试。它使用二进制搜索来遍历所有这些提交,最后到达引入了回归/错误的提交。
$ git bisect start
#开始二等分
$ git bisect bad
#说明当前提交(v1.5)具有回归/设置“坏”点
$ git bisect good v1.0
#提及它最后一次有效的提交(不进行回归)
提到“坏”和“好”点将有助于git bisect(二进制搜索)选择中间元素(提交v1.3)。如果在提交v1.3处存在回归,则将其设置为新的“坏”点,即(好-> v1.0和坏-> v1.3)
$ git bisect bad
或类似地,如果提交v1.3没有错误,则将其设置为新的“好点”,即(* Good-> v1.3和Bad-> v1.6)。
$ git bisect good
注意:术语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
将报告哪个提交引入了该属性。
参见Matthieu Moy()的提交06e6a74,提交21b55e3和提交fe67687(2015年6月29日)。
参见Antoine Delaite()的commit 21e5cfd(2015年6月29日)。(由Junio C Hamano合并--在commit 22dd6eb中,2015年10月5日)moy
CanardChouChinois
gitster