git:合并两个分支:什么方向?

时间:2010-02-28 12:59:38

标签: git merge git-merge

我们有以下情况:

             A --- B --- C --- ... --- iphone
           /
  ... --- last-working --- ... --- master

在上次工作和iPhone之间,进行了3​​2次提交。在last-working和master之间,提交了许多

我现在想要的是一个新分支,我将iphone和当前主人合并在一起。稍后,这应该合并到主人。

首先,我打算这样做:

git checkout iphone -b iphone31
git merge master

但后来我想,如果做得更好:

git checkout master -b iphone31
git merge iphone

现在我在想。 结果会有什么不同?合并会有不同的行为吗?

我已经尝试了两种方式,正如我所料,我遇到了很多冲突,因为与主人相比,iphone真的很老了。现在我想知道合并它们的最简单方法。

甚至可能从master开始并将每个iphone的提交合并到它中会更容易?喜欢这样做:

git checkout master -b iphone31
git merge A
git merge B
git merge C
...
git merge iphone

最后,当这个合并完成时(即所有冲突都已解决且工作正常),我想这样做:

git checkout master
git merge iphone31

5 个答案:

答案 0 :(得分:42)

关于替代方案

git checkout iphone -b iphone31
git merge master

git checkout master -b iphone31
git merge iphone
他们会有同样的轻松或困难,就像争论一杯是半满或半空。

版本树感知

我们如何看待版本树在某种程度上只是我们的任意感知。 假设我们有一个如下所示的版本树:

    A----------+
    |          |
    |          |
   \_/        \_/
    B          X
    |          |
    |          |
   \_/        \_/
    C          Y
    |
    |
   \_/
    D
    |
    |
   \_/
    E

让我们说我们想要从Y签出一个新版本Z. 基于从C到E的变化,但不包括从中做出的更改 A到C.

“哦,这很难,因为没有共同的起点。” 好吧不是真的。如果我们只是放置不同的对象 在像这样的图形布局

      /
    C+---------+
    | \        |
    |          |
   \_/         |
    D          B
    |         / \
    |          |
   \_/         |
    E          A
               |
               |
              \_/
               X
               |
               |
              \_/
               Y

现在情况开始变得很有希望了。请注意,我没有 改变了这里的任何关系,箭头都指向同样的方式 在上一张图片和版本A仍然是共同的基础。 只更改了布局。

但现在想象一个不同的树

是微不足道的
    C'---------+
    |          |
    |          |
   \_/        \_/
    D          B'
    |          |
    |          |
   \_/        \_/
    E          A
               |
               |
              \_/
               X
               |
               |
              \_/
               Y

任务只是正常合并版本E.

所以你可以合并你想要的任何东西,唯一影响的东西 容易或困难是在哪里之间完成的变化的总和 您选择作为起点或公共基地以及合并到的位置。 您不仅限于使用自然起点 版本工具建议。

对于某些版本控制系统/工具,这可能并不简单, 但如果一切都失败了 没有什么可以阻止你手动执行此操作 检出版本C并将文件另存为file1, 检出版本E并将文件另存为file2, 检出版本Y并将文件另存为file3, 并运行kdiff3 -o merge_result file1 file2 file3

答案

现在针对您的具体情况,很难准确说出具体情况 战略会产生最少的问题,但是 如果有很多变化会造成某种冲突呢 可能更容易拆分和合并较小的部分。

我的建议是那样的 因为last-working和iphone之间有32次提交, 例如,你可以通过分支master然后开始 在前16次提交中合并。如果结果是 太麻烦了,还原并尝试合并8个第一次提交。 等等。在最坏的情况下,您最终会逐个合并32个提交中的每个提交, 但它可能比处理所有的更容易 在一次合并操作中积累的冲突(和 在这种情况下,您正在使用真正分歧的代码库。)

提示:

在纸上画一个版本树并用箭头记下你想要的东西 合并。如果你分开这个过程就会完成它们的工作 分几个步骤。这将使您更清楚地了解您想要的内容 实现,到目前为止你做了什么,剩下什么。

我真的可以推荐KDiff3,它是一个出色的差异/合并工具。

答案 1 :(得分:8)

有区别。

在合并期间始终检查目标分支(即,如果将A合并到B,结帐B)。

