使用Git或TortoiseGit合并一系列修订版

时间:2012-02-20 21:01:05

标签: git tortoisegit

我正在尝试将使用git或TortoiseGit在我的存储库的主分支中进行的更改合并到开发分支中。我知道我可以使用git pullmerge,但这会在开发分支中同时合并太多更改,并且使解决冲突变得更加困难。

如果我使用的是SVN或TortoiseSVN,我可以一次一点地合并来自主干的更改,而不是一次性合并,使用一系列修订进行合并。我可以用git或TortoiseGit做类似的事情吗?也就是说,我可以将一系列修订合并到我的开发分支中,而不是立即合并所有更改吗?

3 个答案:

答案 0 :(得分:6)

摘要

从命令行使用Git,您可以将feature重新定位到master

git rebase master feature

# Now force push the changes to your remote
git push <remote> feature --force

警告 如果您与其他人共享这些提交/分支,请不要随意强制推送(重写)提交/分支 ,因为你会因为旧版本的提交/分支所做的任何更改而导致冲突。可以在(非常)小团队中以这种方式工作,但需要良好的协调。

您还可以使用--onto标记指定范围,其中<start commit>是范围的独占开头:

git rebase --onto master <start commit> feature

最后,cherry-pick实际上可以接受一系列参数。已签出master分支:

# Cherry-pick all commits from `<start commit>`
# exclusive, not included) to feature:
git cherry-pick <start commit>..feature

详细说明

我的最初目标是能够将feature分支与master中所做的更改同步,但我不想仅仅master合并,因为它导致了太多必须立即解决的冲突。我只是希望能够逐步合并这些变化,因此我可以用更小,更易于管理的部分解决冲突。

输入git rebase

实现这一目标的最佳方式实际上是git rebase。实际上,它是完美的。它会做的是以相同的顺序对我在feature 制作这些提交的 所做的所有提交,除了它 在目标分支的最新版本 之上重新发布它们,在我的情况下,它是master

这有两个重要原因:

  1. 这相当于将master合并到feature。为什么?因为feature基本上是在master的最新版本之上重新创建的...所有master的提交现在都存在于feature的历史记录中,包括master中的提交{1}} feature还没有。

  2. Git按顺序重新提交 一次提交 ,所以如果有任何冲突,它们会被引入几个较小的进程中,更易于管理的作品,一次一个,这正是我希望做的!

  3. 这就是它在视觉上的样子(例子改编自official Linux Kernel Git documentation):

          A---B---C feature
         /
    D---E---F---G master
    

    在上面的示例中,提交FGmaster上进行的操作,因为我将feature分开。我想要做的是将这些更改同步到feature

    git rebase master feature
    

    现在我的分支看起来像这样:

                  A'--B'--C' feature
                 /
    D---E---F---G master
         \
          A---B---C (no branch)
    

    AC之前的A'已在C'的最新版本之上通过master重新创建{{1}}。旧的提交仍然存在于Git仓库中,但由于没有引用它们的分支指针,它们最终将被Git垃圾收集。

答案 1 :(得分:4)

是的,你可以这样做。假设您的存储库看起来像这样:

      master
 A---[B]
  \
   \                       feature
    (c1)---(c2)---(...)---(c100)

您想将feature分支合并到master,但那里有很多提交。相反,让我们创建一个新的分支tmp,指向feature之前的提交:

 git branch tmp c2

 A---[B]
  \
   \        tmp               feature
    (c1)---[(c2)]---(...)---(c100)

现在tmp指向c2。现在,我们只需将提交c1...c2合并到master中,而不考虑c3...c100

 git checkout master
 git merge tmp

现在,将tmp移至下一批提交(我们需要-fforce,因为tmp已经存在)。例如,如果我们现在要转移到c6,请使用:

 git branch -f tmp c6

重复此操作,直到您想要合并的所有提交都在。

答案 2 :(得分:2)

注意:John的回答是正确的;这只是基于评论中后续问题的进一步解释 - 我只需要更多空间:)

  

我喜欢不必创建临时分支以在提交中合并的想法,但使用git merge <commit-hash>的问题是它只合并在一个修订版中,而不是它们的范围(正确吗?)。如果我有100个版本要合并,我不是必须100次使用该命令吗?

不,在Git中,历史始终是连通的。因此,如果将提交合并到master中,并且在master的共同祖先和该提交之间进行更多提交,则会完全保留这些提交。与SVN不同,Git保留对先前提交的完全引用(具有无限数量的指针,因此您可以一次合并多个分支)。因此,最后,您将始终看到分支的起始位置,发生了什么,合并之间以及合并回主分支的位置 - 只有名称(或者更确切地说是标签 )不保留分支(除了在自动合并文本中,如果计算^^)。

所以你的历史就像这样:

* -- A -- * ---------- * ----- * -- * -- M [master]
      \
       \
        B1 -- B2 -- B3 -- B4 -- B5 -- B6 -- B7 -- B8 -- B9 [br]

假设您要将B9(分支br上的HEAD提交)合并回M master分支指向的地方#。通过直接合并,您将获得此(* -- A -- * ---------- * ----- * -- * -- M ---------------- # [master] \ / \ / B1 -- B2 -- B3 -- B4 -- B5 -- B6 -- B7 -- B8 -- B9 [br] 是合并提交):

br

因此,即使删除了分支指针* -- A -- * -- * -- * -- * -- M -- #---------- # --------------- # --- # [master] \ / / / / \ / / / / B1 -- B2 ------------ - B3 -- B4 -- B5 -- B6 -- B7 -- B8 -- B9 [br] ,您仍然可以看到在该单独分支上发生的所有提交。

或者,如果您想要在多个步骤中合并,您可以轻松地合并它:

{{1}}

同样,您可以随时回顾整个树,以及在分支上进行的所有单独提交 - 即使您删除了分支(再次删除指针)。

所以也许这个解释也会告诉你,你不一定需要在这么小的步骤中进行合并。在合并期间,您永远不会丢失信息,因为您始终可以回顾所有提交。