Ben Reser wrote: > On Mon, Jan 14, 2013 at 8:49 AM, David Moon <david.m...@versata.com> wrote: >> Subversion creates an unnecessary tree conflict when two branches of a >> directory are merged. See the transcript below. Since the contents of the >> directory do not conflict between the two branches, it should just add both >> subdirectories to the directory and not report any conflict. In my opinion, >> that should be the default merge behavior, but there isn't even any way >> using svn resolve to tell it to do that! The only thing svn resolve can do >> is lose the incoming change. >> >> The unnecessary tree conflict does not always happen, based on I know not >> what. But the transcript below seems to be a reliable way to reproduce it. >> >> This transcript is boiled down to a simple test case. In the real thing >> there were too many of these tree conflicts to fix by hand, so fixing it by >> hand is not a solution even if I could figure out how to fix it by hand. >> >> $REPOS is file:/// something. >> >>> svn --version >> svn, version 1.7.8 (r1419691) >> compiled Dec 12 2012, 14:18:28 >> >>> svn mkdir --parents $REPOS/test1/branches/B1/D1/D2/A -m xx >> >>> svn mkdir --parents $REPOS/test1/tags/T1/D1/D2/B -m xx >> >>> svn co $REPOS/test1/branches/B1/D1/D2/A >>> echo test > A/test1.txt >>> cd A; svn add test1.txt >>> svn commit -m xx >>> cd .. >> >>> svn co $REPOS/test1/tags/T1/D1/D2/B >>> echo test > B/test2.txt >>> cd B; svn add test2.txt >>> svn commit -m xx >>> cd .. >> >>> svn copy $REPOS/test1/tags/T1 $REPOS/test1/branches/B2 -m xx >> >>> svn list -R $REPOS/test1/branches/B1 >> D1/ >> D1/D2/ >> D1/D2/A/ >> D1/D2/A/test1.txt >>> svn list -R $REPOS/test1/branches/B2 >> D1/ >> D1/D2/ >> D1/D2/B/ >> D1/D2/B/test2.txt >> >>> svn co $REPOS/test1/branches/B2 >>> cd B2 >>> svn merge $REPOS/test1/branches/B1 >> --- Merging r167502 through r167505 into '.': >> C D1/D2/A >> --- Recording mergeinfo for merge of r167502 through r167505 into '.': >> U . >> Summary of conflicts: >> Tree conflicts: 1 >>> svn status >> M . >> ! C D1/D2/A >> > local delete, incoming edit upon merge >> Summary of conflicts: >> Tree conflicts: 1 >>> ls D1/D2 >> B/ >> >> Note: ls D1/D2 should say A/ B/ and there should be no tree conflict. >> >> In the real thing, the svn status explanation of the tree conflict is >> usually "local add, incoming add upon merge." I can't explain why the >> simple test case says local delete instead. I don't know if this matters. >> >> I can't say that Subversion is not behaving according to the documentation, >> because the documentation at http://svnbook.red-bean.com/en/1.7/index.html >> is extremely vague about this aspect of Subversion. But it's not behaving >> in a useful way. >> >> I hope this bug report is useful to you. I can't wait for a fix, so I am >> changing to a different strategy that does not depend on Subversion merge. > > Looks to me like you're using the merge command wrong. > > 1) You're using the sync merge format of the 1.7.x merge command, > however the two branches you're merging (B1 and B2) have no common > ancestor. Since B2 was copied from T1 which you independently > created, there's really no way for the command to know what to do. > The fact that it does anything can be considered a bug, I'll note that > on trunk right now the example you give above fails with the following > error: > [[[ > svn: E205000: Try 'svn help merge' for more information > svn: E205000: Source and target must be different but related branches > svn: E205000: Source and target have no common ancestor: > 'file:///Users/breser/moon/repo/test1/branches/B1@head' and > '.@unspecified' > ]]] > > Based on the behavior it seems that in 1.7.x the command is somehow > trying to do a cherry-pick. > > 2) If what you're really intending to do here is a cherry-pick merge > of the changes that were made on B1 (adding A and test1.txt) then you > want to use the cherry-pick form: > svn merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH] > > Note that you need either -c or -r to specify the range of revisions. > > You might be tempted to try (assuming that r1 is where A was added) > svn merge -r0:HEAD $REPOS/test1/branches/B1 > > However, you'll still get the conflict: > [[[ > $ svn merge -r0:HEAD $REPOS/test1/branches/B1 > --- Merging r2 through r5 into '.': > C D1/D2/A > --- Recording mergeinfo for merge of r2 through r5 into '.': > U . > Summary of conflicts: > Tree conflicts: 1 > ]]] > > and a similar status: > [[[ > $ svn status > M . > ! C D1/D2/A > > local delete, incoming edit upon merge > Summary of conflicts: > Tree conflicts: 1 > ]]] > > If I modify your example by adding the following two commands onto the front: > [[[ > svn mkdir --parents $REPOS/test1/branches/B1/D1/D2 -m xx > svn mkdir --parents $REPOS/test1/tags/T1/D1/D2 -m xx > ]]] > > Which shifts the creation of your shared paths from the differences > onto separate versions (and as such A isn't created until r3) then I > get the following a successful merge by doing: > [[[ > $ svn merge -r2:HEAD $REPOS/test1/branches/B1 > --- Merging r3 through r7 into '.': > A D1/D2/A > A D1/D2/A/test1.txt > --- Recording mergeinfo for merge of r3 through r7 into '.': > U . > > $ svn status > M . > A + D1/D2/A > > ]]] > > So what's happening here is that Subversion is conflicting on trying > to create D1 and D2 because the creation of these directories are in > the revision you're trying to merge. > > You can work around this by doing: > svn mkdir D1/D2/A > > and then doing the merge as follows: > svn merge -r0:HEAD $REPOS/test1/branches/B1/D1/D2/A D1/D2/A > > This works because the creation of those directories is now filtered > out as happening below the path you're merging. > > It's hard to say if there's a bug here or not based on what you've > said so far. Your example use case seems so far from any realistic > scenario that it's hard to envision what you're actually doing here. > > The local delete on the status notification is a bug of some sort in > 1.7 but it doesn't happen in trunk and so many things have changed > between the two it's really hard to be sure why. > > I can understand the argument that maybe we should handle this > directory creation conflict a little more gracefully, but it does seem > to be a legitimate tree conflict. > > Hopefully someone else can chime in with a little more knowledge of > this code than I have.
I think the main point is you need to understand that "svn merge" doesn't calculate the union of two sets of nodes, it combines two sets of *changes* that have been made since a common starting point. You might want to read the section on merging in The Book <http://svnbook.red-bean.com/>. The other point of note is that the difference between getting an "add versus add" tree conflict in your real case and a "delete versus add" conflict in your test case points to your test case not reflecting your real case -- those are two very different scenarios. - Julian