您是对的:将新主题分支合并到V1.1将带来 commit D。(将其合并到V1.0将同时引入C 和 D。)
我只是假设我们正在努力V1.1;这同样适用于V1.0除了有时还会有更多的事情要做C。(而且我不确定你为什么在编辑中更改V1.1为otherbranch,但我会在otherbranch下面继续,因为我做了很多复制粘贴......)
您至少有以下选择:
- 通过“真正的”合并引入 D(
--no-ff如果需要,尽管不是),然后恢复它。
- 用 进行“真正的”合并(就像用
--no-ff)--no-commit,然后反向应用D(用 最简单git revert --no-commit,但你也可以git show D | git apply -R -,例如),并提交结果。
- 做一个“壁球”合并,然后
D像任何一个“真实”合并一样删除。
- 樱桃采摘(带或不带
--no-commit)E、F和G。
这些都导致了一些不同的提交图,除了 squash-merging 和“取消应用”D然后进行一次提交会产生与cherry-picking-through-然后提交结果相同的图(和文件E)。G--no-commit
真正的合并为您提供了实际的合并提交:
V1.0 : B.A--B.B
otherbranch :/ C.A--C.B-----M
/ / /
master: A--B--C--D /
\ /
topicbranch: E--F--G
如果您允许git merge提交(并且它能够自己这样做),则生成的树将包含D自合并基础以来所做的更改otherbranch和topicbranch是 commit C。但是,如果您禁止提交,然后在工作目录中撤回在 commit 中所做的更改D,然后才提交生成的工作目录文件,则提交树M将忽略D.
缺点是,在未来尝试合并master或topicbranch进入otherbranch时,git 会认为更改D在那里(因为它们是,你只是删除了它们)。
对 D 进行单独的还原提交会给出此图:
V1.0 : B.A--B.B
otherbranch :/ C.A--C.B-----M--R
/ / /
master: A--B--C--D /
\ /
topicbranch: E--F--G
R“还原D”变化在哪里。同样,未来的合并master或topicbranch合并otherbranch尝试不会尝试引入来自提交的更改,D因为 git 可以告诉他们已经放入。(这个和前面的场景之间的唯一区别是你取出的事实D是明确的记录为一个单独的提交——除非他们去查看,否则任何人都不会注意到,但他们可能更容易找到他们是否/何时去查看,而不是这只是混合到合并提交M中。)
在 git 中,“壁球合并”提交与常规合并提交完全相同,只是M只有一个父级。Git 像往常一样通过相同的合并机制,它只是没有进行最终提交,也没有进行设置,以便您的手册git commit将进行双亲提交。所以你得到这个图表:
V1.0 : B.A--B.B
otherbranch :/ C.A--C.B-----M
/ /
master: A--B--C--D
\
topicbranch: E--F--G
(调用此提交M是一种谎言,因为它不是合并,而是什么鬼:-))。同样,您可以选择是否在提交D 之前M或之后进行反转,应用相同的推理。但是,在任何一种情况下,因为M不是实际的合并提交,所以稍后在分支中合并的尝试将尝试引入D,因为合并基础没有移动。(当然,它也会尝试再次引入。如果幸运的话,git 将能够告诉他们它们已经在那里,并且合并会自动“思考”类似“哦,好的,已经在那里E,G继续!”。如果没有,您将需要进行一些手动清理。)
最后,挑选提交会复制他们的更改,或者——使用——--no-commit只是应用他们的更改并跳过提交部分。因此,假设您将所有三个组合成一个 commit N,您将得到以下图表:
V1.0 : B.A--B.B
otherbranch :/ C.A--C.B---N
/ /
master: A--B--C--D
\
topicbranch: E--F--G
如果您将它们分开,您会得到E'--F'--G'(这些名称表示您将看到的补丁,如果您git show的提交基本上与您看到的git showof E、F和的补丁匹配G)。如果您将它们组合成一个新的大补丁N,那么看起来与 squash-merge 案例中的N外观非常相似M,只是您不必“取消应用” D,因为您不会带来这些更改。
无论哪种方式,您都必须为 branch 重复整个过程V1.0。
(但请注意:如果您有一个按原样N引入E+F+G的提交,您可以执行其中git cherry-pick之一N。这实际上并不比一个樱桃挑选容易E F G,除非可能要考虑。)