使用git merge,如何将错误修复合并到多个长期分支中?

时间:2015-01-30 21:31:34

标签: git merge

最近在工作中,我们已经从使用SVN切换到使用git。我们必须维护我们软件的多个版本,之前我们将它们设置为分支。因此,在使用git svn clone之后,我们最终得到了4个分支:master,5.0,5.1和5.2。

注意:我们使用master作为我们的开发分支。 5.0,5.1和5.2都是来自master的分支,并用作生产分支。

几天过去了,很多变化已经掌握了。在5.2中发现了一个错误,我们想要修复它。我们尝试了Merging one change to multiple branches in Git的解决方案并且运气不错。我们总是可以轻松地合并回主人,但每当我们合并回5.2时,我们就会遇到一堆冲突。我们所看到的一切都显示了这个过程(为bugfix创建一个新的分支并将其合并回开发和生产),这表明它应该如下所示:

(master)$ git checkout -b bugfix
# fixed bug and committed

(bugfix)$ git checkout master
(master)$ git merge bugfix
# successful merge

(master)$ git checkout 5.2
(5.2)$ git merge bugfix
# successful merge

然而,对于我们来说,当我们到达最后一行git merge bugfix时,我们会遇到大量冲突。我们甚至没有触及错误修正的文件冲突。我们做错了什么?

注意:我们也尝试通过启动5.2中的bugfix分支来完成此过程。然后将错误修复程序合并到5.2中很容易,但将错误修复程序合并到主文件中会产生冲突。

显示该过程的其他地方:

3 个答案:

答案 0 :(得分:12)

几年前,我们将一个非常大的项目从SVN转移到了git。这是我一直提出的问题。

首先(这一点不是你问题的答案,它是对“你为什么问这个问题?”这个问题的答案,),请阅读:   http://nvie.com/posts/a-successful-git-branching-model/ 并接受它可能是正确的,这意味着放弃你的一些SVN心态。这对我来说是最难的。

现在你已经完成了,我会回答这个问题。

最佳途径是:

  • 确保您始终可以将任何较旧的分支合并到任何较新的分支中,而不会影响较新的分支

  • 执行您需要修复的任何错误修复,修复您想要修复的最旧的分支。然后将其顺序合并到新分支中,随时修复合并冲突。

执行第二项操作会使第一项始终有效(如果您考虑一下)。

这种技术可以扩展到不同年龄段的许多分支,只要任何给定分支中的变更集始终包含 all 来自所有旧分支的变更集。

然而,上面的第二个要点假设一个理想的世界:

  • 你确切知道哪个是你在进行错误修复时执行错误修复所需的最旧的分支(即没有人来找你并说“嘿,我们需要修复bug向后移动,这也给客户X带来了问题。)

  • 每个分支的错误修复总是相同的(例如,您为旧分支执行创可贴最小熵修复)。

您可以使用git cherry-pick选择旧分支中的提交来解决第一个问题。但后来(这是重要的一点)将修复程序合并到较新的分支(即使它已经存在)。你可以谨慎而谨慎地使用:

git checkout newer
git merge older   # check it's all merged up
git checkout older
git cherry-pick xxxxx
... fix up cherry pick, check it works ...
git checkout newer
git merge -s ours older

请注意,这标志着合并但有效忽略旧分支中已更改的所有内容,因此在更改之前检查它是否合并非常重要。

第二种情况可以类似地处理。将实际修复应用于newer。检查older已合并到newer,然后将您的绑定应用于older,然后使用git merge -s ours older

答案 1 :(得分:2)

git merge是共同基础以来的所有变化。如果你想记录只有一个变化到多个历史的合并,你必须使它成为所有历史中一些祖先内容的唯一变化,如下所示:

git checkout -b bugfix `git merge-base 5.0 5.1 5.2 master`
# so now bugfix is an ancestor of all of the above

# fix the bug here, then:
git commit -m 'bug fixed'

git checkout 5.0; git merge bugfix     # bugfix has just the one change
git checkout 5.1; git merge bugfix
git checkout 5.2; git merge bugfix
git checkout master; git merge bugfix

最好一点一点地将bug修正为首先引入bug的提交,但如果它已经被删除,那么它并不总是能够实现干净的合并。足够长的时间。

答案 2 :(得分:1)

我们的问题来自git svn clone。虽然它确实给了我们一个git repo并且它似乎给了我们正确的分支,但这些分支实际上并没有像我们预期的那样来自master。这是相当令人困惑的,因为当我们查看日志时,我们可以看到分支创建之前的日志在两个分支上都具有相同的哈希值。实际上,唯一能让我们知道发生这种情况的事情就是从TortoiseGit查看 Revision Graph 。我没有屏幕截图,但这基本上就是图表的样子:

    5.2          master
 origin/5.2   origin/master
      `-.       .-'
         `-. .-'
        a3f2d6205

因此我们可以看到两个分支都来自根提交a3f2d6205。我们需要做到这一点,以便5.2源于主人。以下是我们采取的步骤,以便让我们在那里。

(master)$ git reset --hard 0b73ab0
(master)$ git branch 5.2.new
(master)$ git merge --no-ff --log origin/master
(master)$ git push origin master
(master)$ git checkout 5.2.new
(5.2.new)$ git merge -Xtheirs --log origin/5.2
(5.2.new)$ git push -u origin 5.2.new
(5.2.new)$ git push origin --delete 5.2

# hopped on the "central" git repo
(master)$ git branch -m 5.2.new 5.2

# run these commands for all of the developers repos
(master)$ git pull
(master)$ git remote prune origin
  • (master)$ git reset --hard 0b73ab0 - 0b73ab0是5.2分支的提交。
  • (master)$ git branch 5.2.new - 创建一个源于此点的新分支
  • (master)$ git merge --no-ff --log origin/master - 我们需要让主人回到原来的位置,但无论出于何种原因,如果它进行了快速合并,它会弄乱词干,所以要标记它--no-ff以确保这并没有发生。
  • (master)$ git push origin master - 将我们的新主人推送到服务器
  • (master)$ git checkout 5.2.new - 结帐5.2.new
  • (5.2.new)$ git merge -Xtheirs --log origin/5.2 - 我们需要将5.2回到原来的位置。使用-Xtheirs,以便我们不必处理冲突。
  • (5.2.new)$ git push -u origin 5.2.new - 将此分支推送到" central" git repo。
  • (5.2.new)$ git push origin --delete 5.2 - 删除dumb 5.2分支。

跳上"中心" git repo。

  • (master)$ git branch -m 5.2.new 5.2 - 将5.2.new分支重命名为5.2。

确保每个人都是最新的:

  • (master)$ git pull - 提取最新信息
  • (master)$ git remote prune origin - 删除任何过时的分支

最后说完并完成后,修订图应该类似于:

             5.2
         origin/5.2
          .-'
       .-'
    master
origin/master
      |
      |
  a3f2d6205