繁体   English   中英

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

[英]How do you get git bisect to ignore merged branches?

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

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

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

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

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

所以问题是:有没有办法用 git bisect 做 --first-parent 或提供我认为有效的提交列表,以避免检查我知道已经不可编译的分支? 我们如何只检查图中标记为o的提交?

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

编辑:为了清楚起见添加了图表

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

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

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

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

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

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

鉴于问题中所述的历史,运行单线会给你:

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 测试合并提交时就会发现它,这可能是进一步调查该分支的原因。

我也一直在寻找这样的东西。 据我git rev-list --bisect --first-parentgit rev-list --bisect --first-parent似乎可以做你想做的事情,而 rev-list 的文档暗示--bisect选项是 bisect 在内部使用的选项 - 但是让git bisect将该标志添加到其对 rev-list 的调用中似乎不那么简单:

bisect 命令是由 shell 脚本 git-bisect 实现的,它反过来使用内置命令bisect--helper来实际完成有趣的部分(“计算、显示和结帐”评论说......),显然基于.git/ 中的一堆魔法状态文件。 似乎是 rev-list 命令重用了 bisect--helper 中的代码,而不是像您期望的那样。

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

作为一种解决方法,这样的事情可能会奏效:在 bisect 为您检查了一些东西之后,使用git rev-list --bisect --first-parent重置为另一个,测试并标记为好/坏/跳过,然后继续那里。

如果历史看起来像:

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 似乎做你想做的事。

有没有办法用 git bisect 做--first-parent

是的:在 Git 2.29(2020 年第 4 季度)中,“ git bisectman学习“ --first-parent ”选项以查找沿第一父链的第一个断裂点。

请参阅Aaron Lipman ( alipman88 ) 的commit ad464a4commit e8861ffcommit be5fe20commit 0fe305acommit 15a4802 (2020 年 8 月 7 日
(由Junio C gitster -- gitster --commit 47f0f94 中合并,2020 年 8 月 17 日)

bisect : 引入第一父标记

签字人:Aaron Lipman

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

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

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

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

git bisect现在包含在其手册页中

--first-parent

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

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

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

您可以使用嫁接让 git 将您的历史视为线性。 要线性化整个第一个父历史记录,您可以使用:

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

完成二等分后,只需放下移植文件即可。

Björn Steinbrink 的回答效果很好,但最近开始打印:

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/*

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

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

因此,合并提交的第一个父项总是同一个分支的假设并不总是正确的。 例如,如果您在主题分支上关闭并将 master 合并到它以获取最新信息(因此对于此合并提交,第一个父项是主题分支)然后检出 master 并将主题合并回它,您会得到一个快进合并,这只是将 master 移动到以第一个父级作为主题分支的合并提交。 这似乎是人为的,但它实际上是一个非常正常的工作流程 - 我总是将 master 合并到我的分支中,这样我的合并回 master 将是一个微不足道的合并(即,快速转发)(对不起,詹姆斯,总是忘记重新设置它) .

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

所以我尝试了这个,它似乎对我有用。 我写了一个 Python 脚本来帮助在 github 上做到这一点。 如果您运行此脚本,它将尝试向后跟踪并跟踪您的分支并发出提交 ID 列表,这些提交 ID 是合并到您的分支中的分支的提示。 使用此列表,您可以将它们提供给“git bisect good”,然后 bisect 将从您的平分中省略合并分支上的所有提交,从而实现所需的结果。

您也许可以使用git bisect start --no-checkout来避免实际将提交签出到工作树中。 然后我怀疑你可以为你真正想要测试的提交做git checkout BISECT_HEAD (即只有主分支上的第一个父提交)。 我没有试过这个,但我希望它会起作用。

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

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

手册页有详细信息; 也有有趣的阅读,太。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM