You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@subversion.apache.org by Neels Janosch Hofmeyr <ne...@elego.de> on 2009/07/21 13:34:36 UTC

operation based merging -- was: Re: svn commit: r38394 - in trunk/subversion: include libsvn_delta

Stefan Sperling wrote:
> On Tue, Jul 21, 2009 at 04:30:53AM +0200, Neels Janosch Hofmeyr wrote:
>> - is it ok to disallow multiple add() and delete() calls on the same path,
>>   in principle?
>>    e.g. during merge, there are only the two sides, merge-left
>>    and merge-right. A replace means that both exist but are "unrelated". So
>>    a merge will never need to send more than one (delete, add) tuple.
>>    Usually it's either *one* delete or *one* add. The (add, delete) tuple
>>    simply cancels out, nothing being sent.
>>
>>   But are there cases where we also send all the steps in-between? Then we
>>   could allow this: add(), add(REPLACES_REV), add(REPLACES_REV), delete().
>>   But *are there*?
>>
>> - is it necessary to disallow multiple add() and delete() calls on the same
>>   path, to make the atomic replace useful?
>>    e.g. during merge, the receiver needs to cache all delete()s and match
>>    with add()s, carrying out the leftovers during dir_close(). And merge
>>    is not the only one in need of this quirky code construct.
>>   I want to eradicate this madness -- I'd love to force atomic replaces
>>   on everyone, so the receivers are entirely relieved of this quirkiness.
>>   Will allowing both separate and atomic replace calls defy my plan by
>>   actually adding more code to the receivers?
>>
>> - is there a case where separate calls have a different meaning than an
>>   atomic replace?
>>    e.g. for merge, it doesn't matter whether the nodes are "related".
>>   I can't think of any case where we'd want to highlight that the node was
>>   deleted and later re-added with the same history, or something. Right?
>>
>> ~Neels
> 
> Note that if we ever switch to operation-based merging, a sender
> might send mulitple replace calls for the same item.
> 
> Right now, Subversion just looks at the static difference between
> the source and target branches, and tries to eliminate this difference.
> Operation-based merging adds a notion of time to this difference.
> It means that tree operations such as copy, delete, add, replace
> would be replayed in order on the target branch just like they
> happened on the source branch in the revision range being merged.
> 
> This would make handling tree conflicts much easier, and would also
> deal with other wrinkles, such as the fact that copies aren't being
> merged from one branch to another in a useful way.[*]
> 
> The editor interface should allow for this kind of operation.
> In the long term, I hope to see Subversion do operation-based merging.

That's quite an interesting perspective.
Thanks!


> 
> Stefan
> 
> [*] We end up merging "svn copy /branch/A /branch/B" from branch
> to trunk as "svn copy /branch/B /trunk/B" while it should be
> "svn copy /trunk/A /trunk/B" plus merging any additional textual edits
> made in /branch/B since its inception into /trunk/B.
> Right now, edits made to /trunk/A after branching do not make their
> way into /trunk/B in the merge result, which is wrong since B is
> supposed to be a copy of A on trunk, too, but ends up not being a copy
> of /trunk/A. And it's even worse with moves because changes made to A
> after branching just get dropped in <1.6. In 1.6 and beyond, we're
> flagging a tree conflict on A, (local edit, incoming delete upon merge)
> but we should be handling this automatically. And IIRC detecting this
> case doesn't even work for directories right now.

whoa, stsp, you sometimes have a way of writing a really complicated example
in one huge paragraph rant. I admittedly do not understand every detail in
this one... but I do have a question:


A  /trunk/A
    |
    |\_________svn copy ^/trunk ^/branch___________
    |                                              \
