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

Chr*_*ite 9 git version-control merge merge-conflict-resolution

几天前,我有master一个完全线性历史的分支.然后我创建了一个功能分支,我们将调用它feat/feature-a.我在那个分支上工作,然后提交它进行代码审查以便合并master.

在进行feat/feature-a审核时,我想开发另一个依赖于引入的代码的功能feat/feature-a.所以我feat/feature-bfeat/feature-a分支机构创建了一个分支.

在我工作的时候feat/feature-b,feat/feature-a合并到了主人.所以现在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
Run Code Online (Sandbox Code Playgroud)

我的猜测是,因为我feat/feature-a对我的feat/feature-b分支进行了更改,我现在正试图"复制"那些以合并冲突结束的更改.

我可以手动解决这些问题,但它们在数十个文件中存在多次,所以如果有的话,我想知道更好的解决方案.

tor*_*rek 16

总结:使用 git rebase --onto <target> <limit>

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

...--E---H         <-- master
      \
       F--G        <-- feat/feature-a
           \
            I--J   <-- feat/feature-b
Run Code Online (Sandbox Code Playgroud)

这里有两个提交(虽然确切的数字并不重要)只有 on feat/feature-b,called IJhere; 两个功能分支上有两个提交,称为FG; 并且有一个提交master,被称为H.(提交E和更早的是在所有三个分支.)

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

...--E---H--K      <-- master
      \    /
       F--G        <-- feat/feature-a
           \
            I--J   <-- feat/feature-b
Run Code Online (Sandbox Code Playgroud)

请注意,实际合并K作为其父提交历史指针,包括commit H(on master)和G(on feat/feature-a).因此,Git后来知道合并J意味着"从...... 开始G".(更确切地说,commit G将是后来合并的合并基础.)

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

...--E---H--K      <-- master
      \
       F--G        <-- feat/feature-a
           \
            I--J   <-- feat/feature-b
Run Code Online (Sandbox Code Playgroud)

注意缺乏从背指针KG.

因此,当你去合并(真实壁球 - 不是真正的"合并")时feat/feature-b,Git认为应该从合并开始E.(从技术上讲,E是合并基础,而不是G早期真正合并的情况.)正如您所看到的,这最终会给您一个合并冲突.(无论如何它通常仍然"正常工作",但有时 - 就像在这种情况下 - 它没有.)

或许这对未来很好,但现在的问题是如何解决它.

你想要做的是 exclusive- feat/feature-bcommits 复制到之后的提交中K.也就是说,我们希望图片看起来像这样:

              I'-J'  <-- feat/feature-b
             /
...--E---H--K        <-- master
      \
       F--G          <-- feat/feature-a
           \
            I--J     [no longer needed]
Run Code Online (Sandbox Code Playgroud)

要做到这一点,最简单的方法就是变基这些提交,因为底垫的副本.问题是简单git checkout feat/feature-b; git rebase master会复制太多提交.

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

git checkout feat/feature-b
git rebase --onto master feat/feature-a
Run Code Online (Sandbox Code Playgroud)

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


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