繁体   English   中英

合并基于另一个功能分支的功能分支

[英]Merging a feature branch that is based off another feature branch

几天前,我有一个完全线性历史的master分支。 然后我创建了一个功能分支,我们称之为feat/feature-a 我在那个分支上工作,然后将其提交给代码审查以合并到master

虽然正在审查feat/feature-a ,但我还想开发另一个依赖于feat/feature-a引入的代码的feat/feature-a 所以,我创建了一个feat/feature-b从分支feat/feature-a分支。

当我正在研究feat/feature-bfeat/feature-a合并为master。 所以现在master拥有feat/feature-a引入的代码。 我现在想将feat/feature-b合并到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>

正如评论中提到的无用 ,如果你有一个真正的合并,这不应该发生。 这就是我所说的“真正的合并”,以及如果你绘制相关提交图形时分支的外观图。 我们从这样的事情开始:

...--E---H         <-- master
      \
       F--G        <-- feat/feature-a
           \
            I--J   <-- feat/feature-b

这里有两个提交(虽然确切的数字并不重要) 只有feat/feature-b ,在这里称为IJ ; 两个特征分支上有两个提交,称为FG ; 并且有一个提交master ,称为H (提交E和早期的所有三个分支。)

假设我们在master进行真正的合并以引入FG 看起来像这样,以图表形式:

...--E---H--K      <-- master
      \    /
       F--G        <-- feat/feature-a
           \
            I--J   <-- feat/feature-b

注意,真正的合并K作为其父提交历史指针,具有提交H (在master )和G (在feat/feature-a )。 因此,Git后来知道合并J意味着“从G开始”。 (更确切地说,提交G将是后来合并的合并基础 。)

合并就行了。 但这不是之前发生的事情:相反,合并的人使用了所谓的“壁球合并”功能。 虽然squash-merge带来了与实际合并相同的更改 ,但它根本不会产生合并。 相反,它会产生一个单独的提交,它复制了已合并的许多提交的工作。 在我们的例子中,它重复了FG的工作,所以它看起来像这样:

...--E---H--K      <-- master
      \
       F--G        <-- feat/feature-a
           \
            I--J   <-- feat/feature-b

注意缺少从KG的后向指针。

因此,当你去合并(真实壁球 - 不是真正的“合并”) 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 checkout feat/feature-b; git rebase master会复制太多提交。

解决方案是告诉git rebase 提交复制 您可以通过将参数从master更改为feat/feature-a (或提交G的原始哈希ID - 基本上,标识前1个提交复制的任何内容)来执行此操作。 但这告诉git rebase将它们复制到已经存在的位置; 所以这不好。 因此, 问题的解决方案是添加--onto ,它允许您从“要复制的内容”部分拆分“副本去哪里”部分:

git checkout feat/feature-b
git rebase --onto master feat/feature-a

(这假设您仍然有名称feat/feature-a指向提交G ;如果没有,您将必须找到一些其他方式来命名提交G - 您可能希望绘制自己的图形和/或仔细观察git log输出,找到提交哈希)。


以Git风格向后的方式获得1个 “第一”,即。 我们从最近的提交开始,然后按照连接向后提交旧提交。 Git向后做所有事情,所以在这里思考倒退会很有帮助。 :-)

简单模型如下所示:

X  -> MA  <master
  \  /
   A      <feature-a

在这里,feature-a 可能已经通过rebase压缩成单个提交,但合并仍然是真正的合并。 然后,你有

X -> MA -> MB  <master
 \  /     /
  A ---> B     <feature-b

其中feature-b基于feature-a之后的任何压缩,并且正常合并。 这种情况应该可行 ,因为git可以看到AB的祖先并且你已经合并了它。

为了比较,这不会干净利落:

X -> MA -> ...                  <master
|\  /      
| As                            <feature-a
|  |
|  ^--squash------<--
 \                   \
  A0 -> A1 -> ... -> An -> B    <feature-b

你在合并feature-a之前将A0..n压缩为As,但是feature-b是从An分支出来的。

现在git不知道As和A0..n是如何相关的,所以合并和(简单)变基都不会自动运行。 如果你想使用rebase --onto来修复这种情况,请参阅torek的优秀答案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM