如何让git bisect忽略合并的分支?

如何让git bisect忽略合并的分支?,git,git-bisect,Git,Git Bisect,我知道git bisect在设计上是支持分支的,因此如果在良好提交G和错误提交B之间,您合并到了一个分支中,那么它也需要考虑这些更改,因为错误可能包含在分支中 在我的例子中,我有一个依赖项作为一个分支,我不时地合并对主项目的更改。这个依赖关系可以被认为是一个库,它与我的主项目有着不同的运行方式、不同的构建系统等,但我仍然希望通过合并到主分支来实现最近的更改 git rev-list --first-parent --merges --parents GOOD..BAD \ | sed 's/^[

我知道git bisect在设计上是支持分支的,因此如果在良好提交G和错误提交B之间,您合并到了一个分支中,那么它也需要考虑这些更改,因为错误可能包含在分支中

在我的例子中,我有一个依赖项作为一个分支,我不时地合并对主项目的更改。这个依赖关系可以被认为是一个库,它与我的主项目有着不同的运行方式、不同的构建系统等,但我仍然希望通过合并到主分支来实现最近的更改

git rev-list --first-parent --merges --parents GOOD..BAD \
| sed 's/^[^ ][^ ]* [^ ][^ ]* //' \
| xargs git bisect good
问题是,在这种情况下进行二分法时,最终会在依赖项的提交中进行不可编译的提交

我只想把每个分支合并看作是一个单独的提交,同时做二分。

到目前为止,我发现的一种解决方法是使用git log(第一个父级)创建一个有效提交的列表G..B,然后在对分时,如果当前提交不在该列表中,则执行git对分跳过。但这需要很多时间(每次跳过都需要签出/更改很多文件)

所以问题是:有没有任何方法可以避免签出我知道已经不可编译的分支——使用git对分的第一个父级或提供我认为有效的提交列表?如何仅检查图中标记为o的提交

G---o---o---o---o---o---o---B main project branch / / / x---x---x---x---x dependency \ / x' dependency project taskbranch G---o---o---o---o---o---B主项目分部 / / / x--x--x--x--x依赖关系 \ / x'依赖项项目任务分支
编辑:为清晰起见添加了图表

但是,根据您当前的解决方案,我看不到一步到位的方法: git bisect skip可以获取要跳过的提交列表。 git log branchname将列出branchname上的提交。 因此,这应该允许您指定提交列表

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


有细节,;这本书也有有趣的读物。

我也一直在寻找类似的东西。据我所知,
git rev list--bisect--first parent
似乎做了您想做的事情,而docs for rev list意味着,
--bisect
选项是bisect内部使用的,但是让
git bisect
将该标志添加到对rev list的调用中似乎不那么简单:

bisect命令由一个shell脚本git bisect实现,它反过来使用一个内置命令bisect--helper来实际执行有趣的部分(“计算、显示和签出”注释…),显然是基于.git/中的一堆神奇状态文件。而且似乎是revlist命令在重用来自bisect-helper的代码,而不是像您所期望的那样

因此,我认为,您必须扩展对分——助手代码的提交过滤来完成它


作为一种解决方法,类似的方法可能会奏效:在对分为您检查出某个内容后,使用
git rev list--bisect--first parent
重置为另一个,测试它并将其标记为good/bad/skip,然后从那里继续操作。

如果历史看起来像:

A - B - C - H - I - J - K - L \ / D - E - F - G 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 $git对分开始 $git对分跳过$(git修订列表G^C) $git二等分坏L $git二等分好B
其中B、C、G和L是各自的SHA,它们似乎可以满足您的需求。

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

将所有合并到主分支的第二个父级标记为良好

标记每一个合并的所有远程父节点都是好的,将考虑它们之前的所有提交都是好的(这样就被平分了)。此解决方案还应该足够通用,以处理来自多个分支的多个合并,只在主分支上保留提交

git rev-list --first-parent --merges --parents GOOD..BAD \
| sed 's/^[^ ][^ ]* [^ ][^ ]* //' \
| xargs git bisect good
(用相关承诺替换好的和坏的)

sed中的正则表达式删除每行的前两个提交;合并提交自身和第一个父级,留下其余父级(通常仅第二个父级)

鉴于问题中所述的历史,运行“一号班轮”将为您提供:

G---o---o---o---o---o---o---B main project branch / / / G---x---G---x---G dependency \ / x' dependency project taskbranch G---o---o---o---o---o---B主项目分部 / / / G--x--G--x--G相关性 \ / x'依赖项项目任务分支 这将使对分仅遍历主分支上的提交:

o---o---o---o---o---o o--o--o--o--o--o
如果任何合并的分支都是问题的间接原因,那么当您通过对分测试合并提交时,就会发现问题,这可能是进一步研究该分支的原因。

您可以使用grafts使git将历史视为线性。要线性化整个第一父历史,可以使用:

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

完成二分法后,只需删除grafts文件。

通过运行以下命令,可以指示git bisect只遍历合并提交的第一个父级:

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

git bisect skip$(comm-23因此,合并提交的第一个父级始终是同一个分支的假设并不总是正确的。例如,如果您关闭了主题分支,并将主级合并到它以获得最新信息(因此对于此合并提交,第一个父级是主题分支)然后签出master并将主题合并回它,你会得到一个快进合并,它只是将master移动到合并提交中,该合并提交将第一个父级作为你的主题分支。这似乎是人为的,但实际上是一个非常正常的工作流-我总是将master合并到我的分支中,这样我的合并回master将是一个简单的合并(即,快速)
git rev-list --first-parent --merges --parents HEAD | \
  while read COMMIT PARENT1 PARENT2; do 
    git replace --graft $COMMIT $PARENT1; 
  done
git bisect [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]