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

Reply via email to