几天前,我有一个完全线性的分支。然后我创建了一个功能分支,我们称之为master
。我在那个分支上工作,然后将其提交给代码评审,以便合并到feat/feature-a
中。
在对master
进行审查时,我想研究另一个依赖于feat/feature-a
引入的代码的特性。所以我从feat/feature-a
分支创建了一个feat/feature-b
分支。
当我在工作时,feat/feature-a
被合并到master中。所以现在master有了feat/feature-b
引入的代码。我现在想将feat/feature-a
合并到master中,但是我遇到了很多这样的合并冲突:
<<<<<<< HEAD
=======
// Some code that was introduced by feat/feature-b
>>>>>>> c948094... My commit message from feat/feature-b
我的猜测是,因为我将
feat/feature-a
更改带入了我的feat/feature-b
分支,所以我现在试图“复制”那些以合并冲突结尾的更改。我可以手动解决这些问题,但是它们在几十个文件上存在多次,所以如果有一个文件,我想知道一个更好的解决方案。
最佳答案
摘要:使用git rebase --onto <target> <limit>
作为Useless suggested in a comment,如果您有一个真正的合并,这不应该发生。这是我所说的“真正的合并”的意思,还有一个图,如果你画出有问题的提交的图,分支看起来是什么样子的。我们从这样开始:
...--E---H <-- master
\
F--G <-- feat/feature-a
\
I--J <-- feat/feature-b
这里有两个提交(尽管确切的数字无关紧要),它们只在
feat/feature-b
上,这里称为I
和J
;有两个提交在两个功能分支上,叫做F
和G
;还有一个提交只在master
上,叫做H
。(提交E
和更早版本都在所有三个分支上。)假设我们在
master
上进行真正的合并以引入F
和G
。看起来是这样,以图形的形式:...--E---H--K <-- master
\ /
F--G <-- feat/feature-a
\
I--J <-- feat/feature-b
注意,real merge
K
作为其父提交历史指针,同时提交H
(onmaster
)和G
(onfeat/feature-a
)。因此,git后来知道合并J
意味着“从G
开始”。(更准确地说,commitG
将是稍后合并的合并基础。)合并就行了。但这不是以前发生过的事情:相反,无论是谁进行了合并,都使用了所谓的“挤压合并”功能。虽然挤压合并会带来与实际合并相同的更改,但它根本不会产生合并。相反,它只生成一个提交,复制合并后的多个提交的工作。在我们的例子中,它复制了
F
和G
中的工作,因此看起来如下:...--E---H--K <-- master
\
F--G <-- feat/feature-a
\
I--J <-- feat/feature-b
请注意,从
K
到G
没有返回指针。因此,当您转到merge(real或squash-not-real-a-“merge”)
feat/feature-b
时,git认为应该从E
开始。(从技术上讲,E
是合并基础,而不是像前面的实际合并案例中那样,G
)正如您所看到的,这最终会导致合并冲突。(通常它仍然“只是工作”无论如何,但有时在这种情况下,它没有。)也许这对未来是好的,但现在的问题是如何解决它。
在这里您要做的是将排他性的-
feat/feature-b
提交复制到K
之后的新提交。也就是说,我们希望图片看起来像这样: I'-J' <-- feat/feature-b
/
...--E---H--K <-- master
\
F--G <-- feat/feature-a
\
I--J [no longer needed]
最简单的方法是重新设置这些提交的位置,因为重新设置意味着复制。问题是一个简单的
git checkout feat/feature-b; git rebase master
将复制太多提交。解决方案是告诉
git rebase
哪个提交要复制。您可以通过将参数从master
更改为feat/feature-a
(或者commitG
的原始散列id基本上是标识第一个提交不复制的任何内容)。但这告诉git rebase
将它们复制到它们已经存在的位置;所以这不好。因此,解决这个新问题的方法是添加--onto
,这样您就可以将“副本的去向”部分与“要复制的内容”部分分开:git checkout feat/feature-b
git rebase --onto master feat/feature-a
(这假设您仍然有指向commit
feat/feature-a
的名称G
;如果没有,则必须找到其他方法来命名commitG
—您可能希望绘制自己的图和/或仔细查看git log
输出,以找到commit散列)。1“第一”在git风格的反向时尚,即。我们从最新的提交开始,然后将连接向后追溯到较旧的提交。git做任何事情都是向后的,所以在这里向后思考是有帮助的。:-)
关于git - merge 基于另一个功能分支的功能分支,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42210712/