2014-02-20 79 views
7

我早就听说过svn的合并冲突问题。什么是SVN实际使用mergeinfo?

当我得知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

如果它不能弄清楚,svn做的mergeinfo的实际用途是什么?

如果svn无法处理这个问题,难道不可能在这个方面创建一个工具来帮助我(即自动解决这种无脑的问题..)吗?我猜可能会有人存在?

感谢

+0

显示真实的输出,而不是图片 - 我看不到您的图纸中可能存在的问题 –

+1

我添加了一个我认为与askers图形匹配的示例。有些地方不清楚。这些文件是否已经存在或是否是新的(我将它们制作成新的,如果发生冲突,其差异将会按照您获得的冲突类型而定)?合并究竟是如何完成的?他们是樱桃选择还是全分支合并。 –

+0

BenReser说得没错。他们是新文件,我正在做一个完整的分支合并。 –

回答

12

有两种类型在颠覆合并的:

  1. 三点合并
  2. 两点合并(又名重返合并)

假设您正在使用trunk,并且您需要完成一项特定功能。您创建一个功能A分支。当您使用该功能时,您需要将中继所做的工作纳入功能A,以便您可以跟上其他人的工作。 Subversion将使用三点合并。

Subversion将从分支发生的位置查看树干和分支特征A之间的区别。最近的共同祖先。然后它会考虑已完成的功能A上的所有更改(您不想触及的)以及中继线上完成的代码更改。

Subversion然后将合并主干上的更改而不覆盖分支上所做的更改。标准的合并过程,Subversion做得很好。

svn:mergeinfo在哪里?您不想合并两次相同的更改,因此Subversion使用svn:mergeinfo属性跟踪更改。如果Subversion看到版本5中主干的变化已经被合并,它不会重新发生这种变化。这是非常好的。

现在,您已完成了您的功能,并且希望将这些更改合并回主干。你做最后一个主干分支合并,提交这些更改,现在从Feature分支合并回主干。

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

事实上,在这一点上,我们想要做一个两点合并。我们希望trunk和Feature分支在我们进行合并时完全匹配。毕竟,我们现在已经定期将树干合并到Feature分支中。我们想要做的就是将这些功能重新加入后备箱。因此,主干将与特征分支相同。

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


现在这里是棘手的部分。仔细查看版本号。这些将会非常非常重要!

  • 修订10:这是我最后变成树干,我需要将这些合并到功能分支。
  • 修订11:我合并中继到功能分支。 svn:mergeinfo将显示从版本1到版本10的所有主干都位于特征分支中。由于主干上的最后更改是版本10,因此这非常合理。
  • 修订12:我将Feature Branch的版本11合并到主干中。这是一个重新整合合并。在此之后,Feature分支上的内容和Trunk中的内容应该完全一致。

现在,这里是踢球者!

  • 修订13:我在中继线上做了另一个改变。

现在,我想合并到我的功能分支(创建修订14)。现在,功能部件上的svn:mergeinfo说什么?它表示从版本1到版本10的主干已经合并到Feature分支中。不过,主干版本12和版本13没有。因此,Subversion需要将版本12和版本13重新合并到Feature分支中。

但等一下!

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


有处理这种双向的:

  • 推荐的方法:一旦你重返社会的特性分支回主干,删除分支。锁定它。切勿再次使用它。不要碰!这并不像听起来那么糟糕。重新整合合并后,您的主干和该功能分支无论如何都会匹配。从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现在知道中继线的版本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 

,如果我们想继续使用分支用于进一步的修改:

$ 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的作品,为什么你要知道你是否正在使用正常的三点合并与两点重新合并合并,以及如何能够重新激活分支后r你已经完成了重新整合合并。

只要你牢记这一点,Subversion合并工作就会很好。

0

你误会合并信息的意义和用法 - 它仅保存已(此节点),合并,以便不合并修订了两次,没有什么有关内容的修改和合并,起源

7

David W.'s答案是相当不错的,但我会提供我自己的答案,从更现代的方法回答这个问题。大卫告诉你的是真实的,在阅读我的答案时理解他的答案是有用的,所以如果你还没有阅读,你应该阅读他的第一个答案。我的回答对David所指出的问题和解决方案提供了更现代的理解。

因此,首先简单的答案是,如果您使用Subversion 1.8,那么您呈现的情况工作得很好。使用Subversion 1.8运行时,添加到问题中的示例脚本没有冲突。只有客户需要更新才能获得此功能。

这里较长的答案是,对于较旧版本的Subversion,您需要知道何时使用命名不清的--reintegrate选项(1.8数字表示适合您)。尽管名称为--reintegrate不仅适用于将分支重新集成到主干时。

人们经常遇到的问题之一是当他们使用功能分支时,他们想要将功能分支合并回主干,然后继续使用该分支。正如大卫的回答所表明的那样,有两种方法可以解决这个问题。首先删除分支,然后使其新鲜。其次,只记录合并。我的Subversion开发人员之一Julian Foad在向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。现在你已经到了传统智慧的地步,你必须删除你的功能分支或者只做一个记录合并。相反,朱利安发现,如果你遵循这些规则,你可以继续使用分支。

  • 你在相同的方向两支之间的最后合并合并每次你做使用--reintegrate选项。将分支的创建视为与创建位置的合并。

  • 每次更改您在两个分支之间合并的方向时,都会使用--reintegrate进行合并。

在你的具体情况下,你正在改变你已经合并的方向。 r7正在从分支B合并到分支A. r9从分支A合并到分支B.因此,当您开始进行r9合并时,您需要使用--reintegrate。这个逻辑正是Subversion为1.8所做的。

最后,我不建议你在这里做兄弟分支之间的合并。很多简单的例子,比如你在这里做的事情都能很好地工作。但是,如果您例如分割一个文件(svn cp file file2,将文件1的一部分和file2中的不同部分删除),那么当您尝试将两个功能分支的最后一个合并回到trunk时会遇到问题(假设您已将拆分合并到两个兄弟分行)。最好将合并限制在两个分支(儿童和父母)之间。您可以在转到其父母的父母之前将其他分支关闭分支并合并回父母等,并且没问题。我们希望即使这些事情在未来也能正常工作,但现在情况就是这样,情况目前在1.8(现在远比过去好,但不如我们想要的好)。