M  /trunk/A  (1)                                   |
    |                                          svn copy A B
    |                                          A+ /branch/B
    |                                              |
    |                                          M  /branch/B  (2)
    |                                              |
    |               <--- merge ---{                |
A+ /trunk/B  (3)                                   |


So you argue that (3) should contain *both* the edits (1) and (2), instead
of just (2)? It seems to me that it is impossible to know whether a user
wants that or not!

I can imagine both cases:
 - "What!? Why did it not merge the edits on /trunk/A (1)?"
 - "What!? It included all the edits on /trunk/A (1) as well?"

I would probably have been asking the latter, *not* expecting trunk/B to
contain (1). So operation based merges would throw me off at first.

If I got it right and you're sure about it, it seems to me like this
situation needs some kind of conflict resolu
 * neels stops short.

I'll rather keep quiet before we add another column for "merge conflicts"
;)

~Neels

------------------------------------------------------
http://subversion.tigris.org/ds/viewMessage.do?dsForumId=462&dsMessageId=2372974

Re: operation based merging -- was: Re: svn commit: r38394 - in trunk/subversion: include libsvn_delta

Posted by Gavin Baumanis <ga...@thespidernet.com>.
On 22/07/2009, at 00:44 , Stefan Sperling wrote:

> On Tue, Jul 21, 2009 at 03:34:36PM +0200, Neels Janosch Hofmeyr wrote:
>>> [*] We end up merging "svn copy /branch/A /branch/B" from branch
>>> to trunk as "svn copy /branch/B /trunk/B" while it should be
>>> "svn copy /trunk/A /trunk/B" plus merging any additional textual  
>>> edits
>>> made in /branch/B since its inception into /trunk/B.
>>> Right now, edits made to /trunk/A after branching do not make their
>>> way into /trunk/B in the merge result, which is wrong since B is
>>> supposed to be a copy of A on trunk, too, but ends up not being a  
>>> copy
>>> of /trunk/A. And it's even worse with moves because changes made  
>>> to A
>>> after branching just get dropped in <1.6. In 1.6 and beyond, we're
>>> flagging a tree conflict on A, (local edit, incoming delete upon  
>>> merge)
>>> but we should be handling this automatically. And IIRC detecting  
>>> this
>>> case doesn't even work for directories right now.
>>
>> whoa, stsp, you sometimes have a way of writing a really  
>> complicated example
>> in one huge paragraph rant.
>
> Your diagram sums it up nicely though :)
>
>> I admittedly do not understand every detail in
>> this one... but I do have a question:
>>
>>
>> A  /trunk/A
>>    |
>>    |\_________svn copy ^/trunk ^/branch___________
>>    |                                              \
>> M  /trunk/A  (1)                                   |
>>    |                                          svn copy A B
>>    |                                          A+ /branch/B
>>    |                                              |
>>    |                                          M  /branch/B  (2)
>>    |                                              |
>>    |               <--- merge ---{                |
>> A+ /trunk/B  (3)                                   |
>>
>>
>> So you argue that (3) should contain *both* the edits (1) and (2),  
>> instead
>> of just (2)? It seems to me that it is impossible to know whether a  
>> user
>> wants that or not!
>
> True, there is ambiguity. There is more than one way to merge this.
>
>> I can imagine both cases:
>> - "What!? Why did it not merge the edits on /trunk/A (1)?"
>> - "What!? It included all the edits on /trunk/A (1) as well?"
>
> Does it need to be configurable? I'd imagine that merging the
> edits by default is a safe thing to do. Note that e.g. Mercurial
> does this by default, so there is precedence.
>
>> I would probably have been asking the latter, *not* expecting trunk/ 
>> B to
>> contain (1). So operation based merges would throw me off at first.
>
> In a huge merge, it's easier to revert a textual edit you don't want,
> and which you can see in svn diff, than to find an edit which should
> have happened but didn't. And which you can't tell from svn diff so
> it's easy to overlook -- you may see it as part of a file being  
> deleted
> but if it's a huge file who is going to bother checking every line
> for things they want to keep in the copy?
>
>> If I got it right and you're sure about it, it seems to me like this
>> situation needs some kind of conflict resolu
>> * neels stops short.
>
> We could flag a tree conflict and have the edits be applied
> to the victim by default. Just like we currently schedule some
> victims A+ by default to make it easy for people who want to keep
> the victim. People who do not want to keep the A+ victim can just run
> 'svn revert victim' to unschedule it. People who do not want the
> edits in the copy can just revert them. At least the edits have
> been brought to their attention this way. And that's what Subversion
> is supposed to do -- helping people with keeping track of changes.
>

+1

Not knowing that something didn't happen is a lot harder to diagnose -  
especially if it is out of sight.

And since I am not a developer I am loathed to add comments that  
require extra work.... but if it could be flagged as being abnormal,  
via some sort of conflict property, then that would also assist the  
end-user with making an informed decision about the resultant operation.

Gavin.

------------------------------------------------------
http://subversion.tigris.org/ds/viewMessage.do?dsForumId=462&dsMessageId=2373778

Re: operation based merging -- was: Re: svn commit: r38394 - in trunk/subversion: include libsvn_delta

Posted by Stefan Sperling <st...@elego.de>.
On Tue, Jul 21, 2009 at 03:34:36PM +0200, Neels Janosch Hofmeyr wrote:
> > [*] We end up merging "svn copy /branch/A /branch/B" from branch
> > to trunk as "svn copy /branch/B /trunk/B" while it should be
> > "svn copy /trunk/A /trunk/B" plus merging any additional textual edits
> > made in /branch/B since its inception into /trunk/B.
> > Right now, edits made to /trunk/A after branching do not make their
> > way into /trunk/B in the merge result, which is wrong since B is
> > supposed to be a copy of A on trunk, too, but ends up not being a copy
> > of /trunk/A. And it's even worse with moves because changes made to A
> > after branching just get dropped in <1.6. In 1.6 and beyond, we're
> > flagging a tree conflict on A, (local edit, incoming delete upon merge)
> > but we should be handling this automatically. And IIRC detecting this
> > case doesn't even work for directories right now.
> 
> whoa, stsp, you sometimes have a way of writing a really complicated example
> in one huge paragraph rant.

Your diagram sums it up nicely though :)

