你怎么得到git bisect忽略合并的分支?

时间:2011-04-12 15:59:18

标签: git git-bisect

我知道git bisect在设计上是分支感知的,所以如果在良好提交,G和错误提交之间,B,你在一个分支中合并,它也需要考虑这些变化,如该错误可能包含在分支中。

在我的情况下,我有一个依赖作为一个侧分支,我不时合并对我的主项目的更改。依赖项可以被认为是一个具有不同运行方式的库,不同的构建系统等来自我的主项目,但我仍然希望通过合并到主分支的最近更改。

问题在于,在这种情况下进行二等分处理时,您最终会在依赖项的提交中进行不可编译的提交。

我真的只想在进行二分时将每个分支合并视为一次提交。

到目前为止我找到的一个解决方法是使用git log --first-parent制作一个有效提交G..B的列表,然后在二等分的情况下,如果当前提交不在该列表中,请执行git bisect skip 。这需要花费很多时间(每次跳过都要检查/更改大量文件)。

所以问题是:有没有办法做 - 第一父与git bisect或提供一个我觉得有效的提交列表能够避免检查我知道已经不可编译的分支?我们如何仅检查图中标记为 o 的提交?

G---o---o---o---o---o---o---B  main project branch
   /       /       / 
  x---x---x---x---x            dependency
           \ /
            x'                 dependency project taskbranch

修改:为清晰起见添加了图表

10 个答案:

答案 0 :(得分:11)

