假设这是我的git历史记录
<>之前Z/A——c——d/B之前我的头目前在Z
。我想挑选B
和C
。如果我的理解是正确的,我应该这样做:
git cherry-pick B
git cherry-pick C -m 1
git commit --allow-empty
它在我的情况下工作,因为C
是一个无操作(因此之后的空提交,我需要提交其他原因),但我想知道-m
之后的参数是什么。以下是我从文档中读到的内容:
- m parent-number
——主线parent-number
通常您不能选择性地选择合并,因为您不知道合并的哪一边应该被认为是主线。该选项指定主线的父编号(从1开始),并允许选择性地重播相对于指定父的更改。
在我的情况下,C
有两个父母,但我怎么知道哪一个是1和2,更重要的是,当我选择1或2时,它什么时候重要?
基于这个答案,我的理解是父级1是被合并的分支,而父级2是被合并的分支。在你的例子中,父结点1是A
,父结点2是B
。因为精挑细选实际上是应用两次提交之间的差异,所以使用-m 1
只应用来自B
的更改(因为A
和C
之间的差异包含来自B
的更改)。在您的情况下,这可能无关紧要,因为您在A
和C
之间没有提交。
所以,是的,-m 1
是你想要的,这是真的,即使在A
和C
之间有额外的提交。
如果你想让新的历史记录看起来更像原来的历史记录,还有另一种方法:
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
我已经为Scott Weldon的答案投了赞成票,这是正确的,但我只是想添加一个包含父编号的ASCII艺术尝试。给定如下图:
B
/
...--A D--...
/
C
我们可以知道节点D
是一个合并提交,但是我们不能知道B
还是C
是D
的第一个父节点。两者中必然有一个是第一个父母,另一个是第二个父母。所以如果我们需要知道,我们必须在图上加标签,这样会占用更多的空间。
B
/ ²
...--A D--...
/¹
C
我们现在看到,由于某种原因,1我把图"颠倒"了:commit C
实际上是D
的第一个父节点,而commit B
是第二个父节点。
可以使用较低级别的("plumbing")命令创建任意合并。特别是,git commit-tree
只是接受你希望给它的-p
参数,按照你给它们的顺序,并用给定的提交作为它的父提交进行新的提交。给它一个-p
,它与一个父节点进行普通的提交。不给它任何-p
参数,它就会进行根提交。给它155个不同的-p
参数(当然所有参数都必须解析为有效的提交id),它就会进行一次大规模的章鱼合并提交。
git merge
命令,然而,总是使它的新提交与第一个父是当前HEAD
(因此当前分支,如果在一个分支上)。对于标准的双亲合并,第二个父节点来自.git/MERGE_HEAD
, git merge
将另一个提交ID写入其中。如果合并发生冲突,或者最终的合并提交被--no-commit
延迟,这个MERGE_HEAD
文件实际上是唯一的提交ID可用的地方。
(当git merge
使用-s octopus
策略(这种策略是强制使用的)和多个额外的父节点进行章鱼合并时,如果存在合并冲突,它将终止并且根本不会留下任何痕迹,因此冲突情况永远不会发生。我没有尝试将--no-commit
与章鱼合并,但是,从逻辑上讲,如果Git允许的话,在MERGE_HEAD
中留下第2到第N个父级。
<一口> 1> 一口>