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

Re: Issue 3247 "merge doesn't honour specified source"

From: Paul Burba <ptburba_at_gmail.com>
Date: Tue, 19 Mar 2013 10:43:24 -0400

On Mon, Mar 18, 2013 at 6:40 PM, Philip Martin
<philip.martin_at_wandisco.com> wrote:
> Paul Burba <ptburba_at_gmail.com> writes:
>
>> On Mon, Mar 18, 2013 at 3:26 PM, Philip Martin
>> <philip.martin_at_wandisco.com> wrote:
>>> This is one of the issues blocking 1.8. I don't really understand the
>>> merge behaviour. Consider this test case: a file in a directory,
>>> branch, modify the file on the branch:
>>>
>>> svnadmin create repo
>>> svn -mm import repo/format file://`pwd`/repo/A/B/f
>>> svn -mm cp file://`pwd`/repo/A ^/A2
>>> svnmucc -mm put repo/README.txt file://`pwd`/repo/A2/B/f
>>>
>>> Now merge the change back to the original branch:
>>>
>>> svn co file://`pwd`/repo/A wc
>>> svn merge -c3 ^/A2 wc
>>>
>>> that works and modifies wc/B/f and records the merge. Then reverse merge
>>>
>>> svn merge -c-3 ^/A2 wc
>>>
>>> and the change is undo leaving a pristine working copy. That all
>>> seems fine.
>>>
>>> However a reverse merge alone does nothing (call this case A):
>>>
>>> svn co file://`pwd`/repo/A wc
>>> svn merge -c3 ^/A2 wc
>>
>> You mean 'svn merge -c-3 ^/A2 wc' right?
>
> Yes.
>
>>> The notifications say:
>>>
>>> --- Recording mergeinfo for reverse merge of r3 into 'wc':
>>> U wc
>>> --- Eliding mergeinfo from 'wc':
>>> U wc
>>>
>>> and overall there are no changes in the working copy. I don't really
>>> understand that
>>
>> The notifications could be handled better in these cases. Right now
>> the merge code assumes that a mergetracking aware merge will record
>> mergeinfo describing the merge and that that mergeinfo will mean
>> something. For forward merges this is always the case, but not so for
>> reverse merges. This is the same thing we see when reverting a change
>> using a reverse merge from the same branch's history:
>>
>> # Starting with an unmodified WC for ^/subversion/trunk, say we want to
>> # revert a recent commit:
>>
>> C:\SVN\src-trunk-4>svn merge ^^/subversion/trunk -c-1457920
>> --- Reverse-merging r1457920 into '.':
>> U contrib\client-side\svncopy\svncopy.pl.in
>> --- Recording mergeinfo for reverse merge of r1457920 into '.':
>> U .
>>
>> # We claim to have recorded mergeinfo describing the merge, and we
>> did, it's just that it's
>> # identical to what we started with (since we don't currently have a
>> way of representing
>> # reverse merges in svn:mergeinfo -
>> http://subversion.tigris.org/issues/show_bug.cgi?id=2881)
>>
>> C:\SVN\src-trunk-4>svn st
>> M contrib\client-side\svncopy\svncopy.pl.in
>>
>> The situation is a bit odder in your example because there is no
>> pre-existing mergeinfo on the merge target, so the mergeinfo
>> describing the merge is simply "" and that elides away.
>
> It's not just the mergeinfo that is difficult to understand. Your
> reverse merge example includes a text change:
>
> U contrib\client-side\svncopy\svncopy.pl.in
>
> my reverse merge does not include:
>
> U wc/f
>
> So the merge has not only elided the mergeinfo change, it has also
> removed the text change. Even if recording the reverse merge is
> impossible I'd still expect to see a text change.

My mistake Philip, at first glance I thought r3 was inoperative on ^^/A2.

Looking at this with fresh eyes this morning I see what should have
been clear last night. What's happening here (and also in 'Case B')
is that we only allow a reverse merge[1] if the requested merge is
either:

1) Recorded in the target's mergeinfo

or

2) Part of the target's natural history (i.e. it's "implicit" mergeinfo).

Why? Because mergetracking's raison d'ĂȘtre is to avoid repeat merges.
If we merge rX from /trunk to branch, commit the merge, then try the
same merge again it's obviously a no-op.

Things are bit messier with reverse merges though since we currently
don't have a way to record reverse merges in svn:mergeinfo (issue
#2881 again) except by removing existing mergeinfo. The simple case
is something like this:

merge ^/trunk branch-wc -r100:200 # Adds '/trunk:101-200' mergeinfo
commit
merge ^/trunk branch-wc -c-150 # Removes '/trunk:150' mergeinfo
commit
merge ^/trunk branch-wc -c-150 # Repeat merge is a no-op because the history
                               # represented by '/trunk:150' isn't part of
                               # the target's implicit or explicit mergeinfo.

Unfortunately this approach means the reverse merges in your examples
are no-ops because neither criteria #1 or #2 are met. I believe this
is the better choice -- If we were to allow those merges, then my
above repeat merge scenario breaks. FWIW this is how reverse merges
have behaved since 1.5.

Where we can improve is in skipping the '[Recording | Eliding]
mergeinfo' notifications if nothing was actually merged.

[1] Assuming mergetracking is in effect of course. Using
--ignore-ancestry to disable mergetracking gives the results you were
expecting case B:

>svn merge ^^/A2/B A -c-3 --ignore-ancestry
  --- Reverse-merging r3 into 'A':
     C A\f
  Summary of conflicts:
    Tree conflicts: 1

Case A is a little odd:

>svn merge ^^/A2 A -c-3 --ignore-ancestry

>

This is a no-op because we treat the file merge case where left !=
right, right == target => no-op, see merge.c:merge_file_trivial().

-- 
Paul T. Burba
CollabNet, Inc. -- www.collab.net -- Enterprise Cloud Development
Skype: ptburba
Received on 2013-03-19 15:43:56 CET

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