樱桃采摘合并提交时的主线父编号

Posted

技术标签:

【中文标题】樱桃采摘合并提交时的主线父编号【英文标题】:Mainline parent number when cherry picking merge commits 【发布时间】:2017-03-02 02:24:22 【问题描述】:

假设这是我的 git 历史

Z / A -- C -- D \ / 乙

我的 HEAD 目前在 Z。我想挑选BC。如果我的理解是正确的,我应该这样做:

git cherry-pick B
git cherry-pick C -m 1
git commit --allow-empty

它在我的情况下有效,因为C 是一个无操作(因此之后的空提交,我出于其他原因需要提交),但我想知道-m 之后的参数是做什么的。这是我从the docs 读到的内容:

-m 父编号

--mainline parent-number

通常您不能挑选合并,因为您不知道合并的哪一侧应该被视为主线。该选项指定主线的父级编号(从 1 开始),并允许cherry-pick 重播相对于指定父级的更改。

在我的例子中,C 有两个父母,但我怎么知道哪个是 1 和 2,更重要的是,我何时选择 1 或 2?

【问题讨论】:

这似乎主要是 ***.com/questions/9229301/… 的副本......或者你的问题真的是关于你是否可以从这个图表中确定父编号? (答案:否),或者:合并时是否存在关于第一个与第二个父级的确定性? (回答:是的,没有足够的空间来评论更多)。 您希望生成的历史记录是什么样的?你想让C' 有父母ZB' 吗?如果您已经挑选了B,为什么还需要挑选C @ScottWeldon 我希望我在该分支上生成的历史记录为A -- Z -- B' -- C'(如果C' 更容易拥有多个父母也可以)。我需要为作者信息挑选提交,尽管它是“空的” @torek 我实际上在发布这个问题之前阅读了这个问题,答案表明合并提交代表多个不同的差异并且有多个父级,例如-m 1,但并没有真正展开关于有什么区别。我认为,扩展您的第二个问题并可能显示第一个父母与第二个父母之间的差异会非常有帮助。 【参考方案1】:

我基于this answer 的理解是父 1 是要合并到的分支,父 2 是要合并的分支。所以在你的情况下,父母1是A,父母2是B。由于樱桃选择实际上是在两次提交之间应用差异,因此您使用-m 1 仅应用来自B 的更改(因为AC 之间的差异包含来自B 的更改)。在您的情况下,这可能无关紧要,因为您在 AC 之间没有提交。

所以是的,-m 1 是你想要的,即使在 AC 之间有额外的提交也是如此。

如果您想让新历史看起来更像原始历史,还有另一种方法:

git cherry-pick B
git checkout Z
git merge --no-ff --no-commit B
git commit --author="Some Dev <someone@example.com>" --date="<commit C author date>"

(如果需要,您可以在挑选樱桃之前为B 创建一个新分支。)

这将保留作者信息,应该给你一个看起来像这样的历史:

    B'
   /  \
  Z -- C'
 /
A -- C -- D
 \  /      
  B

【讨论】:

这是正确的:任何正常合并的 第一个父 是您在进行合并时所在的分支,因此 -m 1 总是给出“更改通过合并引入”。但是,无法仅从图形中判断,因为该信息在二维化过程中丢失了。 (也就是说,我们可以绘制我们喜欢的图形:图形拓扑没有父排序。父排序是 Git 添加的东西。我们需要能够在每个出站弧上粘贴少量计数从每个顶点开始,代表 Git 的父编号概念。) @torek 关于图表的要点。我通常假设当它被绘制为三角形(而不是您的答案中的菱形)时,作者指出哪个分支被合并到哪个分支。 请注意,父订单似乎也是Merge:行上显示的订单git show &lt;commit&gt;【参考方案2】:

我赞成Scott Weldon's answer,这是正确的,但我只想尝试添加包含父编号的 ASCII 艺术。给定一个看起来像这样的图表:

       B
      / \
...--A   D--...
      \ /
       C

我们可以判断节点D 是一个合并提交,但我们无法判断BC 是否是D 的第一个父节点。两者中的一个必然是第一个父母,另一个是第二个父母。所以如果我们需要知道,我们必须给图纸贴上标签,这会占用更多的空间。这是一种这样的尝试。

         B
       /   \²
...--A       D--...
       \   /¹
         C

我们现在看到,出于某种原因,1 我“颠倒”绘制了图表:提交 C 实际上是 D 的第一个父项,而提交 @987654331 @ 是第二个父母。

可以使用较低级别(“管道”)命令创建任意合并。特别是,git commit-tree 只接受您希望给它的许多 -p 参数,按照您给它们的顺序,并以给定的提交作为其父项进行新的提交。给它一个-p,它会与一个父母进行一次普通的提交。不给它-p 参数,它会进行根提交。给它 155 个不同的 -p 参数(当然,所有参数都必须解析为有效的提交 ID),它会进行一次大规模的章鱼合并提交。

然而,git merge 命令总是在第一个父级是当前HEAD 的情况下进行新提交(因此,如果在分支上,则为当前分支)。第二个父级,对于标准的双父级合并,来自.git/MERGE_HEADgit merge 将另一个提交 ID 写入其中。如果合并发生冲突,或者最终的合并提交因--no-commit 而延迟,则此MERGE_HEAD 文件实际上是唯一提交 ID 可用的地方。

(当git merge 进行章鱼合并时,使用-s octopus 策略(这种策略强制用于此类合并)以及多个其他父级,如果存在合并冲突,它会中止并且根本不留下任何痕迹,所以冲突的情况永远不会发生。我没有尝试将--no-commit 与章鱼合并组合,但从逻辑上讲,如果 Git 允许的话,这会在MERGE_HEAD 中留下第二个到第 N 个父母。)


1固执。

【讨论】:

所以如果我想知道哪些数字属于哪个父母,我会使用git cat-file -p D-sha1-hash 并且文件中的第一个父母是1,下一个是2,然后...? @Brandon:这肯定会起作用(并且会准确地向您展示提交是如何编码的,这也很好)。不过,Git 确实在其他输出中保留了父顺序,因此 git rev-parse &lt;hash&gt;^@ 也会按顺序打印它们(并且更适合脚本编写,如果你正在这样做的话)。 还有帽子和数字后缀方法,用于一次解析它们:git rev-parse &lt;hash&gt;^1git rev-parse &lt;hash&gt;^2 等等。这里的数字是十进制的,所以如果你有一个 66-parent Cthulhu merge,你会使用 ^9 然后 ^10^11 等等一直到 ^66

以上是关于樱桃采摘合并提交时的主线父编号的主要内容,如果未能解决你的问题,请参考以下文章

樱桃选择合并

合并分支,从当地分支机构挑选樱桃,没有任何冲突

错误:指定了主线,但提交不是合并;致命:还原失败

为啥我的樱桃采摘失败了? [复制]

Git 樱桃挑选和数据模型完整性

“樱桃选择合并”的最简单方法