我有一个从trunk开始的分支a和一个从a开始的分支B。定期进行从主干到a的合并,然后还执行从a到B的合并。当我想将A和B合并到中继时,我想遵循以下方式:
- 将合并从B重新整合到A
- 将合并从A重新整合到主干
正确吗?或者它会给mergeinfo带来问题或其他问题?在这种情况下,最佳做法是什么?
Subversion因合并不好而受到(有时是不公平的)批评。事实上,Subversion非常擅长合并。要了解您需要做什么,您需要了解Subversion是如何进行合并的。
Subversion通常(我稍后会解释)会进行标准的3向合并。它将合并的两个文件与共享的最后一个祖先文件进行比较。这样,它就可以判断文件中的哪些更改来自它所在的分支,以及哪些更改来自另一个分支。
因为Branch"B";来自Branch";A";它来自树干。您可以从主干到B或从主干到A进行合并。这些合并应该很好。如果您正在将一组特定的更改从枯萎的分支B或分支a合并到主干或另一个分支,那么一切都应该正常工作。
现在,我说(有点)做一个标准的3向合并。编写子版本是为了允许您指定在一个分支中所做的特定更改集,以便与另一个分支合并。合并时,Subversion不会查看正在合并的文件,而是从基础文件(最后一个公共祖先)开始,然后应用正在考虑进行合并的更改。在这种情况下,当您确切地指定要合并的内容时,Subversion在合并方面做得很好。
因此,如果您指定Branch"A";有一个特定的更改,并且您想将此更改合并到Branch"B";或者对于主干,Subversion在合并方面做得很好。
在Subversion 1.5中,当Subversion开始跟踪以前合并到分支或主干中的存储库修订时,情况开始发生变化。这使我无法将以前合并到分支中的更改合并,但也让我变得懒惰。懒惰没有错。我高度赞同。
想象一下,我在修订版100中从主干中创建了一个功能分支。我在第100次修订时做了这个分支。假设这是我的回购中所做的修订列表:
- 分支:103 105 108
- 主干:101 102 104 105 106 107
当我从主干合并到我的功能分支,并且我没有指定要合并的修订版时,Subversion会帮我挑选。它知道最后一个共同的祖先是修订版100。然后,它查看并看到修订版101、102、104、105、106和107主干上的更改尚未应用于我的分支。然后它挑选这些特定的更改并将它们合并到我的分支中。
- 分支:103 105 108109
- 主干:101 102 104 105 106 107
修订版109是我合并的结果。为了跟踪这些更改,Subversion在Revision 109中添加了一个svn:mergeinfo
属性,该属性表示trunk:101-107已合并到分支上。让我们做更多的工作:
- 分支:103 105 108109110 111
- 主干:101 102 104 105 106 107 112 113
我想再次从主干合并到分支。如果我不懒惰的话,我会指定我希望修订112和113合并到我的分支中。然而,由于懒惰,我让Subversion来做这项工作。Subversion从svn:mergeinfo
中看到,从101到107的所有主干修订都已经合并到我的分支中。因此,Subversion为我选择了修订版112和113:
- 分支:103 105 108109110 111114
- 主干:101 102 104 105 106 107 112 113
Subversion创建修订版114,并设置svn:mergeinfo
,表示主干上从修订版101到修订版113的所有更改都已合并到我的分支上。
现在,我已经完成了我的功能,我想将我在分支上所做的所有更改合并到主干上。如果我不是一个懒惰的流浪汉,我会指定我希望修订版103、105、108、110和111合并到我的主干上。如果我这样做了,绝对没有问题。Subversion在合并方面做得很好。
注意,我没有具体说明我希望109和114更改合并(这两个更改用粗体表示)。为什么?因为这些不是我的分支上的更改,它们是我合并到分支上的主干更改。如果我指定了这两个修订,我将把我的主干更改重新应用到主干上。
但是,我很懒,我希望Subversion为我做这项工作。Subversion查看我的分支,看到所有这些更改,包括更改109和114,并希望将它们合并到我的主干上。不好。
所以,Subversion在这里做了一些特别的事情。如果我们将文件和修订视为应用于文件的更改集,那么我基本上将主干上发生的所有更改应用到分支上,将分支上的所有更改都应用到主干上。换句话说,当我完成这个分支到主干的合并时,我的分支和主干将匹配。
这就是重新融合的作用。与普通合并不同的是,将我的两个文件中的更改与基本修订进行比较,然后仔细应用,我的分支上的所有更改都将应用于我的主干,而不将其与基本修订相比较。重新整合合并是一种双向合并。分支和主干之间的任何差异都将被覆盖。
让我们看看发生了什么:
重新整合合并之前
-
分支:103 105 108109110 111114
-
中继:101 102 104 105 106 107 112 113
-
分支上的
svn:mergeinfo
现在显示trunk:101-113
重新整合合并后
-
分支:103 105 108109110 111114
-
中继:101 102 104 105 106 107 112 113115
-
分支上的
svn:mergeinfo
现在显示trunk:101-113
-
中继线上的
svn:mergeinfo
现在显示branch:103-114
让我们在trunk上做更多的工作,向您展示如果我继续使用我的功能分支会发生什么。我将在主干上再做两个更改:
-
分支:103 105 108109110 111114
-
中继:101 102 104 105 106 107 112 113115116 117
-
分支上的
svn:mergeinfo
现在显示trunk:101-113
-
中继线上的
svn:mergeinfo
现在显示branch:103-114
现在,我想将这些更改合并回我的功能分支。如果我自己挑选,我会指定我想要在我的分支上修改116和117,因为这是我刚刚做的两个更改。再说一次,如果我勤奋好学,Subversion合并会很好。然而,我很懒,会让Subversion来挑选樱桃。
Subversion查看svn:mergeinfo
,发现我已经将更改103到114应用到了分支上。现在,它在我的主干上看到了三个新的变化:变化115、116和117。然而,改变115是我重新融合的结果!115中的所有更改都已在分支上。让Subversion来挑选将导致灾难。
这就是为什么你被告知一旦重新整合了分支就不要再使用它。解决这个问题的方法是从主干到我的分支执行svn merge --record-only -c 115
。实际上不会发生合并,但现在Subversion将记录101到115的更改在我的分支上。如果我这样做,然后从主干到分支进行合并,Subversion将跳过选择更改115,只做更改116和117。
现在您了解了Subversion是如何进行合并跟踪的,以及什么是重新整合合并,我们可以看看您的情况:
- 您从主干分支到分支A
- 你从A分支到B分支
- 您从Trunk合并到分支A
- 您从分支机构A合并到分支机构B
如果你是一个勤奋的年轻程序员,每天早上5点起床跑5英里只是为了让你有心情工作,你会指定你想将每个分支的哪些修订合并到其他分支或主干中。如果你这样做了,就没有任何问题,你可以进行标准的合并,并在健身房进行剧烈锻炼后,为每天100公里的自行车骑行做好准备。
如果你是一个典型的技术工作者(即懒惰),并且你希望Subversion为你处理修订的选择,那么事情就有点不同了:
- 您将分支A中的所有更改合并到分支B中。现在,分支B将包括分支A上的所有修订
- 您执行重新整合将分支B合并回分支a。现在,您对分支a和分支B的所有更改都将在两个分支上
- 您定期将主干合并到分支a。分支a包含您在分支a上所做的所有更改。此外,分支B和主干上的所有更改都包含在内
- 您将分支a(已包含分支B的更改)合并到主干上。现在Trunk、分支A和分支B都包含相同的一组更改,并且这三个更改都应该匹配
- 您现在不应该再使用分支A或分支B,除非您执行
svn merge --record-only
,将分支B到分支A的重新整合更改记录到分支B,并将分支A到主干重新整合更改记到分支A
子版本1.8中的重要更改
知道是在Subversion中进行常规合并还是重新整合合并可能有点容易出错。这是一个手动的过程,如果我作为一个正常人犯了错误(我会在最糟糕的时候犯错误),那可能会是一场灾难。
在Subversion 1.8中,Subversion现在试图通过查看svn:mergeinfo
来确定合并的方式以及何时必须进行重新整合合并。因此,您不再需要在合并时指定--reintegration
标志。Subversion还将确保,如果在分支重新集成到另一个分支或主干中后重用该分支,则不会重新应用重新集成过程中发生的更改。
如果你喜欢做很多功能分支,你应该使用Subversion 1.8,它将为你处理合并跟踪中的许多错误倾向。如果您使用的是Subversion 1.8,那么您应该能够在没有任何问题的情况下完成从分支B到分支A以及到主干的合并。