Git如何合并处理同时提交?

时间:2014-04-29 19:07:49

标签: git github merge commit

给定一个带有两个分支的repo,每个分支都有独立的提交:

Branch  Commits
------  -----------

final:        e-g-i
             /     \
master: a-b-c-d-f-h-?

上图中的字母很重要:即“master”和“final”同时处于开发状态,并且必须保留两个分支中的提交。

将“master”合并为“final”更好(更安全),然后将合并回“master”?或者直接合并到“最终”的“主”中保留之前的提交?

我知道可能会出现合并冲突。我更担心的是,在将“最终”合并到其中后,我们不会丢失任何致力于“掌握”的代码。

3 个答案:

答案 0 :(得分:4)

没有区别。您可以通过执行

来查看git将要合并的更改
git diff master...final

git diff final...master

每个分支都会显示每个分支与其合并基础的累积差异。 git尝试将这两组累积的变化放在一起,并且它没有“分支优先级”的概念。或类似的东西。

git不会丢失提交。 Go back to the basics,追踪其中的链接,并特别注意文档与其他vcs的区别所在。

答案 1 :(得分:4)

  

将“master”合并为“final”更好(更安全),然后将其合并回“master”?或者直接合并到“最终”的“主”中保留之前的提交?

后者:直接合并到“最终”中的“master”保留之前的提交。

git与SVN等其他版本控制系统不同。对于不熟悉的,SVN将分支视为“桶” - 分支/桶是固定的(稳定的),你必须小心移动桶之间的提交。在SVN中,在将“最终”分支“重新集成”(伪合并)回“主”之前,必须将任何最近的“主”提交合并(复制)到“最终”。 “重新整合”有效地将“最终”的尖端复制到“主人”的尖端,有效地用“最终”尖端的精确副本替换“主人”。您可能会丢失“master”中未首先合并(复制)到“final”的任何提交。

像我说的那样,git是不同的。在git中,我喜欢将存储库树(提交)视为稳定,而不是移动的“分支” - 将分支视为挂起提交的小标签/装饰。

我要以不同的方式绘制你的树 - 事实上,我会在提交'i'之前绘制它:

              final
                |
            e - g
          /
a - b - c 
          \
            d - f - h
                    |
                  master

现在让我们提交'i':

                  final
                    |
            e - g - i
          /
a - b - c 
          \
            d - f - h
                    |
                  master

只改变了两件事。 (1)暂时忽略分支“装饰”,我们看到新提交'i'是从其父提交'g'创建的,以及(2)最终的“装饰”从提交'g'移动到'i'。

让我们将final合并为master - 也就是说,让我们更新master,使其包含final的更改:

                  final
                    |
            e - g - i
          /           \
a - b - c              j
          \           /|
            d - f - h  |
                       |
                     master

现在'主'分支装饰移动了。 “最终”的分店装修仍然存在。 'j'提交是由2个父母创建的合并提交:'h'和'i'。

但是如果我们将master合并到final中也是如此 - 也就是说,更新final以便它包含来自master的更改:

                     final
                       |
            e - g - i  |
          /           \|
a - b - c              j
          \           /
            d - f - h
                    |
                  master

现在'最后'被移动,'主'继续存在。请注意,合并是一个真正的合并 - 来自两个分支的更改都在提交'j'中。无论哪个分支合并到哪个'j'都是一样的 - 唯一的区别是哪个分支“装饰”被移动了。 (那些分支“装饰”很容易移动。)

为了完整性,让我们将另一个分支合并回第一个分支(无论是谁合并到谁的第一个 - 只要我们这次合并到另一个方向)。请注意,只有装饰移动 - 不需要新的提交(在git术语中,它是'快进'),因为'j'已经包含来自两个分支的两组更改:

                     final
                       |
            e - g - i  |
          /           \|
a - b - c              j
          \           /|
            d - f - h  |
                       |
                     master

事实上,让我们看几天后的树(我删除了'最终'分支 - 我完成了它):

            e - g - i
          /           \
a - b - c              j - k - l - m
          \           /            |
            d - f - h              |
                                   |
                                 master

好的,你能从树上看出哪个分支最初是'主'而最初是'最终':e-g-i还是d-f-h?这有关系吗?

在git中,merge是真正的合并。没有“存储桶”,您不必像在SVN中那样在“桶”/分支之间移动提交。只有你正在发展的“树”,树枝(“装饰品”)正在为你的地方添加书签。

答案 2 :(得分:1)

合并不是基于时间的,并且合并的结果 1 不依赖于哪个分支"合并来自"哪一个是"合并到"。 2

&#34;合并如何运作的简短形式&#34;这是。你在某些(当前/&#34;我们的&#34; /&#34;合并到#34;)分支,你发出命令git merge <commit-ID> 3 所以git做这样:

  1. 找到&#34;合并基地&#34;当前分支和命名提交。

    在您的图表中,您要么是分支final,其提示是i,要么是分支master,其提示是{ {1}}。如果你在分支机构h上命名提交final,如果你在分支机构h上,则命名为提交master,这样无论哪种方式有问题的两个提交是ih,合并基础是提交i:当你从这两个提交中向后工作时,你找到了共同点。

  2. 运行c(带git diff选项)以将合并基础与当前提示进行比较(例如,-M vs c)。

  3. 运行h(再次使用git diff)将合并基础与其他提交进行比较(例如,-M vs c)。

  4. 在步骤3中使用差异 - 变化&#34;他们&#34;从中删除已在步骤2中找到的任何更改,然后在当前提示中进行所有相同的更改(例如,使i中尚未包含的所有更改,将它们应用于{{1}中的树}})。

  5. 在尝试应用&#34;剩余更改时,会发生冲突。从第4步开始,周围的上下文不匹配(或者,对于文件创建,删除或重命名,没有明显正确的选择)。

    如果没有冲突并且您没有使用h,那么git会提交生成的树,当然这个树会在当前(&#34;我们的&#34;)分支上进行。但无论哪种方式,您都可以获得相同的。 (当然,如果存在冲突,您获得的树取决于如何解决它们。我只是指自动结果。)


    1 更确切地说,结果。 提交取决于哪个分支是&#34;来自&#34; &#34;进入&#34;:特别是,生成的合并提交的第一个父进程是&#34;进入&#34;或者&#34;我们的&#34;分支,第二个父母是&#34;来自&#34;或者&#34;他们的&#34;科。当然,提交本身也放在&#34;进入&#34; /&#34;我们的&#34;现任分支。

    2 无论如何都禁止h--no-commit等选项。

    3 使用--ours -X ours 部分将解析为commit-ID。不过,Git确实保留了合并提交消息的原始参数,因此分支名称通常比原始SHA-1更好。