将先前创建的分支合并到最近创建的分支

时间:2014-08-20 01:38:00

标签: git version-control merge

我不知道这个问题有多常见,但我似乎无法很好地掌握如何优雅地解决这个合并问题。

所以,我从一个主分支开始。在几次提交之后,我创建了一个新的分支(让它称之为包装器分支),然后继续处理它(几乎没有提交)。我很满意,但与此同时,我在master分支上做了一些额外的工作,多次提交。然后我意识到我最好创建一个 develop 分支,并将其作为我的主 dev 分支。所以我再次从master创建了一个分支,并将其命名为 develop 分支。

现在我意识到将我的包装器分支合并到 develop 分支而不是master分支是最好的。我试过了: -

git checkout wrapper;
git rebase develop;

但这似乎不起作用。我仍然没有在开发分支中看到包装器的更改。我该如何解决这个问题?

我还附上了一张图片,以便更好地展示该场景。

Merging a perviously created branch to the recently created branch

2 个答案:

答案 0 :(得分:2)

你可能不想要rebase,如果你这样做,你可能希望它的用法略有不同。

让我首先将其重绘为ASCII文本,以便我可以说明。请注意,这与您的图形相同,除了我不确定从masterdevelop的行中的简短拆分(没有中间节点)应该表示什么。与您的图表一样,圆点(o)表示单独的提交,但我会在下面的讨论中使用*特别标记一个,并使用x标记一个:

o - * ------------------- o - o - o - o   <-- master
      \                                 \
        x - o - o - o   <-- wrapper       o - o - o   <-- develop

现在让我们来看看git rebase做了什么:

git checkout wrapper
git rebase develop

rebase命令确实执行了一系列cherry-pick次操作。每个cherry-pick 复制提交:它会比较&#34;来源&#34;提交其父级以查看更改的内容,然后尝试对目标提交执行相同的更改,并进行新的提交。因此,让我们假装手动挑选x,即第一个wrapper - 仅提交,将其添加到develop的末尾。我们通过获取git diff x*来查看更改内容。然后我们查看分支develop(其最后o个节点)的提示,但不要进入分支(以便develop保持指向它的最后一个o)。我们使用与commit git commit相同的消息进行相同的更改,x结果。假设一切顺利,这给了我们一份副本,让我们称之为x',悬挂在develop的末尾:

o - * ------------------- o - o - o - o   <-- master
      \                                 \
        x - o - o - o   <-- wrapper       o - o - o   <-- develop
                                                    \
                                                      x'

现在我们重复o上剩余的三个wrapper,从左到右工作,扩展我们的匿名分支。这给了我们:

o - * ------------------- o - o - o - o   <-- master
      \                                 \
        x - o - o - o   <-- wrapper       o - o - o   <-- develop
                                                    \
                                                      x'- o'- o'- o'

几乎所有的事情都是这样的:除了一件事,我们已经完成了整个底板。名称wrapper仍然指向旧提交的提示,而不是新副本。所以我们删除旧标签,并指出最新的标签:

o - * ----------- o - o - o - o   <-- master
      \                         \
        x - o - o - o             o - o - o   <-- develop
                                            \
                                              x'- o'- o'- o'   <-- wrapper

那些旧提交仍保留在存储库中,但不再具有(直接)名称:它们已经被放弃了#34;。 (他们仍然有几种方法可以找到它们,但最终会过期,然后git gc可以移除它们并回收空间。但是,默认情况下,你至少有30天的时间让它们回来。)


如果那不是你想要的,你还有什么选择?好吧,你可以将wrapper重新定义到master

                        x'- o'- o'- o'   <-- wrapper
                      /
o - * - o - o - o - o     <-- master
      \               \
        x ...           o - o - o   <-- develop

然后将develop重新绑定到wrapper(这需要更复杂的命令行,告诉rebase只接受三个develop提交:我们可以使用git rebase --onto wrapper master develop此):

                                        o'- o'- o'   <-- develop
                                      /
                        x'- o'- o'- o'   <-- wrapper
                      /
o - * - o - o - o - o     <-- master
      \               \
        x ...           o ...
     [old wrapper]    [old develop]

这可能是你想要的,也可能不是。所以还有一个非常简单的选择:使用git merge,而不是任何这些rebase选项。


git merge的作用最好描述为:

  • 找到两个提交的合并基础。
  • 将merge-base与两个提交中的第一个进行比较,给出&#34;这里发生了什么&#34;。
  • 将merge-base与两个提交中的另一个进行比较,给出&#34;那里发生了什么&#34;。

第一次提交是总是&#34;你现在是#34;。让我们说你在分支develop上,所以这是提示 - 分支develop右边的最后一次提交,其中标签develop指向。另一个提交是您提出的任何提交:如果您说git merge wrapper,则表示分支wrapper的提示。

在这种情况下,合并基础是标记为*的提交,因为它是从wrapper向左移动并从{{​​1}}向左移动的点,两条线首次相遇。

因此,git执行develop git diff*&#34;的提示。这是develop之后*以及master链上所做的一切。

接下来,git执行develop git diff*&#34;提示。wrapper&#34;。这是您在分支wrapper上完成的所有事情,在这种情况下(因为我们正在使用原来的,未重新定位的wrapper来自提交{{1} }})。

现在git尽力结合这两组变化,从当前的提交 1 开始(再次是*的提示)和&# 34;重做&#34; second 差异中的所有更改,只要它们第一差异中已经

换句话说,如果在develop中的某个位置,你修正了一个单词的拼写,但是你在wrappermaster也做了同样的事情,git说:aha ,这个变化已经存在,我可以跳过它。或者,如果您在develop中删除了一堆错误的内容,但是您在wrappermaster中执行了同样的操作,那么git再次看到它已经完成,并跳过它

这一切都令人惊讶地好,因为git只知道&#34;这些行被添加,其他行被删除&#34;和类似的低级别的东西。例如,它不知道某个单词的哪个拼写是正确的。它只是结合了变化。它取决于以确保git能够做到这一点。 (对于cherry-pick / rebase也是如此,因此这两种方法都没有优势。)

在任何情况下,如果git成功组合了两个差异,它会从结果文件中进行新的提交。关于这个新提交的特殊之处在于它有两个父项,而不只是一个:合并提交&#34;指回&#34;当前提交(在这种情况下为develop的旧提示),以及合并提交(develop的提示)。与任何新提交一样,您正在进行的分支也会指向新提交。所以这现在看起来像:

wrapper

合并操作 - 组合差异 - 有效地带来了分支o - * ------------------- o - o - o - o <-- master \ \ x - o - o - o <-- wrapper o - o - o - M <-- develop \______________________________/ 的所有更改,从而可以安全地删除分支标签本身:

wrapper

(除非您想要挂在标签上,以便例如对其进行更多提交)。

(当然,在差异合并期间可能会出现问题; git branch -d wrapper 可能会停止并需要您手动解决冲突。如果是这样,您必须执行最终git merge以创建合并{ {1}},或使用git commit停止尝试合并并将其重新置于原始状态。)


1 实际上,M以工作树中的任何内容开头。但是,文档建议确保工作树是干净的(git merge --abort没有显示任何修改),因为如果合并失败,则返回原始状态,包括已修改但未提交的任何内容,可能很棘手。

答案 1 :(得分:1)

你只需要签出开发,并在该分支内部将另一个合并到其中。 请记住,通常你正在修改的分支是你要修改的分支。

git checkout develop

然后

git merge wrapper