Subversion 中有两种类型的合并:
- 三点合并
- 两点合并(又名重新整合合并)
假设您正在开发主干,并且您有一个特定的功能需要完成。您创建一个 Feature A 分支。在开发该功能时,您希望您在 trunk 上所做的工作包含在 Feature A 中,这样您就可以跟上其他人的工作。 Subversion 将使用三点合并。
Subversion 将从分支发生的那一点开始查看主干和分支特性 A 之间的区别。最近的共同祖先。然后,它会考虑对功能 A 所做的所有更改(您不想触摸)以及在主干上完成的代码更改。
Subversion 将合并主干上的更改,而不会覆盖分支上所做的更改。标准的合并过程,Subversion 做得很好。
svn:mergeinfo 来自哪里?您不想合并两次相同的更改,因此 Subversion 使用 svn:mergeinfo 属性跟踪更改。如果 Subversion 发现来自 Revision 5 的主干中的更改已经被合并,它不会重新合并该更改。这个很好用。
现在,您已经完成了您的功能,并且您希望将这些更改合并回主干。您将最后一个主干进行分支合并,提交这些更改,然后从功能分支合并回主干。
这里有点问题。我们通过svn:mergeinfo 跟踪了我们从主干合并到功能分支的内容。但是,由于我们还没有从 Feature 分支合并到主干,所以那里没有 svn:mergeinfo。如果我们尝试从 Feature 分支正常的三点合并到主干,主干将假定 Feature 分支中的所有更改都应该合并回主干。但是,其中许多功能实际上是已合并的主干更改。
说实话,在这一点上,我们想做一个两点合并。一旦我们进行合并,我们希望主干和功能分支完全匹配。毕竟,我们现在已经定期将主干合并到功能分支中。我们想要做的是将这些功能重新合并到主干中。因此,主干将与功能分支相同。
在 Subversion 1.8 之前,您必须通过运行 svn merge --reintegration 来强制重新集成合并。现在,Subversion 将查看合并历史并确定何时应该进行重新集成。
现在是棘手的部分。仔细查看修订号。这些将非常非常重要!
-
修订版 10:我对 Trunk 进行了最后的更改,我需要将这些更改合并到 Feature 分支中。
-
Revision 11:我将主干合并到功能分支中。
svn:mergeinfo 将显示从 Revision 1 到 Revision 10 的所有主干都在 Feature 分支中。由于主干上的最后一次更改是修订版 10,因此这非常有意义。
-
Revision 12:我将 Feature Branch 的 Revision 11 合并到主干。这是一个重新整合合并。在此之后,Feature 分支上的内容和主干中的内容应该完全一致。
现在,关键来了!
现在,我想将其合并到我的功能分支(创建修订版 14)。现在,功能分支上的svn:mergeinfo 是什么意思?它表示从 Revision 1 到 Revision 10 的主干已合并到 Feature 分支中。但是,主干的修订版 12 和修订版 13 还没有。因此,Subversion 将希望将 Revision 12 和 Revision 13 合并回 Feature 分支。
请稍等!
主干上的修订版 12 是我将功能分支中的所有更改合并回主干!也就是说,Revision 12 已经包含了我在 Feature 分支中所做的所有修订更改。如果我将修订版 12 合并回我的功能分支,我会说修订版 12 中主干上的所有这些更改(实际上是在功能分支上进行的更改并合并到主干)需要合并到功能分支中。但是,这些更改也是在 Feature 分支上进行的。你能说合并冲突吗?我知道你可以!
有两种处理方式:
-
推荐方式:将功能分支重新集成回主干后,删除该分支。锁定它。永远不要再使用它。不要碰!这并不像听起来那么糟糕。重新集成合并后,您的主干和该功能分支无论如何都会匹配。从主干删除和重新创建分支不会那么糟糕。
-
棘手的工作方式:我们需要做的是让 Subversion 认为 Revision #12(或重新集成合并更改)已经合并到我们的功能分支中。我们可以使用
svn:mergeinfo 属性来解决问题。而且,我过去就是这样做的。如果上面写着trunk:1-11,我会手动将其更改为trunk:1-12。
这很棘手,但是太棘手了,而且有风险,因为 Subversion 已经为您提供了一种无需手动更改即可操作 svn:mergeinfo 的方法。
这称为仅记录合并。
$ svn co svn://branches/feature_a
$ cd feature_a
$ svn merge --record-only -c 12 svn://trunk
$ svn commit -m "Adding in the reintegration merge back into the feature branch."
这会更改功能分支上的svn:mergeinfo,而不会影响文件的实际内容。没有进行真正的合并,但 Subversion 现在知道主干的修订版 12 已经在 Feature 分支中。一旦你这样做了,你就可以重用功能分支。
现在看一下您的图表:当您将分支 B 合并到分支 A 时,您将 B 中的所有更改合并到 A 中,svn:mergeinfo 跟踪了这一点。当您将分支 B 合并回分支 A 时,您已经在分支 A 中拥有来自分支 B 的所有更改,并且您不希望将这些更改带回分支 B。您应该使用 reintegration 合并:
$ cd $branch_a_working_dir
$ svn merge $REPO/branches/B
$ svn commit -m "Rev 7: All of my changes on Branch B are now in A"
$ vi d.txt
$ svn add d.txt
$ svn commit -m"Rev 8: I added d.txt"
$ cd $branch_b_working_dir
$ svn merge --reintegrate svn://branch/A # Note this is a REINTEGRATION merge!
$ svn commit -m"Rev 9: I've reintegrated Branch A into Branch B
现在,如果我们想继续使用分支 A 进行进一步的更改:
$ cd $branch_a_working_dir
$ svn merge -c 9 --record-only $REPO/branches/b
$ svn commit -m"I've reactivated Branch A and can make further changes"
我希望这能解释一下svn:mergeinfo 的工作原理,为什么你必须知道你是使用普通的三点合并还是两点重新整合合并,以及如何能够重新激活分支在您完成重新集成合并之后。
只要记住这一点,Subversion 合并就可以很好地工作。