“壁球合并”根本不是合并,所以这张图在几个重要方面是错误的:
D--E--F--H'--I--J--K (mybranch)
/ \
A--B--C--G--H--L--M--N--O (master)
...但幸运的是,它为我提供了我们需要知道的一切,让我知道如何尽可能轻松地处理这个问题。
首先,您说这H'
是从master合并到 mybranch
. \
可能应该是(我们希望“/
稍后”提交位于“早期”提交的右侧),但它实际上根本不应该表示合并,并且可能应该以不同的方式命名。
所以,这就是我将如何重新绘制图形片段(无论如何我都可以正确地管理 -在使用它之前,您需要仔细检查所有这些):
D--E--F----BCGH'--I--J--K <-- mybranch
/
A--B--C--G--H----L--M--N--O <-- master
此处命名的提交是提交BCGH'
的壁球“合并” 1B--C--G--H
,您已将其称为H'
。它是原始四个提交中所有工作的副本。
使用变基,省略壁球
您现在可能想要mybranch
基于master
. 这可能是最简单和最好的方法,尽管它确实意味着“重写历史”(假装您在 commit 之后开始工作O
)。为此,请使用交互式变基:
$ git checkout mybranch
$ git rebase -i master
然后专门BCGH'
从pick
列表中删除提交。这将要求 Git 挑选每个提交D
, E
, F
, I
, J
, 和K
(除非您还重新排序这些pick
行):
D--E--F----BCGH'--I--J--K [will be abandoned]
/
A--B--C--G--H----L--M--N--O <-- master
\
D'-E'-F'-I'-J'-K' <-- mybranch
使用合并,让 Git 完成工作
或者,如果您真的想合并,请创建一个新的(但临时的)分支,从 commit 开始A
,您可以在其中挑选相同的六个提交:
$ git checkout -b tempbranch mybranch~7 # this should start from A
$ git cherry-pick mybranch~7..mybranch~4 # pick D, E, and F
$ git cherry-pick mybranch~3..mybranch # pick I, J, and K
D--E--F----BCGH'--I--J--K <-- mybranch
/
A--B--C--G--H----L--M--N--O <-- master
\
D'--E'--F'--I'--J'--K' <-- tempbranch
请注意,tempbranch
它没有BCGH'
来自 的提交的副本,master
否则与我们重新定位到 master 的尖端时得到的基本相同。2 制作此特定副本的目的是获取与此新提交关联的源代码树K'
,因为现在我们可以运行:
$ git merge master
进行新的(尽管是临时的)合并提交T
,不受以下因素的干扰BCGH'
:
D--E--F----BCGH'--I--J--K <-- mybranch
/
A--B--C--G--H----L--M--N--O <-- master
\ \
D'--E'--F'--I'--J'--K'----T <-- tempbranch
如果我们从into进行真正的合并,这个新的合并提交T
具有我们想要获得的源代码树。因此,现在让我们开始该合并,由于 commit 导致合并冲突失败:master
mybranch
BCGH'
$ git checkout mybranch
$ git merge master
这会因冲突而失败,所以现在让我们通过丢弃整个合并结果并将其替换为临时合并的树来解决所有冲突T
。请注意,您必须在此处的 git 树的顶层,以便.
引用所有内容:
$ git rm -rf .
$ git checkout tempbranch -- .
第一步丢弃整个工作树(和索引/暂存区内容),第二步从最尖端的提交(tempbranch
即 commit )创建一个全新的工作树(和索引内容) T
。
现在您可以提交结果了(尽管首先仔细检查它是明智的——当然,tempbranch
您甚至可以在到达这里之前在分支上执行此操作)。提交后,您将拥有:
D--E--F----BCGH'--I--J--K-P <-- mybranch
/ /
A--B--C--G--H----L--M--N--O <-- master
\ \
D'--E'--F'--I'--J'--K'----T <-- tempbranch
哪里P
是正确的合并,使用来自T
. 现在可以安全地tempbranch
完全删除:
$ git branch -D tempbranch
剩下的就是 Git 使用省略了 commit 的临时分支进行的合并BCGH'
。
更多选项,以及关于如何以及为什么做任何事情的注释
还有其他方法可以解决这个问题,例如从 commit 开始创建一个新分支F
,从这个新分支中进行真正的合并master
(而不是壁球“合并”),然后挑选樱桃并I
从.K
master
与任何其他方法相比,使用任何一种方法的唯一充分理由是:
- 如果你更喜欢这种方法;
- 如果对您来说更容易;和/或
- 如果其他人有其中的一些提交,而您不想让其他人做更多的工作。
最后,提交给你两件事:状态(工作树,加上提交作者、日期和日志消息等元数据)和历史记录(在此提交之前有哪些提交?)。这个想法是根据需要进行尽可能多的提交,以提供足够的状态和历史来有意义并启用合作开发,而不会提供太多的状态和历史来模糊意义和禁用合作开发。
1 “合并”周围的引号是因为,壁球合并不是合并。合并是具有两个或多个父级的提交,并且这些壁球“合并”提交不记录第二个父级:它们丢弃关键信息,这就是为什么如果您对它们不太小心,它们会变得如此麻烦的原因。
2我在这里的意思是,在提交方面,如果我们要变基,我们想要的结果是一样的。当然,就相关的源代码树而言,它是不同的,因为它不包含在B
、C
、G
、H
、L
、M
、N
或中完成的任何工作O
。O
从完成所有工作的源树开始的变基。