什么是SVN对mergeinfo的实际使用?

时间:2014-02-20 19:11:30

标签: svn version-control merge mergeinfo

我早就听说过svn的合并冲突问题。

当我得知svn在几个版本之前实现了一个名为mergeinfo的功能时,我很放心。似乎它的引入似乎允许svn有足够的信息来解决它们出现时的合并问题。直到我遇到以下情况:

enter image description here

上图的脚本示例:

SVN=${SVN:-svn}
SVNADMIN=${SVNAMDIN:-svnadmin}

rm -rf repo wc

$SVNADMIN create repo

$SVN co file://$PWD/repo wc
cd wc

# r1
$SVN mkdir trunk branches
$SVN ci -m 'structure'
$SVN up

# r2
echo 2 > trunk/t.txt
$SVN add trunk/t.txt
$SVN ci -m 'add t.txt'
$SVN up

# r3
$SVN cp trunk branches/A
$SVN ci -m 'create branch A'
$SVN up

# r4
echo 4 > branches/A/a.txt
$SVN add branches/A/a.txt
$SVN ci -m 'add a.txt'
$SVN up

# r5
$SVN cp trunk branches/B
$SVN ci -m 'create branch B'
$SVN up

# r6
echo 6 > branches/B/b.txt
$SVN add branches/B/b.txt
$SVN ci -m 'add b.txt'
$SVN up

# r7
$SVN merge ^/branches/B branches/A
$SVN ci -m 'merge branch B into A'
$SVN up

# r8
echo 8 > branches/A/d.txt
$SVN add branches/A/d.txt
$SVN ci -m 'add d.txt'
$SVN up

# r9
$SVN merge ^/branches/A branches/B

如果svn记录了每个分支的来源,为什么它不能理解b.txt未被触及@ branch A

如果无法解决这个问题,mergeinfo的实际用途是什么?

如果svn无法解决这个问题,那么在这方面是不是可以创建一个工具来帮助我(即自动解决这种简单的问题......)?我想也许会有人存在?

由于

3 个答案:

答案 0 :(得分:19)

Subversion中有两种类型的合并:

  1. 三点合并
  2. 两点合并(又名重新融合)
  3. 让我们说你正在使用trunk,并且你有一个特殊的功能需要完成。您创建功能A 分支。当您使用该功能时,您希望在主干上执行的工作包含在功能A 中,这样您就可以跟上其他人所做的事情。 Subversion将使用三点合并。

    Subversion将从分支发生的点开始查看主干和分支功能A之间的区别。最近的共同祖先。然后,它会考虑已完成的功能A的所有更改(您不想触摸)以及在主干上完成的代码更改。

    Subversion将合并trunk上的更改,而不会覆盖在分支上进行的更改。标准合并程序,Subversion做得很好。

    svn:mergeinfo在哪里进来?您不希望将两次相同的更改合并,因此Subversion会使用svn:mergeinfo属性跟踪更改。如果Subversion发现修订版5中的trunk更改已经合并,则不会重新合并该更改。这很好。

    现在,您已完成了自己的功能,并且希望将这些更改合并回主干。您执行最后一个中继以进行分支合并,提交这些更改,然后现在从功能分支合并回主干。

    这里有点问题。我们通过svn:mergeinfo跟踪我们从主干合并到功能分支的内容。但是,由于我们尚未从功能分支合并到主干,因此没有svn:mergeinfo。如果我们尝试从Feature分支到trunk的正常三点合并,则trunk将假定Feature分支中的所有更改都应合并回trunk。但是,其中许多功能实际上是已合并的主干更改。

    说实话,在这一点上,我们想要进行两点合并。我们希望一旦我们进行合并,trunk和Feature分支就完全匹配。毕竟,我们现在定期将主干合并到功能分支中。我们想要做的是将这些功能合并到主干中。因此,主干将与功能分支相同。

    在Subversion 1.8之前,您必须通过运行svn merge --reintegration强制执行重新整合合并。现在,Subversion将查看合并历史记录,并确定何时应该重新整合合并。


    现在这里是棘手的部分。仔细查看修订号。这些非常非常重要!

    • 修订版10 :我对Trunk进行了最后的更改,我需要将这些更改合并到功能分支中。
    • 修订版11 :我将trunk合并到Feature分支中。 svn:mergeinfo将显示从修订版1到修订版10的所有主干都在功能分支中。由于主干上的最后一次更改是修订版10,因此这非常有意义。
    • 修订版12 :我将功能分支的修订版11合并为主干。这是重新整合合并。在此之后,功能分支上的内容以及主干中的内容应该完全一致。

    现在,这里是踢球者!

    • 修订版13 :我在主干中进行了另一项更改。

    现在,我想将其合并到我的Feature分支(创建版本14)。现在,功能分支上的svn:mergeinfo说什么?它表示从修订版1到修订版10的主干已合并到功能分支中。但是,主干的修订版12和修订版13还没有。因此,Subversion将希望将版本12和修订版13合并回功能分支。

    但等一下!

    主干上的版本12是我将功能分支中的所有更改合并回主干!也就是说,修订版12已包含我在功能分支中所做的所有修订更改。如果我将版本12合并回我的功能分支,我会说,版本12中的主干上的所有这些更改(实际上是在功能分支上进行了更改并合并到主干中)需要合并到功能上科。但是,这些更改也在功能分支上进行。你能说合并冲突吗?我知道你可以!


    有两种方法可以解决这个问题:

    • 推荐方式:将功能分支重新集成到主干后,删除分支。锁定它。切勿再次使用它。别碰!这并不像听起来那么糟糕。重新集成合并后,您的主干和该功能分支无论如何都会匹配。从trunk中删除和重新创建分支并不是那么糟糕。
    • 有效的方法:我们需要做的是让Subversion认为修订版#12(或重新整合合并更改)已经合并到我们的Feature分支中。我们可以使用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现在知道trunk的Revision 12已经在Feature分支中。完成后,您可以重用功能分支。


    现在查看您的图表:当您将分支B合并到分支A时,您将B中的所有更改合并到A中,svn:mergeinfo跟踪了该更改。当您将分支B合并回分支A时,您已经完成了分支A中分支B的所有更改,并且您不希望将这些更改带回分支B.您应该使用重新融合合并:

    $ 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合并就可以了。