> I admittedly do not understand every detail in
> this one... but I do have a question:
> 
> 
> A  /trunk/A
>     |
>     |\_________svn copy ^/trunk ^/branch___________
>     |                                              \
> M  /trunk/A  (1)                                   |
>     |                                          svn copy A B
>     |                                          A+ /branch/B
>     |                                              |
>     |                                          M  /branch/B  (2)
>     |                                              |
>     |               <--- merge ---{                |
> A+ /trunk/B  (3)                                   |
> 
> 
> So you argue that (3) should contain *both* the edits (1) and (2), instead
> of just (2)? It seems to me that it is impossible to know whether a user
> wants that or not!

True, there is ambiguity. There is more than one way to merge this.
 
> I can imagine both cases:
>  - "What!? Why did it not merge the edits on /trunk/A (1)?"
>  - "What!? It included all the edits on /trunk/A (1) as well?"

Does it need to be configurable? I'd imagine that merging the
edits by default is a safe thing to do. Note that e.g. Mercurial
does this by default, so there is precedence.

> I would probably have been asking the latter, *not* expecting trunk/B to
> contain (1). So operation based merges would throw me off at first.

In a huge merge, it's easier to revert a textual edit you don't want,
and which you can see in svn diff, than to find an edit which should
have happened but didn't. And which you can't tell from svn diff so
it's easy to overlook -- you may see it as part of a file being deleted
but if it's a huge file who is going to bother checking every line
for things they want to keep in the copy?
 
> If I got it right and you're sure about it, it seems to me like this
> situation needs some kind of conflict resolu
>  * neels stops short.

We could flag a tree conflict and have the edits be applied
to the victim by default. Just like we currently schedule some
victims A+ by default to make it easy for people who want to keep
the victim. People who do not want to keep the A+ victim can just run
'svn revert victim' to unschedule it. People who do not want the
edits in the copy can just revert them. At least the edits have
been brought to their attention this way. And that's what Subversion
is supposed to do -- helping people with keeping track of changes.

Stefan