45

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

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

那么问题是,在这种情况下二等分时,您最终会在依赖项的提交中出现不可编译的提交。

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

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

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

G---o---o---o---o---o---o---B主项目分支
   ///
  x---x---x---x---x 依赖
           \ /
            x' 依赖项目任务分支

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

4

10 回答 10

14

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

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

将每个合并的所有远程父级标记为良好将认为它们之前的所有提交都是良好的(因此被 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主项目分支
   ///
  G---x---G---x---G 依赖
           \ /
            x' 依赖项目任务分支

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

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

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

于 2011-04-13T16:14:58.950 回答
12

我也一直在寻找这样的东西。据我所知,这git 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,对其进行测试并将其标记为好/坏/跳过并从那里继续。

于 2011-04-12T17:12:42.413 回答
12

有什么办法可以--first-parent使用 git bisect

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

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

bisect: 引入第一父标志

签字人:Aaron Lipman

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

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

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

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

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

--first-parent

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

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

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

于 2020-08-24T20:35:47.427 回答
11

如果历史看起来像:

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

其中 L 不好,B 好,并且您想忽略 DEFG 分支,然后运行

$ git bisect 开始
$ git bisect skip $( git rev-list G ^C )
$ git bisect bad L
$ git bisect 好 B

其中 B、C、G 和 L 是各自的 shas 似乎可以做你想做的事。

于 2011-04-13T14:36:02.990 回答
8

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

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

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

于 2013-06-18T09:42:50.127 回答
4

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

提示:对 /info/grafts 的支持已弃用
提示:并将在未来的 Git 版本中删除。
暗示:
提示:请使用“git replace --convert-graft-file”
提示:将移植物转换为替换参考。
暗示:
提示:通过运行关闭此消息
提示:“git config advice.graftFileDeprecated false”

这是他使用“git replace”而不是移植的解决方案的更现代版本:

git rev-list --first-parent --merges --parents HEAD | \
  同时读取 COMMIT PARENT1 PARENT2;做
    git 替换 --graft $COMMIT $PARENT1;
  完毕

不幸的是,大型存储库的速度要慢得多(150k 提交大约需要 3 分钟);git replace似乎还没有批量模式。您可能希望将 rev-list 限制为仅对分范围内的提交。

要在完成后移除替换件,您可以rm .git/refs/replace/*.

于 2018-07-24T14:23:38.543 回答
2

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

git bisect skip $(comm -23 <(git rev-list G | sort) <(git rev-list --first-parent G | sort))
于 2014-02-04T07:20:38.073 回答
2

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

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

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

于 2015-09-19T23:33:36.503 回答
1

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

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

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

于 2011-04-12T16:24:01.277 回答
1

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

于 2015-10-22T03:31:49.573 回答