答案 1 :(得分:10)

David W.'s答案非常好,但我将提供自己的答案,以更现代的方式回答这个问题。大卫告诉你的是真的,在阅读我的答案时理解他的答案是有用的,所以如果你还没有,你应该先阅读他的答案。我的回答提供了对问题的更现代的理解以及大卫指出的问题的解决方案。

首先,简单的回答是,如果你使用Subversion 1.8,你提出的情况就可以了。我在问题中添加的示例脚本在使用Subversion 1.8运行时没有冲突。只需要更新客户端即可获得此功能。

这里较长的答案是,对于旧版本的Subversion,您需要知道何时使用命名不佳的--reintegrate选项(1.8为您解决此问题)。尽管名称--reintegrate不仅适用于将分支重新集成到主干的情况。

人们在使用功能分支时遇到的一个反复出现的问题是,他们希望将功能分支合并回主干,然后继续使用分支。正如大卫的答案在过去所暗示的,有两种方法可以解决这个问题。首先删除分支,然后将其刷新。其次,只记录合并。 Julian Foad,我的Subversion开发人员之一,在向1.8工作时意识到这两种技术都不是必需的。他在his presentation on merging at the Subversion Live 2012 conference中介绍了这一点。他的演示幻灯片可以在这里在线获取(请注意这是会议所有幻灯片的PDF,所以它并不是很小),关于这个问题的部分从第123页开始。

总结他的演示文稿,典型的功能分支工作流程是创建分支机构。对您的功能分支进行提交,并定期从主干到功能分支进行合并,以便与主干上的内容同步,例如: svn merge ^/trunk $BRANCH_WC。然后,当您准备好合并回主干时,您会svn merge --reintegrate ^/branches/myfeature $TRUNK_WC。现在你已经到了传统智慧你必须删除你的功能分支或只做一个记录合并的地步。相反,朱利安发现如果遵循这些规则,你可以继续使用分支。

  • 每次合并方向与两个分支之间的最后一次合并方向相同时, NOT 使用--reintegrate选项。将分支的创建视为来自该创建位置的合并。

  • 每当您更改两个分支之间合并的路线时,请使用--reintegrate进行合并。

在您的具体情况下,您正在更改已合并的路线。 r7从分支B合并到分支A. r9从分支A合并到分支B.所以当你去做你的r9合并时,你需要使用--reintegrate。这个逻辑正是Subversion为你做的1.8。

最后,我不建议你在这里做兄弟分支之间的合并。许多简单的案例,比如你在这里做的事情都会很好。但是,如果您例如拆分文件(svn cp file file2,删除文件1的一部分和文件2中的不同部分),那么当您尝试将两个功能分支中的最后一个合并回来时,您将遇到问题。 trunk(假设您已将拆分合并到两个兄弟分支)。最好将合并限制在两个分支(子分支和父分支)之间。你可以在其他分支之外建立分支并在转到父母的父母之前合并回父母,依此类推。我们希望将来能够使这些事情正常运作,但现在的情况就是1.8(比我们过去好得多,但不如我们想的那么好)。 / p>

答案 2 :(得分:-1)

你误解了mergeinfo的含义和用法 - 它只保留(对于这个节点)合并修订版本和合并源文件,以便不合并修订版本两次,内容无关