You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@subversion.apache.org by Philip Martin <ph...@wandisco.com> on 2013/03/18 20:26:47 UTC

Issue 3247 "merge doesn't honour specified source"

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

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 but it's not new behaviour, 1.7 was the same.

Next consider merging the wrong URL:

svn co file://`pwd`/repo/A wc
svn merge -c3 ^/A2/B wc

that gives a tree-conflict on wc/f.  The cherry-pick merge doesn't check
ancestyr, gets a diff from the repository, and fails to apply it because
the paths don't match.  That seems OK.

Now try the reverse merge alone (call this case B):

svn co file://`pwd`/repo/A wc
svn merge -c-3 ^/A2/B wc

Again 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.  If this merge
attempted to merge the change the tree-conflict would indicate to the
user that the wrong URL was used.

I'm not sure why cases A and B don't attempt to merge changes.  Can
anyone explain the behaviour?

-- 
Certified & Supported Apache Subversion Downloads:
http://www.wandisco.com/subversion/download

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

Posted by Paul Burba <pt...@gmail.com>.
On Tue, Mar 19, 2013 at 10:56 AM, Philip Martin
<ph...@wandisco.com> wrote:
> Paul Burba <pt...@gmail.com> writes:
>
>> Where we can improve is in skipping the '[Recording | Eliding]
>> mergeinfo' notifications if nothing was actually merged.
>
> Essentially we are skipping a reverse merge because we cannot record
> it. That's fine by me so long as we make it clear to the user.  This is
> clear:
>
> $ svn co file://`pwd`/repo/A2@2 wc
> $ svn merge -c-3 ^/A2 wc
> svn: E195020: Cannot reverse-merge a range from a path's own future history; try updating first
>
> but I believe simply skipping the notifications to give:
>
> $ svn co file://`pwd`/repo/A wc
> $ svn merge -c-3 ^/A2 wc
> $
>
> would still be confusing.

So you'd like to see some alternative notification for merges that are
ultimately inoperative?

Do you agree that we'd need a variant for inoperative forward merges too, e.g.:

  >svn pl -vR
  Properties on 'branch':
    svn:mergeinfo
      /A:2-6

  >svn merge ^^/A branch -r1:6
  --- Recording mergeinfo for merge of r2 through r6 into 'branch':
   U   branch

  >svn st

  >

And what about inoperative merges that adjust mergeinfo (think
periodic automatic sync merges that are occasionally inoperative, but
still tweak mergeinfo):

  >svn merge ^^/A branch
  --- Recording mergeinfo for merge of r7 into 'branch':
   U   branch

  >svn diff
  Index: branch
  ===================================================================
  --- branch      (revision 7)
  +++ branch      (working copy)

  Property changes on: branch
  ___________________________________________________________________
  Modified: svn:mergeinfo
     Merged /A:r7

-- 
Paul T. Burba
CollabNet, Inc. -- www.collab.net -- Enterprise Cloud Development
Skype: ptburba

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

Posted by Philip Martin <ph...@wandisco.com>.
Paul Burba <pt...@gmail.com> writes:

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

Essentially we are skipping a reverse merge because we cannot record
it. That's fine by me so long as we make it clear to the user.  This is
clear:

$ svn co file://`pwd`/repo/A2@2 wc
$ svn merge -c-3 ^/A2 wc
svn: E195020: Cannot reverse-merge a range from a path's own future history; try updating first

but I believe simply skipping the notifications to give:

$ svn co file://`pwd`/repo/A wc
$ svn merge -c-3 ^/A2 wc
$

would still be confusing.

-- 
Certified & Supported Apache Subversion Downloads:
http://www.wandisco.com/subversion/download

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

Posted by Paul Burba <pt...@gmail.com>.
On Mon, Mar 18, 2013 at 6:40 PM, Philip Martin
<ph...@wandisco.com> wrote:
> Paul Burba <pt...@gmail.com> writes:
>
>> On Mon, Mar 18, 2013 at 3:26 PM, Philip Martin
>> <ph...@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

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

Posted by Philip Martin <ph...@wandisco.com>.
Paul Burba <pt...@gmail.com> writes:

> On Mon, Mar 18, 2013 at 3:26 PM, Philip Martin
> <ph...@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.

Using gdb I see that the merge:

  svn co file://`pwd`/repo/A wc
  svn merge -c-3 ^/A2 wc

doesn't call svn_ra_do_diff3, in other words the whole merge has been
elided.  I guess it's related to this:

  svn co file://`pwd`/repo/A2@2 wc
  svn merge -c-3 ^/A2 wc
  svn: E195020: Cannot reverse-merge a range from a path's own future history; try updating first

-- 
Certified & Supported Apache Subversion Downloads:
http://www.wandisco.com/subversion/download

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

Posted by Paul Burba <pt...@gmail.com>.
On Mon, Mar 18, 2013 at 3:26 PM, Philip Martin
<ph...@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?

> 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.

> but it's not new behaviour, 1.7 was the same.
>
> Next consider merging the wrong URL:
>
> svn co file://`pwd`/repo/A wc
> svn merge -c3 ^/A2/B wc
>
> that gives a tree-conflict on wc/f.  The cherry-pick merge doesn't check
> ancestyr, gets a diff from the repository, and fails to apply it because
> the paths don't match.  That seems OK.
>
> Now try the reverse merge alone (call this case B):
>
> svn co file://`pwd`/repo/A wc
> svn merge -c-3 ^/A2/B wc
>
> Again 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.  If this merge
> attempted to merge the change the tree-conflict would indicate to the
> user that the wrong URL was used.
>
> I'm not sure why cases A and B don't attempt to merge changes.  Can
> anyone explain the behaviour?

Wow, that is surprising.  I can't explain it either...1.7 behaves the same...

...investigating

-- 
Paul T. Burba
CollabNet, Inc. -- www.collab.net -- Enterprise Cloud Development
Skype: ptburba