如何将所有更改从一个分支合并到另一个分支

时间:2017-04-11 12:39:29

标签: git merge

(道歉,如果这是一个骗局 - 我在搜索中出现的答案似乎与我的确切情况无关,和/或建议的动作都没有解决我的问题问题)。

我的Git仓库中有以下(近似)结构。我已修补缺陷并将该修补程序合并到Production分支中。

A--B--C--D--E--F--G               [Master]
      |     |
      |     \--K--L--M            [Release Candidate]
      |
      \--H--I--J--N--O--P         [Production]
               |
               \--N--O--P         [Patch]

现在,我需要将完全相同的修补程序(提交NOP)应用于MasterRelease Candidate分支,自从Production分支开始以来已经移动了(批次),但是我所影响的文件没有变化。然而,HIJ需要来进入这些分支。

有没有办法在不需要使用提交ID进行操作的情况下执行此操作?

理想情况下,我正在寻找可以通过其分支名称引用Patch的内容。 (毕竟,Git知道Patch分支上有什么变化,不是吗?我不应该再告诉它了!)

P.S。我尝试了git cherry-pick Patch因为这似乎是一个明显的猜测,但这只是提交P

编辑:当我尝试重新绑定时,来自另一个问题的建议解决方案导致大量冲突,即使我知道想要合并的更改也不会与{{ 1}}和Master分支。

请注意,即使图中的每个分支上只显示了一些提交,但除了Production之外,每个分支上实际上有几十个(可能是数百个,我没有计算它们),这只有三次(这次)。理想情况下,当Patch分支也可能有大量提交时,我理想地寻找一种情况。

为什么告诉git"使用自分支以来对该分支进行的提交是如此困难?#/ p>

2 个答案:

答案 0 :(得分:1)

如果你的补丁确实是3次提交:git cherry-pick N O P会做

否则,你可以rebase摘录一个分支:

# starting from branch Patch

# create a fresh branch :
$ git checkout -b wip/patch-on-master

# tell rebase to rebase 'commits from (but not including) J' :
$ git rebase --onto master J wip/patch-on-master

答案 1 :(得分:1)

更新 - 正如torek指出的那样,我对运行多个rebase的后果过于乐观了。建议的程序相应调整......

在选择解决方案时需要考虑的一些事情可能很容易被忽视:

是否已经与其他开发者共享了这些内容?共享的内容越少,重写历史记录的灵活性就越大。我不是历史重写的最大倡导者 - 我通常不会仅仅为了使拓扑更加线性 - 但在这样的情况下,具有灵活性可以使您的未来生活更轻松。 (如果你有一个团队可以协调到#34;切换到#34;到一个重写的回购,那么你可以做任何重写的重写;但根据经验,我们假设你可以' ; t重写你已经分享的丢弃提交。)

如果你有多个提交在不同的分支上执行相同的更改会导致多少麻烦?如果这些分支最终会合并,那么这种事情会导致不必要的合并冲突。因此,您可能希望支持使用单个提交进行任何给定更改的解决方案

您希望最终使用哪种分支拓扑?有些人真的不喜欢在历史记录中看到合并。不同的解决方案将产生更多或更少的合并提交。

好的,那又怎样呢?那么,你可能不得不在这三个问题上做出妥协。如果您不想进行任何合并,并且只想对任何给定的更改进行一次提交,那么您必须重写几乎所有内容。您只需重写Patch(以及PatchProduction的应用程序),但需要进行一些合并。如果连Patch都不能被重写,那就是另一种方式(但最后会有一些合并和一些有点愚蠢的分支拓扑)。或者您可以在没有重写的情况下获得不合并的情况(技术性除外),但代表补丁的多组提交。让我们来看看一些选项...

在您将patch合并到production之前,首先让我们回复。我之所以这样做主要是因为我并不清楚合并是如何失败的,所以我从一个更清楚的"开始?#34;州。如果需要,你可以实际做到这一点

git checkout Production
git reset --hard J

在一般情况下,J是提交ID;但如果它是非ff合并,你可以使用HEAD^

A--B--C--D--E--F--G <--(Master)
       \     \
        \     K--L--M <--(Release Candidate)
         \
          H--I--J <--(Production)
                 \
                  N--O--P <--(Patch)

无论如何,如果我们要将NOP应用于所有这些分支而不重复更改且没有合并,那么首先要做的是do将它们变为C。 (您可能希望标记C;当然,设置标记将需要一些提交ID使用...)

git rebase --onto C Production Patch

        N'--O'--P' <--(Patch)
       /
A--B--C--D--E--F--G <--(Master)
       \     \
        \     K--L--M <--(Release Candidate)
         \
          H--I--J <--(Production)

请注意&#34; prime&#34;新补丁的提交标记;这些是重写的提交而不等于原始文件,但它们包含完全相同的更改(假设Patch真正独立于Production上的任何内容。)

如果您不担心重写,那么您可以将其他分支重新绑定到Patch。这并不像我想的那么容易,因为一些提交由多个分支共享,并且多个rebase操作会创建多个重写(由于时间戳)。所以

git rebase --onto Patch Patch master
git rebase --onto Patch Patch rc
git rebase --onto Patch Patch Production

有效。相反,你必须做

git rebase --onto Patch Patch master
git rebase --onto Patch Patch Production

然后识别E&#39;,然后

git rebase --onto E' Master rc

或者,您可以在合并(可能是章鱼合并)您想要重新分支的分支的地方玩游戏,然后使用--preserve-merges选项对该新合并进行单一变更。它可以排序,但是你可能会有一些手动工作来移动你原来的分支引用。

好吧,如果你做其中一件事,你会得到

              (Patch)
                 |
A--B--C--N'--O'--P'--D'--E'--F'--G' <--(Master)
                  \       \
                   \       K'--L'--M' <--(Release Candidate)
                    \
                     H'--I'--J' <--(Production)

当然,现在你已经改写了几乎所有东西。假设Patch是唯一可以安全重写的东西......所以我们回到

        N'--O'--P' <--(Patch)
       /
A--B--C--D--E--F--G <--(Master)
       \     \
        \     K--L--M <--(Release Candidate)
         \
          H--I--J <--(Production)

然后

git checkout Master
git merge Patch
git checkout rc
git merge Patch
git checkout Production
git merge Patch

请注意,与将原始合并投放到生产位置相同。通过返回并重新合并重写的Patch,您可以保留&#34;每次更改一次提交&#34;情况。

但也许你不能重写Patch - 或者更有可能的是,你可以重写PatchProduction的合并。不幸的是,已经完成合并可能已经取消了一些选择。在这种情况下,你必须做出更多妥协,老实说,不要让多组提交代表Patch变得非常困难。你可能只需要考虑其他人已经阐明的答案。

作为最后一个沟通,你可能会想到,嗯,我可以查看Patch并使用revert添加到其中,提交撤消H,{{1} }和I,然后我有一个补丁我可以合并到JMaster&#34; ......好吧,你可以 - 我认为 - 并且它会解决立即问题,它会产生更大的问题,因为现在Release Candidate(以及H), ~H(以及I)和~I(以及J)已经存在于这些分支的历史记录中,因此未来的合并形式生产将不会&# 39; t自动重新引入这些变化。因此,如果您希望~J .. H合并的任何未来状态,则最后一个选项不太好。