人们经常说合并方向并不重要,但这是错误的。虽然无论合并方向如何,结果内容都是相同的,但有几个方面是不同的:

  1. 根据方向,生成的合并提交中列出的差异会有所不同。
  2. 大多数分支可视化工具将使用合并方向决定哪个分支是“主要”。
  3. 详细说明,想象一下这个夸张的例子:

    • 您在1000次提交后从MASTER分支出来,并将其命名为DEVELOP(或者在跟踪分支方案中,您还没有获取相当长的时间)。
    • 您在DEVELOP中添加一个提交。您知道此更改没有冲突。
    • 您想将更改推送到MASTER。
    • 您错误地将MASTER 合并到 DEVELOP(即在合并期间检出了DEVELOP)。然后,您将DEVELOP推送为新的MASTER。
    • 生成的合并提交中的差异将显示MASTER中发生的所有1000次提交,因为DEVELOP是参考点。

    这些数据不仅无用,而且很难读懂正在发生的事情。大多数可视化工具都会让你看起来像你的开发系统一直是主要的,有1000个提交。

    我的建议如下:在合并期间始终检查目标分支(即,如果将A合并到B,结帐B)。

    • 如果您正在处理并行分支并希望定期从主分支引入更改,请检出并行分支。差异是有意义的 - 您将看到主分支w.r.t中的更改已完成到您的分支。
    • 当您完成并行工作并希望将更改合并到主分支时,请检查主分支并与并行分支合并。差异再次有意义 - 它将显示你的并行变化是什么w.r.t到主分支。

    在我看来,日志的可读性很重要。

答案 2 :(得分:6)

最好的方法实际上取决于其他人是否拥有代码的远程副本。如果 master 分支仅在本地计算机上,则可以使用rebase命令以交互方式将功能从功能分支应用到master:

git checkout master -b iphone-merge-branch
git rebase -i iphone

请注意,这会改变新 iphone-merge-branch 分支的提交历史记录,这可能会导致其他人尝试将更改提取到结帐时出现问题。相比之下,merge命令将更改应用为新提交,这在协作时更安全,因为它不会影响分支历史记录。有关使用rebase的一些有用提示,请参阅this article

如果您需要保持提交历史记录同步,则最好执行合并。您可以使用 git mergetool 使用可视化差异工具逐个交互式修复冲突(有关此问题的教程可以是found here):

git checkout master -b iphone-merge-branch
git merge iphone
git mergetool -t kdiff3

如果您想要对流程进行绝对控制,第三个选项是使用 git cherry-pick 。您可以使用gitk(或您最喜欢的历史查看器)查看iphone分支中的提交哈希值,记下它们,然后将它们单独挑选到合并分支中 - 随时修复冲突。对此过程的解释可以是found here。这个过程将是最慢的,但如果其他方法不能解决,可能是最好的后备选项:

gitk iphone
<note down the 35 commit SHA hashes in this branch>
git checkout master -b iphone-merge-branch
git cherry-pick b50788b
git cherry-pick g614590
...

答案 3 :(得分:2)

你说:

  

与主人相比,iphone分支很老了

你真的想把它们合并成一个新的分支吗?

master和iphone分支的目的现在已经非常不同了(因为iphone非常老)。合并iphone与祖先大师的新分支会更好吗?想一想。

我强烈建议您阅读Fun with merges and purposes of branches

如果您仍然觉得想要合并iphone和master,那么阅读那篇文章后,@ seanhodges会解释如何正确处理冲突。

答案 4 :(得分:1)

您可能希望在试验之前对您的作品进行本地备份,这样您就可以重新启动,如果您不再了解发生了什么。

制作工作的备份分支,以便在变基期间不要丢失它,如果你想保留它以供参考。

git checkout iphone -b iphone_backup

从主人

创建一个新分支
git checkout master -b iphone31

然后在它上面重新加注。

git rebase -i --onto iphone31 iphone
对于每次应用一次提交的rebase,上面的Sean是正确的。但是不要担心你重新加入的分支上的现有提交 - 它们不会被更改。 Rebase将新的(改编的)提交放在它们之上。虽然一次完成一次提交,但您可以更好地控制冲突。重要的是,你必须在主人之上改变你的工作而不是反过来,所以主人的历史不会改变。

或者,你只能做

git rebase -i master iphone

如果你不关心备份iphone分支。查看rebase文档以获取详细信息和备选方案http://git-scm.com/docs/git-rebase