使用 git rebase interactive 来编排 git cherry-pick 系列?
Using git rebase interactive to orchestrate series of git cherry-pick?
git cherry-pick 允许通过指示哪个合并父代应该用作基线来简单地挑选简单的合并。例如:
git cherry-pick -m 1 1234abcdef
我有一堆要挑选的提交,其中一些可能是合并,而其他则不是。我希望能够使用 git rebase 来挑选所有这些提交,如下所示:
git rebase -i --onto myBranch myBranch
并将选择列表放入交互式文件中:
p 1234
p 3224
... a bunch more picks
p abcde
而且,如果 git rebase 在这些提交中遇到合并,我想指定等效于 cherry-pick 的 -m 1
选项来指示应该针对第一个父级选择更改.
我已经尝试了一些与合并相关的选项来变基,但我总是以错误告终:
commit 3c4ffe04532 is a merge but no -m option was given.
(即使我指定 -m 来变基。)
我意识到我可以使用 cherry-pick 编写脚本,但我喜欢现有的行为 rebase -i
(它会遍历命令列表并在遇到无法处理的内容时暂停)。我非常想直接利用该逻辑,但我一直无法找出正确的方法来巧妙地使用 rebase 的 pick
命令来填补这个空白。
有没有办法让 rebase 为 pick
采用 cherry-pick 的 -m #
行为?
以另一种方式陈述我的目标并帮助澄清问题 - 我想使用 git-rebase 的 --i
功能来协调一系列 git cherry-pick
,以便任何合并冲突可以手动解决流程中的问题,然后可以使用 --continue
、--abort
and/or --skip
.
管理流程
这会很有用,因为一个简单的脚本包含:
git cherry-pick -m 1 e1bed15c97f3f
git cherry-pick -m 1 6b5e6060b0e99
....
git cherry-pick -m 1 1a625d6b45faa
很可能会因这样的错误而中止:
error: could not apply 6b5e6060b0e99... Implement Something...
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
d:\src>git cherry-pick -m 1 e1bed15c97f3f
error: Cherry-picking is not possible because you have unmerged files.
hint: Fix them up in the work tree, and then use 'git add/rm <file>'
hint: as appropriate to mark resolution and make a commit.
fatal: cherry-pick failed
谢谢!
关于使用 --rebase-merges
在这里是相关的;考虑一下您要解决的实际问题(您还没有真正描述过:我会在下面指出事情似乎已经脱离 rails 的地方)。对于 git rebase
今天的情况,您可能正在做的事情有点太难了。但我 认为 你所做的正是 -r
的设计目的。
如果 -r
有效,您就完成了。如果您的 Git 是旧的,您可能没有 -r
/ --rebase-merges
选项。如果是这样,最好的答案是升级您的 Git.
关于变基的更多信息
让我们更多地谈谈一般的 rebase,从这里开始:
Is there a way to get rebase to adopt cherry-pick's -m #
behavior for pick
?
否:如果有,无论如何也行不通,至少一般情况下行不通。原因如下。
当您在此处使用 -m
选项“复制”合并时,您将其复制到 non-merge 普通提交中。 -m
选项使 Git 将合并提交视为 是 普通提交,具有单个 parent 和 -m
标志告诉它哪个 parent 调用“the” single parent。但是合并提交的目的通常是合并两个parents.的工作 1
同时,git rebase
的目的是重复复制一些提交,随后放弃原始提交以支持新副本。 复制 合并提交是不可能的——cherry-pick 的 -m
不这样做;它会产生一个普通的提交——所以 rebase 通常 discards 合并提交。我将在下面展示如何以及为什么这是正确的事情,以及标准 rebase 的工作方式。
git rebase -i --onto myBranch myBranch
请注意 --onto
的参数和 the git rebase
documentation 调用 upstream
的另一个参数,默认为相同的东西,所以这更简单地写成:
git rebase -i myBranch
此操作要复制的一组提交限于不超过由以下内容生成的提交:
git log myBranch..HEAD
也就是说,假设我们有以下内容,其中较新的提交向右,我们目前在分支 topic
:
G--H <-- topic (HEAD)
/
...--E--F--I--J <-- myBranch
运行 git rebase myBranch
,有或没有 --interactive
,告诉 Git:首先,列出那些可以从 HEAD
访问的提交又名 topic
,减去 也 可从 myBranch
. 访问的任何提交,这导致 Git 列出提交 G
和 H
内部。这些是复制的候选人。
如果这些是 最终将 复制的提交,并且其他简化假设成立,结果将是:
G--H [abandoned]
/
...--E--F--I--J <-- myBranch
\
G'-H' <-- topic (HEAD)
其中 G'
和 H'
是原始提交 G
和 H
的副本,每个副本都有两个重要的区别:
G'
的parent是J
,而不是F
。 G'
中的文件包含 G
对 F
所做的 对 J
的相同 更改 ,因此 存储在G'
中的快照与G
中的不同。
H'
的 parent 是 G'
,而不是 G
,它的快照也有很大的不同。
也就是说,由于每个提交都持有一个完整快照,我们需要复制提交中的快照与原始提交中的快照不同。新快照的差异在于 比较 G'
与 J
或多或少产生相同的 diff,作为 比较 G
与 F
。当然,链接(在 Git 中总是向后)也是不同的,因此副本出现在 myBranch
中的最后一次提交之后。
1一个 octopus merge,如果你有的话,它结合了来自两个以上 parent 的工作,并且rare -s ours
合并完全丢弃了 one parent 的内容,因此这些特殊情况更加特殊;一般来说,rebase 不应该用在这些上面。
rebase 没有故意做什么
假设在我们最初的两个提交中,G
和 H
:
G--H <-- topic (HEAD)
/
...--E--F--I--J <-- myBranch
将从G
更改为H
与完全相同将 从 I
更改为 J
。例如,两个提交都修复了 README
文件中同一个拼写错误的单词的拼写,并且什么都不做。
当我们 运行 git rebase myBranch
时,Git 仍然列出提交 G
和 H
。但它也会查看提交 I
和 J
,对于每个提交,Git 计算它所谓的 补丁 ID(参见 the git patch-ID
documentation).这个补丁 ID 告诉 Git:Commit H
是提交 J
. Git then drops 从要复制的提交列表中提交 H
。
所以当我们说 rebase 列出 myBranch..HEAD
来让候选提交复制时,这些只是 候选 。其中一些候选人是故意自动淘汰的。在这个特殊情况下,只有 H
被故意消除,rebase 的最终结果将是:
G--H [abandoned]
/
...--E--F--I--J <-- myBranch
\
G' <-- topic (HEAD)
Git 基本上认为提交 H
已经应用。所以它完全放弃了它。
Git 还使用一种叫做 fork point 代码的东西来处理相当复杂的舞蹈。 fork-point 代码的目标是发现 被故意删除的提交 并在变基期间自动删除它们。这段代码通常会做正确的事情,尽管它可能会失败。2 在这种情况下,patch-ID 和 fork-point 代码似乎都没有问题,但是有又一个大的特例,值得单独一节。
2它可能失灵的事实让我认为它不一定是正确的默认设置。这也适用于“已在上游应用”patch-ID 的情况。特别是,交互式 rebase 确实应该在其指令 sheet 中包含这些提交,其中 pre-selected 操作是“drop”,以及关于它们被删除的原因的评论。今天不是这样。
合并
至此,我们画的图很简单。但是假设我们的 topic
分支提交看起来像这样:
I--J
/ \
G--H M--N <-- topic (HEAD)
/ \ /
/ K--L
/
...--E--F--------------O--P <-- myBranch
当我们运行:
git log myBranch..topic
我们将看到提交 N
和 M
,然后按某种顺序提交 I
到 L
,之后显示 I
J
但 randomly-ordered 相对于 K
和 L
,K
显示在 L
之后,但 randomly-ordered 相对于 I
和 J
。然后我们将看到提交 H
,然后是 G
,这就是列表的末尾。
(如果我们添加 --topo-order
,列表的顺序会受到更多限制。rebase 代码在内部添加 --topo-order
。我们仍然不知道是 L
还是 J
将排在第一位,但是一旦我们得到其中一个,我们将在转到另一行之前完成整行。没有 --topo-order
我们可以看到 N
、M
、 L
、J
、K
、I
、H
、G
实例。)
这里是您的问题 rails 有点偏离的地方。 git rebase
命令将 自动删除合并提交 M
完全,原因有二:
- cherry-pick(以及基于旧
git format-patch
/ git am
的方法的扩展)不能 复制合并;和
- 标准变基的结果不应该复制合并。
所以你不会有一个pick
命令用于提交M
。要获得一个,您必须手动插入自己的,这是一个错误。要了解原因,让我们看看 Git 如何在没有 pick <hash-of-M>
的情况下使用常规(非 --rebase-merges
)变基来处理此问题。
序列从列出要复制的提交开始。假设它们按此顺序出现,在 git rebase
小心地颠倒它们后 3 同时删除合并:G-H-I-J-K-L-N
.
如果复制阶段一切顺利,结果将是:
I--J
/ \
G--H M--N [abandoned]
/ \ /
/ K--L
/
...--E--F--O--P <-- myBranch
\
G'-H'-I'-J'-K'-L'-N' <-- topic (HEAD)
也就是说,git rebase
已经 将合并变平了 。但是 merge M
的目的是 合并 I-J
和 K-L
分支上的工作 。我们 不需要 合并,因为将 K
复制到 K'
的过程是:
- 对于
H
-vs-K
提交中的每个更改,对从 I'
; 中获取的内容进行相同的更改
- 现在将其提交为新提交
K'
。
也就是说,提交 K'
不是基于 H
或 H'
,而是基于 I'
。它已经包含了另一个分支的工作。同样,当 Git 将 L
复制到 L'
时,它会在 已经包含另一个分支的工作 的提交上执行此操作。所以不需要分支。 rebase 操作只是将其完全扁平化。
3请记住,Git 是反向计算的,因此列表总是先出现 N
。我们最后需要 N
,所以 rebase 反转列表。
--rebase-merges
选项
这种扁平化合并的想法并不总是好的。有时效果不是很好。当然,像这样的系列:
I--J
/
...--H
\
K--L
通常两个分支上的变化都相对较少,因此“扁平化分支”很容易并且进展顺利。但是,如果该系列在每个分支中都有大量提交怎么办:
o--o--...(1000 commits)...--o--tip1
/
...--o
\
o--o--....................--o--tip2
在这种情况下,合并两个提示提交的合并可能有很多工作要做。将合并展平是不切实际的。
或者,也许我们只是 喜欢 存在合并。合并代表了一些重要的东西,我们希望未来的代码考古学家看到它。
好吧,“复制”合并确实是不可能的。 Cherry-pick 的 -m
标志不会那样做。如果我们“复制”与 cherry-pick -m
在 扁平化之后的合并:
I--J
/ \
G--H M--N <-- topic
/ \ /
/ K--L
/
...--E--F--O--P <-- myBranch
\
G'-H'-I'-J'-K'-L' <-- HEAD
我们只是 re-introducing 我们已经通过 I-J
或 K-L
获得的更改。要“复制”合并正确,我们必须先形成一个分支:
I--J
/ \
G--H M--N <-- topic
/ \ /
/ K--L
/
...--E--F--O--P <-- myBranch
\
\ I'-J' <-- temp-label-1
\ /
G'-H'
\
K'-L' <-- temp-label-2, HEAD
然后我们必须选择正确的分支 tip 作为 HEAD
提交,然后从字面上 运行 git merge
再次进行M'
:
reset-to temp-label-1
merge temp-label-2
如果合并顺利,我们现在将拥有:
I--J
/ \
G--H M--N <-- topic
/ \ /
/ K--L
/
...--E--F--O--P <-- myBranch
\
\ I'-J' <-- temp-label-1
\ / \
G'-H' M' <-- HEAD
\ /
K'-L' <-- temp-label-2
我们现在可以选择<em>hash-of-N</em>
来制作N'
:
I--J
/ \
G--H M--N <-- topic
/ \ /
/ K--L
/
...--E--F--O--P <-- myBranch
\
\ I'-J' <-- temp-label-1
\ / \
G'-H' M'-N' <-- HEAD
\ /
K'-L' <-- temp-label-2
和然后我们完成了这个花哨的rebase-that-re-does-the-merge,可以移动分支标签topic
并删除任何临时标签:
I--J
/ \
G--H M--N [abandoned]
/ \ /
/ K--L
/
...--E--F--O--P <-- myBranch
\
\ I'-J'
\ / \
G'-H' M'-N' <-- topic (HEAD)
\ /
K'-L'
这就是 git cherry-pick --rebase-merges
所做的。为了达到这个结果,它需要一些额外的命令和插入临时标签的能力。 (请注意,H'
也会有一个临时标签,因为 cherry-picking 操作序列必须在将 K
复制到 K'
之前重置 HEAD
。您将在指令 sheet 中看到所有这些标签和重置,它需要知道何时制作各种标签以及将 HEAD
移动到哪里。)
git cherry-pick 允许通过指示哪个合并父代应该用作基线来简单地挑选简单的合并。例如:
git cherry-pick -m 1 1234abcdef
我有一堆要挑选的提交,其中一些可能是合并,而其他则不是。我希望能够使用 git rebase 来挑选所有这些提交,如下所示:
git rebase -i --onto myBranch myBranch
并将选择列表放入交互式文件中:
p 1234
p 3224
... a bunch more picks
p abcde
而且,如果 git rebase 在这些提交中遇到合并,我想指定等效于 cherry-pick 的 -m 1
选项来指示应该针对第一个父级选择更改.
我已经尝试了一些与合并相关的选项来变基,但我总是以错误告终:
commit 3c4ffe04532 is a merge but no -m option was given.
(即使我指定 -m 来变基。)
我意识到我可以使用 cherry-pick 编写脚本,但我喜欢现有的行为 rebase -i
(它会遍历命令列表并在遇到无法处理的内容时暂停)。我非常想直接利用该逻辑,但我一直无法找出正确的方法来巧妙地使用 rebase 的 pick
命令来填补这个空白。
有没有办法让 rebase 为 pick
采用 cherry-pick 的 -m #
行为?
以另一种方式陈述我的目标并帮助澄清问题 - 我想使用 git-rebase 的 --i
功能来协调一系列 git cherry-pick
,以便任何合并冲突可以手动解决流程中的问题,然后可以使用 --continue
、--abort
and/or --skip
.
这会很有用,因为一个简单的脚本包含:
git cherry-pick -m 1 e1bed15c97f3f
git cherry-pick -m 1 6b5e6060b0e99
....
git cherry-pick -m 1 1a625d6b45faa
很可能会因这样的错误而中止:
error: could not apply 6b5e6060b0e99... Implement Something...
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
d:\src>git cherry-pick -m 1 e1bed15c97f3f
error: Cherry-picking is not possible because you have unmerged files.
hint: Fix them up in the work tree, and then use 'git add/rm <file>'
hint: as appropriate to mark resolution and make a commit.
fatal: cherry-pick failed
谢谢!
--rebase-merges
在这里是相关的;考虑一下您要解决的实际问题(您还没有真正描述过:我会在下面指出事情似乎已经脱离 rails 的地方)。对于 git rebase
今天的情况,您可能正在做的事情有点太难了。但我 认为 你所做的正是 -r
的设计目的。
如果 -r
有效,您就完成了。如果您的 Git 是旧的,您可能没有 -r
/ --rebase-merges
选项。如果是这样,最好的答案是升级您的 Git.
关于变基的更多信息
让我们更多地谈谈一般的 rebase,从这里开始:
Is there a way to get rebase to adopt cherry-pick's
-m #
behavior forpick
?
否:如果有,无论如何也行不通,至少一般情况下行不通。原因如下。
当您在此处使用 -m
选项“复制”合并时,您将其复制到 non-merge 普通提交中。 -m
选项使 Git 将合并提交视为 是 普通提交,具有单个 parent 和 -m
标志告诉它哪个 parent 调用“the” single parent。但是合并提交的目的通常是合并两个parents.的工作 1
同时,git rebase
的目的是重复复制一些提交,随后放弃原始提交以支持新副本。 复制 合并提交是不可能的——cherry-pick 的 -m
不这样做;它会产生一个普通的提交——所以 rebase 通常 discards 合并提交。我将在下面展示如何以及为什么这是正确的事情,以及标准 rebase 的工作方式。
git rebase -i --onto myBranch myBranch
请注意 --onto
的参数和 the git rebase
documentation 调用 upstream
的另一个参数,默认为相同的东西,所以这更简单地写成:
git rebase -i myBranch
此操作要复制的一组提交限于不超过由以下内容生成的提交:
git log myBranch..HEAD
也就是说,假设我们有以下内容,其中较新的提交向右,我们目前在分支 topic
:
G--H <-- topic (HEAD)
/
...--E--F--I--J <-- myBranch
运行 git rebase myBranch
,有或没有 --interactive
,告诉 Git:首先,列出那些可以从 HEAD
访问的提交又名 topic
,减去 也 可从 myBranch
. 访问的任何提交,这导致 Git 列出提交 G
和 H
内部。这些是复制的候选人。
如果这些是 最终将 复制的提交,并且其他简化假设成立,结果将是:
G--H [abandoned]
/
...--E--F--I--J <-- myBranch
\
G'-H' <-- topic (HEAD)
其中 G'
和 H'
是原始提交 G
和 H
的副本,每个副本都有两个重要的区别:
G'
的parent是J
,而不是F
。G'
中的文件包含G
对F
所做的 对J
的相同 更改 ,因此 存储在G'
中的快照与G
中的不同。H'
的 parent 是G'
,而不是G
,它的快照也有很大的不同。
也就是说,由于每个提交都持有一个完整快照,我们需要复制提交中的快照与原始提交中的快照不同。新快照的差异在于 比较 G'
与 J
或多或少产生相同的 diff,作为 比较 G
与 F
。当然,链接(在 Git 中总是向后)也是不同的,因此副本出现在 myBranch
中的最后一次提交之后。
1一个 octopus merge,如果你有的话,它结合了来自两个以上 parent 的工作,并且rare -s ours
合并完全丢弃了 one parent 的内容,因此这些特殊情况更加特殊;一般来说,rebase 不应该用在这些上面。
rebase 没有故意做什么
假设在我们最初的两个提交中,G
和 H
:
G--H <-- topic (HEAD)
/
...--E--F--I--J <-- myBranch
将从G
更改为H
与完全相同将 从 I
更改为 J
。例如,两个提交都修复了 README
文件中同一个拼写错误的单词的拼写,并且什么都不做。
当我们 运行 git rebase myBranch
时,Git 仍然列出提交 G
和 H
。但它也会查看提交 I
和 J
,对于每个提交,Git 计算它所谓的 补丁 ID(参见 the git patch-ID
documentation).这个补丁 ID 告诉 Git:Commit H
是提交 J
. Git then drops 从要复制的提交列表中提交 H
。
所以当我们说 rebase 列出 myBranch..HEAD
来让候选提交复制时,这些只是 候选 。其中一些候选人是故意自动淘汰的。在这个特殊情况下,只有 H
被故意消除,rebase 的最终结果将是:
G--H [abandoned]
/
...--E--F--I--J <-- myBranch
\
G' <-- topic (HEAD)
Git 基本上认为提交 H
已经应用。所以它完全放弃了它。
Git 还使用一种叫做 fork point 代码的东西来处理相当复杂的舞蹈。 fork-point 代码的目标是发现 被故意删除的提交 并在变基期间自动删除它们。这段代码通常会做正确的事情,尽管它可能会失败。2 在这种情况下,patch-ID 和 fork-point 代码似乎都没有问题,但是有又一个大的特例,值得单独一节。
2它可能失灵的事实让我认为它不一定是正确的默认设置。这也适用于“已在上游应用”patch-ID 的情况。特别是,交互式 rebase 确实应该在其指令 sheet 中包含这些提交,其中 pre-selected 操作是“drop”,以及关于它们被删除的原因的评论。今天不是这样。
合并
至此,我们画的图很简单。但是假设我们的 topic
分支提交看起来像这样:
I--J
/ \
G--H M--N <-- topic (HEAD)
/ \ /
/ K--L
/
...--E--F--------------O--P <-- myBranch
当我们运行:
git log myBranch..topic
我们将看到提交 N
和 M
,然后按某种顺序提交 I
到 L
,之后显示 I
J
但 randomly-ordered 相对于 K
和 L
,K
显示在 L
之后,但 randomly-ordered 相对于 I
和 J
。然后我们将看到提交 H
,然后是 G
,这就是列表的末尾。
(如果我们添加 --topo-order
,列表的顺序会受到更多限制。rebase 代码在内部添加 --topo-order
。我们仍然不知道是 L
还是 J
将排在第一位,但是一旦我们得到其中一个,我们将在转到另一行之前完成整行。没有 --topo-order
我们可以看到 N
、M
、 L
、J
、K
、I
、H
、G
实例。)
这里是您的问题 rails 有点偏离的地方。 git rebase
命令将 自动删除合并提交 M
完全,原因有二:
- cherry-pick(以及基于旧
git format-patch
/git am
的方法的扩展)不能 复制合并;和 - 标准变基的结果不应该复制合并。
所以你不会有一个pick
命令用于提交M
。要获得一个,您必须手动插入自己的,这是一个错误。要了解原因,让我们看看 Git 如何在没有 pick <hash-of-M>
的情况下使用常规(非 --rebase-merges
)变基来处理此问题。
序列从列出要复制的提交开始。假设它们按此顺序出现,在 git rebase
小心地颠倒它们后 3 同时删除合并:G-H-I-J-K-L-N
.
如果复制阶段一切顺利,结果将是:
I--J
/ \
G--H M--N [abandoned]
/ \ /
/ K--L
/
...--E--F--O--P <-- myBranch
\
G'-H'-I'-J'-K'-L'-N' <-- topic (HEAD)
也就是说,git rebase
已经 将合并变平了 。但是 merge M
的目的是 合并 I-J
和 K-L
分支上的工作 。我们 不需要 合并,因为将 K
复制到 K'
的过程是:
- 对于
H
-vs-K
提交中的每个更改,对从I'
; 中获取的内容进行相同的更改
- 现在将其提交为新提交
K'
。
也就是说,提交 K'
不是基于 H
或 H'
,而是基于 I'
。它已经包含了另一个分支的工作。同样,当 Git 将 L
复制到 L'
时,它会在 已经包含另一个分支的工作 的提交上执行此操作。所以不需要分支。 rebase 操作只是将其完全扁平化。
3请记住,Git 是反向计算的,因此列表总是先出现 N
。我们最后需要 N
,所以 rebase 反转列表。
--rebase-merges
选项
这种扁平化合并的想法并不总是好的。有时效果不是很好。当然,像这样的系列:
I--J
/
...--H
\
K--L
通常两个分支上的变化都相对较少,因此“扁平化分支”很容易并且进展顺利。但是,如果该系列在每个分支中都有大量提交怎么办:
o--o--...(1000 commits)...--o--tip1
/
...--o
\
o--o--....................--o--tip2
在这种情况下,合并两个提示提交的合并可能有很多工作要做。将合并展平是不切实际的。
或者,也许我们只是 喜欢 存在合并。合并代表了一些重要的东西,我们希望未来的代码考古学家看到它。
好吧,“复制”合并确实是不可能的。 Cherry-pick 的 -m
标志不会那样做。如果我们“复制”与 cherry-pick -m
在 扁平化之后的合并:
I--J
/ \
G--H M--N <-- topic
/ \ /
/ K--L
/
...--E--F--O--P <-- myBranch
\
G'-H'-I'-J'-K'-L' <-- HEAD
我们只是 re-introducing 我们已经通过 I-J
或 K-L
获得的更改。要“复制”合并正确,我们必须先形成一个分支:
I--J
/ \
G--H M--N <-- topic
/ \ /
/ K--L
/
...--E--F--O--P <-- myBranch
\
\ I'-J' <-- temp-label-1
\ /
G'-H'
\
K'-L' <-- temp-label-2, HEAD
然后我们必须选择正确的分支 tip 作为 HEAD
提交,然后从字面上 运行 git merge
再次进行M'
:
reset-to temp-label-1
merge temp-label-2
如果合并顺利,我们现在将拥有:
I--J
/ \
G--H M--N <-- topic
/ \ /
/ K--L
/
...--E--F--O--P <-- myBranch
\
\ I'-J' <-- temp-label-1
\ / \
G'-H' M' <-- HEAD
\ /
K'-L' <-- temp-label-2
我们现在可以选择<em>hash-of-N</em>
来制作N'
:
I--J
/ \
G--H M--N <-- topic
/ \ /
/ K--L
/
...--E--F--O--P <-- myBranch
\
\ I'-J' <-- temp-label-1
\ / \
G'-H' M'-N' <-- HEAD
\ /
K'-L' <-- temp-label-2
和然后我们完成了这个花哨的rebase-that-re-does-the-merge,可以移动分支标签topic
并删除任何临时标签:
I--J
/ \
G--H M--N [abandoned]
/ \ /
/ K--L
/
...--E--F--O--P <-- myBranch
\
\ I'-J'
\ / \
G'-H' M'-N' <-- topic (HEAD)
\ /
K'-L'
这就是 git cherry-pick --rebase-merges
所做的。为了达到这个结果,它需要一些额外的命令和插入临时标签的能力。 (请注意,H'
也会有一个临时标签,因为 cherry-picking 操作序列必须在将 K
复制到 K'
之前重置 HEAD
。您将在指令 sheet 中看到所有这些标签和重置,它需要知道何时制作各种标签以及将 HEAD
移动到哪里。)