[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: Subversion merge creates bogus tree conflicts

From: Ben Reser <ben_at_reser.org>
Date: Mon, 14 Jan 2013 19:03:10 -0800

On Mon, Jan 14, 2013 at 8:49 AM, David Moon <david.moon_at_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
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_at_head' and

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.
Received on 2013-01-15 04:10:32 CET

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.