我一直在寻找类似的东西。据我所知,git rev-list --bisect --first-parent似乎做了你想做的事,而rev-list的文档意味着--bisect选项是bisect在内部使用的 - 但获得{{1}将该标志添加到其对rev-list的调用似乎不那么重要:

bisect命令由shell脚本git-bisect实现,后者又使用内置命令git bisect来实际执行有趣的部分(“计算,显示和检出”表示注释...),显然基于.git /中的一堆魔术状态文件。而似乎是rev-list命令正在重复使用bisect - helper中的代码,而不是像你期望的那样反过来。

所以,我认为你必须扩展bisect - helper代码的提交过滤来做到这一点。

作为一种解决方法,这样的事情可能会起作用:在bisect为你检查一些东西后,使用bisect--helper重置为另一个,测试并标记好/坏/跳过并从那里继续。

答案 1 :(得分:10)

我想到了一个可能的解决方案,但我仍然希望找到更优雅的东西:

将所有合并的所有第二父母标记为主分支

将每个合并的所有远程父项标记为good将认为它们之前的所有提交都是好的(并且由bisect跳过)。这个解决方案也应该足够通用,可以处理来自多个分支的多个合并,只留下主分支上的提交。

git rev-list --first-parent --merges --parents GOOD..BAD \
| sed 's/^[^ ]\+ [^ ]\+ //' \
| xargs git bisect good

(用相关提交替换GOOD和BAD)

sed中的正则表达式删除了每行的前两个提交;合并提交本身,以及第一个父级,留下其余的父母(通常只是第二个)。

鉴于问题中陈述的历史,运行oneliner会给你:

G---o---o---o---o---o---o---B  main project branch
   /       /       / 
  G---x---G---x---G            dependency
           \ /
            x'                 dependency project taskbranch

这将使bisect只遍历主分支上的提交:

    o---o---o---o---o---o

如果任何合并的分支间接导致问题,则在通过bisect测试合并提交时会发现它,这可能是在该分支上进一步调查的原因。

答案 2 :(得分:8)

如果历史记录如下:

A - B - C - H - I - J - K - L
         \              /
          D - E - F - G

其中L是坏的,B很好,你想忽略DEFG分支,然后运行

$ git bisect start
$ git bisect skip $( git rev-list G ^C )
$ git bisect bad L
$ git bisect good B

其中B,C,G和L各自的shas似乎做你想要的。

答案 3 :(得分:5)

你可以让git使用移植物将历史视为线性。要线性化整个第一个父历史记录,您可以使用:

git rev-list --first-parent --merges --parents HEAD | cut -d' ' -f1,2 > .git/info/grafts

完成二分后,只需删除移植文件。

答案 4 :(得分:5)

有什么办法用git bisect做--first-parent

是:在Git 2.29(2020年第4季度)中,“ git bisectman学习了“ --first-parent”选项来查找第一个破损第一父母链。

请参见commit ad464a4commit e8861ffcommit be5fe20commit 0fe305acommit 15a4802Aaron Lipman (alipman88)(2020年8月7日)。
(由Junio C Hamano -- gitster --commit 47f0f94中合并,2020年8月17日)

bisect:引入初生标记

签名人:亚伦·利普曼

在二等分时看到合并提交时,此选项可用于仅跟随第一个父对象。

在检测通过分支合并引入的回归时,合并提交将被标识为错误的引入,并且其祖先将被忽略。

当合并的分支包含损坏的或不可构建的提交但合并本身可以的时候,此选项在避免误报时特别有用。

git bisect [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]

git bisect现在包含在其man page中:

--first-parent

看到合并提交后,仅关注第一个父提交。

在检测通过合并分支引入的回归时,合并 提交将被标识为该错误的引入,其祖先将 忽略。

此选项在避免合并时避免误报特别有用 分支包含已损坏或不可构建的提交,但合并本身可以。

答案 5 :(得分:2)

因此,假设合并提交的第一个父级始终是相同的分支并不总是正确的。例如,如果您关闭主题分支并将master合并到它以获取最新信息(因此对于此合并提交,第一个父级是主题分支)然后checkout master并将主题合并回主页,您将得到一个快进合并,它只是将master移动到具有第一个父级作为主题分支的合并提交。这可能看起来很人为,但它实际上是一个非常正常的工作流程 - 我总是将master合并到我的分支中,这样我合并回master将是一个微不足道的合并(即快速前进)(对不起James,总是忘记改变它)

我发现有一种方法可以帮助找出哪个父级是你的分支 - 合并提交评论本身。默认情况下,git编写一个合并提交注释,说明哪个分支已合并,您可以使用它来推断哪个父级是您感兴趣的分支,只要执行合并提交的人没有覆盖此合并提交评价。

所以我尝试了这个,它似乎对我有用。我写了一个Python脚本来帮助完成这个on github。如果您运行此脚本,它将尝试向后跟踪并跟随您的分支并发出提交ID列表,这些提交ID是合并到您的分支中的分支的提示。通过此列表,您可以将这些内容提供给&#34; git bisect good&#34;然后,bisect将从您的二分中省略合并分支上的所有提交,从而获得所需的结果。

答案 6 :(得分:2)

BjörnSteinbrink的答案很好用,但是最近开始打印它:

hint: Support for /info/grafts is deprecated
hint: and will be removed in a future Git version.
hint: 
hint: Please use "git replace --convert-graft-file"
hint: to convert the grafts into replace refs.
hint: 
hint: Turn this message off by running
hint: "git config advice.graftFileDeprecated false"

这是他的解决方案的更现代版本,使用“ git replace”代替了嫁接:

git rev-list --first-parent --merges --parents HEAD | \
  while read COMMIT PARENT1 PARENT2; do 
    git replace --graft $COMMIT $PARENT1; 
  done

不幸的是,对于大型仓库,它要慢得多(对于15万次提交,大约需要3分钟); git replace似乎还没有批量模式。您可能希望将rev-list限制为仅在等分范围内的提交。

要在完成后删除替换项,可以rm .git/refs/replace/*

答案 7 :(得分:1)

但是,根据您当前的解决方案,我没有看到一步法: git bisect skip可以列出要跳过的提交。 git log branchname将列出分支branchname上的提交。 所以这应该让你指定提交列表。

如果您的依赖项和主代码存在于不同的文件系统空间中,则可以使用git bisect start指定要包含的路径。根据您的代码布局,这可能是最佳选择。 (几乎可以肯定的是,如果你有一个可能包含错误的文件列表!)

man page有详细信息;看也有有趣的阅读。

答案 8 :(得分:1)

您可以通过运行以下命令来指示git-bisect只通过合并提交的第一个父项:

git bisect skip $(comm -23 <(git rev-list G | sort) <(git rev-list --first-parent G | sort))

答案 9 :(得分:1)

您可以使用git bisect start --no-checkout来避免实际检出工作树中的提交。然后我怀疑你可以为你想要测试的提交做git checkout BISECT_HEAD(即只有第一个父提交在主分支上)。我没试过,但我希望它能奏效。