git-merge和git-rebase如何与另一个主题分支分叉的主题分支表现出来?

时间:2015-12-19 01:12:30

标签: git git-merge branching-and-merging git-rebase

让我们假设存储库看起来像这样:

            master
               |
A--B--C--K--L--M
       \
        E-F-G
            |\
            | H-I-J
          topicA  |
                topicB

git merge topicBmaster会做什么?它是否仅适用于提交HIJ?或者从topicA的初始叉点开始的所有提交?

git rebase master topicA会做什么?它会导致这个:

            master
               |
A--B--C--K--L--M
                \
                 E'-F'-G'
                       |\
                       | H'-I'-J'
                     topicA    |
                             topicB

还是更像这样的东西?

            master
               |
A--B--C--K--L--M
       \        \
        \        E'-F'-G'
         \             |
          \          topicA
           \          
            E-F-G-H-I-J
                      |
                    topicB

1 个答案:

答案 0 :(得分:2)

除了解析分支名称以提交ID之外,合并或重新关注任何分支标签所指向的位置。他们只查看提交图。

合并

我认为,git merge的工作方式更容易理解。除了保存默认合并提交消息的分支名称外,git merge只使用git rev-parse来查找提交ID。

对于第一个问题,在分支git merge topicB上给定master时,git会找到三个提交ID:

  • HEAD解析为提交M(分支master上的提示最多提交;这也是您在运行git rev-parse HEAD时看到的提交ID。)
  • topicB解析为提交J(分支topicB上的提示最多提交;这也是您在运行git rev-parse topicB时看到的提交ID。)
  • 这两个提交的合并基础,由提交图确定(仅)。在这种情况下,即提交C

找到合并基础后,git会运行两个git diff:一个在merge-base和HEAD提交之间(看看你的分支“做了什么),另一个在合并之间base和topicB提交(查看“他们的分支”做了什么)。它结合了两组更改,如果没有冲突(或者如果它可以通过git rerere解决它们),则进行一个新的提交,其中两个父项按此顺序 - 当前HEAD提交,以及topicB提交。使新提交像往常一样更新当前分支,以便HEAD现在指向新提交(或更准确地说,HEAD仍然指向mastermaster点到新的提交)。

这个问题:

  

它只适用于提交H,I和J吗?或者来自topicA的初始分支点的所有提交?

暗示了对git的合并算法的基本误解:git不会查看中间提交的任何。它仅查看此处标识的三个提交:MJC。 Git可以像这样“作弊”,因为每个提交在提交的源树内容方面是完全独立的。

底垫

Rebase更复杂(你在上面的第二次猜测中已经做到了,但无论如何我们都要经历它。)

它仍然使用相同的“通过git rev-parse”技巧解析分支名称到ID,但它使用更复杂的git rev-list变体。 git rev-list所做的是在提交图上计算集合操作(​​一旦它实际进入图形本身,再次忽略任何标签)。

鉴于git rebase master topicA,我们(好吧,无论如何:-))首先要检查the rebase documentation,我们发现master被视为&lt; upstream&gt; 参数和topicA被视为&lt; branch&gt; 参数,并且它对最后一个参数的所有操作都是{{1}首先,然后继续进行,就像你没有提供它一样。因此,在精神上,我们可以假设您从git checkout <branch>开始,然后运行git checkout topicA&lt; upstream&gt; 参数为git rebase mastermaster表示分支HEAD,因此它标识提交topicA

过去,在G git rebase之前,更容易确定接下来会发生什么。今天,根据文档,您必须确定是否启用了--fork-point。因为你 提供了一个实际的&lt; upstream&gt; 参数,所以它默认是禁用的:只有在命令行中给出--fork-point时才会启用它。你没有;因此我们不需要深入研究--fork-point的谜团(哇,呀!:-))。所以,这里发生的是rebase本质上运行--fork-point来获取要复制的提交列表。这会列出提交git rev-list master..HEADEF,因为这些是G但不能HEAD可以访问的集合中的提交。

然后,rebase进程在master参数给出的提交中分离HEAD(如果有的话)(没有),或者&lt; upstream&gt; < / em>参数。那是--onto所以这是提交master。从这里开始,rebase基本上只是挑选它之前发现的每个提交,这会为您提交ME'F'。如果所有这些都能正常工作,那么git对rebase的最后一步是将最初的当前分支(G',再次)指向最后一次提交topicA。没有其他标签更改,因此您可以获得最终的图表。