You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@subversion.apache.org by Julian Foad <ju...@btopenworld.com> on 2008/03/10 20:33:23 UTC

Tree conflicts - thoughts on use cases, merging, and tests

Stephen,

I'm thinking about all the different things a user can do (including renames 
and such like) and how the user can do these things in one branch, do other 
such things in another branch, and try to merge the two together. Then I'm 
thinking about how Subversion maps these many different user-level changes down 
onto a smaller set of delta-editor operations under the hood, and how that's 
the place where we're trying to detect conflicts having lost the information 
about the user's original intention.

This email doesn't have a conclusion, it's just me conveying my thought process 
in the hope that it will help us to communicate.


USE CASES

I have started by categorising all the user actions I can think of into four 
categories that reflect whether they delete and/or create an object. This is a 
list of all possible kinds of change to the file object at a particular path 
(or, for creation, about to live at that path). Listed below each kind of 
change are non-exhaustive examples of user-level actions that cause that change.

I'm not entirely sure that these four categories are the best way to split up 
the possibilities, but they are serving a useful purpose for me for the time being.

Kinds of change, and user-level actions that cause them:

   CREATE
     add (a new object without history)
     copy(+modify?) (from any object in any revision)
     move(+modify?) (from any object in the head revision)

   GO-AWAY
     delete
     move(+modify?) (to another name and/or into another dir)

   REPLACE
     replace with different kind (DELETE by any means, and CREATE by any means 
an object of the same name)
     replace with same kind (DELETE by any means, and CREATE by any means an 
object of the same name)
     revert (delete, and copy(+modify?) from this object's history - a special 
case of replace)

   MODIFY
     modify (any text and/or property mods including creation and deletion of 
properties)


Next I thought briefly about the behaviour I would expect when merging a pair 
of changes, and tabulated the results according to those four categories.

Desired behaviour for merging two modifications that each start from the same 
base (as in "svn update"):

   (For files)

     Action ... merged onto ... "Reason"
        |    |
        v    | CREATE  GO-AWAY REPLACE MODIFY
     ------- + ------- ------- ------- -------
     CREATE  |  C       X       X       X
             |
     GO-AWAY |  X       C       C       C
             |
     REPLACE |  X       C       C       C
             |
     MODIFY  |  X       C       C       ok

   C  = conflict (unless same change to same thing and policy allows it)
   X  = can't happen if branch was synchronised (so flag an error or a conflict)
   ok = merge in the obvious way


Summary of the kinds of change covered by the use cases 1 to 6:

   (For files)

     Action ... merged onto ... "Reason"
        |    |
        v    | CREATE  GO-AWAY REPLACE MODIFY
     ------- + ------- ------- ------- -------
     CREATE  |
             |
     GO-AWAY |         3,,6            2,,5
             |
     REPLACE |                         (7)
             |
     MODIFY  |         1,,4     (7)

   #,#,# = use case number for {update,switch,merge}

We talked about a "use case 7" involving replacement and modification; that 
needs splitting into separate use cases and formalising.

We ought to think through some more use cases to fill in the gaps, but I don't 
think it's critical to do that early. We can look at them later, and see if the 
implementation or the proposed design would do something sensible.


DIFFERENCE BETWEEN "UPDATE" AND "MERGE"

With "svn update", we are merging one CHANGE (described by a delta editor 
drive) against the base revision with another CHANGE (described by the WC's 
"schedule" information) against the same base revision. We are pretty clear 
about how to do this.

With "svn merge", are we attempting to merge the incoming CHANGE with an 
existing CHANGE in the target branch against some "base" (whatever that may 
be)? Or are we attempting to merge the incoming CHANGE onto a single tree that 
exists at a point in time, without regard to how that tree has changed?

I think the ultimate answer is the former: we can only do a good job of merging 
if we consider how the target branch has changed already. However, I wonder 
whether we are trying to do the latter (apply a change onto a single tree) and 
whether in fact that is good enough to get us the behaviour we want.


TESTS

I was looking at the Python tests in the tree-conflicts branch. It's great that 
you've already written tests.

I noticed that the test function "set_up_tree_conflicts()" claims to be setting 
up for use cases 1, 2 and 3, but it does so by using "delete" commands whereas 
the use cases call for "move". I know that a "move" and a "delete" will both 
get handled by the same code path in your implementation because they both 
contain a delta-editor "delete-file" command, but I think we should write the 
use-case tests to describe as accurately as possible the actual use cases. In 
addition, we can have tests for other similar and different actions that we 
think ought to trigger the conflict detection as well.

I don't know whether you even noticed there was this difference, but I want to 
make sure we don't accidentally end up testing only what we think we need to 
test and not what the user is going to try doing.


Regards,
- Julian

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: Tree conflicts - thoughts on use cases, merging, and tests

Posted by Nico Schellingerhout <ni...@philips.com>.
Stefan Sperling <st...@elego.de> wrote on 03/21/2008 01:39:40 PM:

> 
> By "true renames", I essentially mean that functionality you
> describe, but implemented in a manner that would make the client
> side trivial to implement. The biggest feature would be the
> editor function I mentioned, because it would unambiguously
> identify moves on the client side, without any logic necessary
> in the client to tell moves apart from deletes.

Ok, I'm glad to hear that.

> 
> But true renames a dream of course, and I don't really want to
> analyze the relationship between true renames and tree conflicts
> deeply. Doing so would be a waste of time for now since we already
> have a plan mapped out that does not require true renames.
> 
> >    The real problem appears to be twofold:
> >    (1) the fact that the client is not given the chance to do this,
> >    because
> >    the server omits the copy-from information for adds, leaving the
> >    client
> >    in the dark about the user intentions.
> >    (2) there is no API call "whereis", defined as follows:
> >      whereis(URL:rev, targetbranchURL:rev), tells you where a file
> >    identified by URL:rev (on a source branch, for example), can be
> >    found
> >    in the targetbranch (note: whereis may return [0:N] URLs because
> >    of
> >    possible cloning on the target branch). (Note that this requires
> >    the ability to search "forward" through the logs efficiently, a
> >    feature that Subversion does not provide right now AFAIK.)
> 
> Indeed, Subversion doesn't do that. As an aside, one of the first things
> I did with the Subversion code base was adding support for "copied-to"
> properties that simulated just that (all copied files got special 
properties
> stating where they got copied at which revisions). An elego client 
wanted
> the feature badly enough to fund its implementation, however it turns
> out it was never used in practice.
> 
> >    Now, I have no clue about performance impact of these extensions,
> >    and I
> >    may be missing ugly consequences, but to me this looks like a path
> >    worth investigating to not only detect and raise tree conflicts,
> >    but to
> >    handle them as well.
> >
> 
> Performance was quite good once the copied-to pointers were in place,
> but handling the insane amount of log output a query like "show me all
> logs for copies of a given file for all branches it was ever copied to"
> produces was quite a nuisance :)

Nice. We have developed a helper tool that crawls through the logs
to build a forward-referencing "cache" to help us determine whereis.

> 
> But I will keep this point in mind and may raise it in future design
> discussions when we'll try to get tree-conflicts to the next level.
> Right now it's out of scope.
> 
> >    Of course, for the initial phase of tree conflicts (raising
> >    conflicts,
> >    not resolving them), we will have to make do with what Subversion
> >    provides, and make the best of it.
> 
> Yes indeed.
> 
> >    However, I do not understand
> >    the
> >    point in detection.txt that the update editor would have to have
> >    the
> >    complete list of all adds with history just to _detect_ tree
> >    conflicts:
> >    UC1 and 3 are triggered simply by trying to change or delete an
> >    absent
> >    file. That should be enough to flag this as a tree conflict,
> >    right?
> 
> It is enough to flag tree conflicts, but at the moment we are also
> flagging double deletes of a file as a tree-conflict, even though
> that isn't a tree conflict. The list would be required to tell whether

I'm not so sure. Deleting a file that has already been deleted may be
'safe' in the sense that the second delete will not cause any problems
by itself, but I cannot help thinking that it is an indication of
'fishiness': The deletes either have the same intent behind them, in
which case the development team has a serious communication problem, or
have different intents, in which case further inspection is also
warranted. A version control tool complaining about double deletes may
be regarded by users as overly pedantic, but given the frequency of
double deletes (very rare), I would rather be warned, than be left
in the dark.

> there is a file that was added with history at all in the update, and
> also to relate this file to a file deleted by the update, searching
> copy-from info. Only then we could be certain whether a delete was due
> to a move operation or not.
> 
> Essentially, the rant in detection.txt is the result of me and my
> colleague Neels sitting down for a whole evening trying to determine
> how we could eliminate all false positives in tree-conflict detection,
> and discovering that it is impossible to do so with the current design.

Ok. Let me just reiterate the point that the false-positive rate for
this use case is low, simply because the use case itself pops up
very rarely (drawing on experience with a long-living archive with a
constant stream of refactoring involving moves going on).

> 
> Does the point make sense to you now? Should I update that section
> of the file to make its background more clear?

Some clarification may be in order: the analysis is based on the
assumption that merging "move a b" onto "move a b" is safe, and that
merging "move a b" onto "move a c" is not. Now, anyone would agree to
the second part, but the first may be debatable (similar arguments
as for double deletes).

The trouble with merging is that (in my opinion) there is no absolute
"truth": whenever you merge, you are making assumptions on what has
happened/was intended, and different assumptions will lead to different
results.

In this case, the more "pedantic" behaviour is much easier to implement,
is safer, and leads to false positives rarely, so to me that seems to
be the way forward.

Happy Easter,

Nico
 

Re: Tree conflicts - thoughts on use cases, merging, and tests

Posted by Stefan Sperling <st...@elego.de>.
[Nico, sorry, you are getting this twice. I forgot to Cc the list
in my original reply.]

On Thu, Mar 20, 2008 at 08:58:27PM +0100, Nico Schellingerhout wrote:
>    Stefan Sperling <st...@elego.de> wrote on 03/11/2008 09:28:40 AM:
> 
>    > Hey Nico,
>    >
>    > On Tue, Mar 11, 2008 at 01:48:09AM +0100, Nico Schellingerhout
>    wrote:
>    > >    I agree, a move should be treated as a first class citizen:
>    for
>    > >    detecting
>    > >    conflicts it doesn't matter, but for resolving them
>    > >    (semi)automatically, it
>    > >    does.
>    >
>    > It does matter for detection. Detection would be much, much
>    > easier already if we had an update editor callback like
>    >   move_file(source, target);
>    >
>    > See the section "TREE CONFLICT DETECTION WITH TRUE RENAMES" in
>    >
>    http://svn.collab.net/repos/svn/trunk/notes/tree-conflicts/detection.txt
>    I have read through the section you mentioned, and I am not sure
>    what you mean by "true renames".

By "true renames", I essentially mean that functionality you
describe, but implemented in a manner that would make the client
side trivial to implement. The biggest feature would be the
editor function I mentioned, because it would unambiguously
identify moves on the client side, without any logic necessary
in the client to tell moves apart from deletes.

But true renames a dream of course, and I don't really want to
analyze the relationship between true renames and tree conflicts
deeply. Doing so would be a waste of time for now since we already
have a plan mapped out that does not require true renames.

>    The real problem appears to be twofold:
>    (1) the fact that the client is not given the chance to do this,
>    because
>    the server omits the copy-from information for adds, leaving the
>    client
>    in the dark about the user intentions.
>    (2) there is no API call "whereis", defined as follows:
>      whereis(URL:rev, targetbranchURL:rev), tells you where a file
>    identified by URL:rev (on a source branch, for example), can be
>    found
>    in the targetbranch (note: whereis may return [0:N] URLs because
>    of
>    possible cloning on the target branch). (Note that this requires
>    the ability to search "forward" through the logs efficiently, a
>    feature that Subversion does not provide right now AFAIK.)

Indeed, Subversion doesn't do that. As an aside, one of the first things
I did with the Subversion code base was adding support for "copied-to"
properties that simulated just that (all copied files got special properties
stating where they got copied at which revisions). An elego client wanted
the feature badly enough to fund its implementation, however it turns
out it was never used in practice.

>    Now, I have no clue about performance impact of these extensions,
>    and I
>    may be missing ugly consequences, but to me this looks like a path
>    worth investigating to not only detect and raise tree conflicts,
>    but to
>    handle them as well.
>

Performance was quite good once the copied-to pointers were in place,
but handling the insane amount of log output a query like "show me all
logs for copies of a given file for all branches it was ever copied to"
produces was quite a nuisance :)

But I will keep this point in mind and may raise it in future design
discussions when we'll try to get tree-conflicts to the next level.
Right now it's out of scope.

>    Of course, for the initial phase of tree conflicts (raising
>    conflicts,
>    not resolving them), we will have to make do with what Subversion
>    provides, and make the best of it.

Yes indeed.

>    However, I do not understand
>    the
>    point in detection.txt that the update editor would have to have
>    the
>    complete list of all adds with history just to _detect_ tree
>    conflicts:
>    UC1 and 3 are triggered simply by trying to change or delete an
>    absent
>    file. That should be enough to flag this as a tree conflict,
>    right?

It is enough to flag tree conflicts, but at the moment we are also
flagging double deletes of a file as a tree-conflict, even though
that isn't a tree conflict. The list would be required to tell whether
there is a file that was added with history at all in the update, and
also to relate this file to a file deleted by the update, searching
copy-from info. Only then we could be certain whether a delete was due
to a move operation or not.

Essentially, the rant in detection.txt is the result of me and my
colleague Neels sitting down for a whole evening trying to determine
how we could eliminate all false positives in tree-conflict detection,
and discovering that it is impossible to do so with the current design.

Does the point make sense to you now? Should I update that section
of the file to make its background more clear?

-- 
Stefan Sperling <st...@elego.de>                 Software Developer
elego Software Solutions GmbH                            HRB 77719
Gustav-Meyer-Allee 25, Gebaeude 12        Tel:  +49 30 23 45 86 96 
13355 Berlin                              Fax:  +49 30 23 45 86 95
http://www.elego.de                 Geschaeftsfuehrer: Olaf Wagner

Re: Tree conflicts - thoughts on use cases, merging, and tests

Posted by Nico Schellingerhout <ni...@philips.com>.
Stefan Sperling <st...@elego.de> wrote on 03/11/2008 09:28:40 AM:

> Hey Nico,
> 
> On Tue, Mar 11, 2008 at 01:48:09AM +0100, Nico Schellingerhout wrote:
> >    I agree, a move should be treated as a first class citizen: for
> >    detecting
> >    conflicts it doesn't matter, but for resolving them
> >    (semi)automatically, it
> >    does.
> 
> It does matter for detection. Detection would be much, much
> easier already if we had an update editor callback like
>   move_file(source, target);
> 
> See the section "TREE CONFLICT DETECTION WITH TRUE RENAMES" in
> http://svn.collab.net/repos/svn/trunk/notes/tree-conflicts/detection.txt

Hi Stefan,

I have read through the section you mentioned, and I am not sure what
you mean by "true renames". The way I see it is that Subversion has all
the concepts in place to achieve what we want. By simply inspecting
logs on source and target branches, it is perfectly possible (albeit very
expensive, currently) to trace the location and a name of the file, and
unambiguously correlate a file in the source branch to a corresponding
file in the target branch (there are exceptions: a file could be cloned
on the target branch, but that could be considered a corner case, for
which tool-support is less strong). This is actually what our integrators
are doing now by hand on a daily basis to resolve "tree conflicts"
(quoted because the "tree conflict" concept does not exist as such in a
Subversion release yet).

The real problem appears to be twofold:
(1) the fact that the client is not given the chance to do this, because
the server omits the copy-from information for adds, leaving the client
in the dark about the user intentions.
(2) there is no API call "whereis", defined as follows:
  whereis(URL:rev, targetbranchURL:rev), tells you where a file 
identified by URL:rev (on a source branch, for example), can be found
in the targetbranch (note: whereis may return [0:N] URLs because of
possible cloning on the target branch). (Note that this requires
the ability to search "forward" through the logs efficiently, a
feature that Subversion does not provide right now AFAIK.)

If (1) and (2) were there, the client could - in principle - replay
"moves" on the source branch to corresponding "moves" on the target
branch. Note that (1) and (2) do not require additional metadata to
be stored in the server (true renames would require that, I guess),
Subversion would just be using the metadata it keeps more "smartly"
to implement the simple heuristic of
   "delete with associated add-with-history constitutes a move"

Now, I have no clue about performance impact of these extensions, and I
may be missing ugly consequences, but to me this looks like a path
worth investigating to not only detect and raise tree conflicts, but to
handle them as well.

Of course, for the initial phase of tree conflicts (raising conflicts,
not resolving them), we will have to make do with what Subversion
provides, and make the best of it. However, I do not understand the
point in detection.txt that the update editor would have to have the
complete list of all adds with history just to _detect_ tree conflicts:
UC1 and 3 are triggered simply by trying to change or delete an absent
file. That should be enough to flag this as a tree conflict, right?

- Nico

Re: Tree conflicts - thoughts on use cases, merging, and tests

Posted by Stefan Sperling <st...@elego.de>.
Hey Nico,

On Tue, Mar 11, 2008 at 01:48:09AM +0100, Nico Schellingerhout wrote:
>    I agree, a move should be treated as a first class citizen: for
>    detecting
>    conflicts it doesn't matter, but for resolving them
>    (semi)automatically, it
>    does.

It does matter for detection. Detection would be much, much
easier already if we had an update editor callback like
  move_file(source, target);

See the section "TREE CONFLICT DETECTION WITH TRUE RENAMES" in
http://svn.collab.net/repos/svn/trunk/notes/tree-conflicts/detection.txt

Great to see you posting by the way. I don't have time to follow
this discussion thoroughly right now, but starting next week
I will have time to catch up and participate more actively again.

See you,
-- 
Stefan Sperling <st...@elego.de>                 Software Developer
elego Software Solutions GmbH                            HRB 77719
Gustav-Meyer-Allee 25, Gebaeude 12        Tel:  +49 30 23 45 86 96 
13355 Berlin                              Fax:  +49 30 23 45 86 95
http://www.elego.de                 Geschaeftsfuehrer: Olaf Wagner

Re: Tree conflicts - thoughts on use cases, merging, and tests

Posted by Nico Schellingerhout <ni...@philips.com>.
Julian Foad <ju...@btopenworld.com> wrote on 03/10/2008 09:33:23 PM:

> Stephen,
> 
> I'm thinking about all the different things a user can do (including 
renames 
> and such like) and how the user can do these things in one branch, do 
other 
> such things in another branch, and try to merge the two together. Then 
I'm 
> thinking about how Subversion maps these many different user-level 
> changes down 
> onto a smaller set of delta-editor operations under the hood, and how 
that's 
> the place where we're trying to detect conflicts having lost the 
information 
> about the user's original intention.
> 
> This email doesn't have a conclusion, it's just me conveying my 
> thought process 
> in the hope that it will help us to communicate.
> 
> 
> USE CASES
> 
> I have started by categorising all the user actions I can think of into 
four 
> categories that reflect whether they delete and/or create an object.This 
is a 
> list of all possible kinds of change to the file object at a particular 
path 
> (or, for creation, about to live at that path). Listed below each kind 
of 
> change are non-exhaustive examples of user-level actions that cause 
> that change.
> 
> I'm not entirely sure that these four categories are the best way 
tosplit up 
> the possibilities, but they are serving a useful purpose for me for 
> the time being.
> 
> Kinds of change, and user-level actions that cause them:
> 
>    CREATE
>      add (a new object without history)
>      copy(+modify?) (from any object in any revision)
>      move(+modify?) (from any object in the head revision)
> 
>    GO-AWAY
>      delete
>      move(+modify?) (to another name and/or into another dir)
> 
>    REPLACE
>      replace with different kind (DELETE by any means, and CREATE byany 
means 
> an object of the same name)
>      replace with same kind (DELETE by any means, and CREATE by any 
means an 
> object of the same name)
>      revert (delete, and copy(+modify?) from this object's history -a 
special 
> case of replace)
> 
>    MODIFY
>      modify (any text and/or property mods including creation and 
deletion of 
> properties)
> 
> 
> Next I thought briefly about the behaviour I would expect when merging a 
pair 
> of changes, and tabulated the results according to those four 
categories.
> 
> Desired behaviour for merging two modifications that each start fromthe 
same 
> base (as in "svn update"):
> 
>    (For files)
> 
>      Action ... merged onto ... "Reason"
>         |    |
>         v    | CREATE  GO-AWAY REPLACE MODIFY
>      ------- + ------- ------- ------- -------
>      CREATE  |  C       X       X       X
>              |
>      GO-AWAY |  X       C       C       C
>              |
>      REPLACE |  X       C       C       C
>              |
>      MODIFY  |  X       C       C       ok
> 
>    C  = conflict (unless same change to same thing and policy allows it)
>    X  = can't happen if branch was synchronised (so flag an error or
> a conflict)
>    ok = merge in the obvious way
> 
> 
> Summary of the kinds of change covered by the use cases 1 to 6:
> 
>    (For files)
> 
>      Action ... merged onto ... "Reason"
>         |    |
>         v    | CREATE  GO-AWAY REPLACE MODIFY
>      ------- + ------- ------- ------- -------
>      CREATE  |
>              |
>      GO-AWAY |         3,,6            2,,5
>              |
>      REPLACE |                         (7)
>              |
>      MODIFY  |         1,,4     (7)
> 
>    #,#,# = use case number for {update,switch,merge}

Julian, Steven,

Thanks for the write ups. I have interpreted the tables as "what should
happen if an action of type 1 is merged onto an action of type 2". 
However, I don't think there is a difference between GO-AWAY and REPLACE
when used purely in this way. The difference between the two is slightly
more subtle: it involves taking the history on a branch into account.

> 
> We talked about a "use case 7" involving replacement and modification; 
that 
> needs splitting into separate use cases and formalising.

Actually, I think UC7, which I raised earlier off-list, and that we 
discussed
earlier over the phone is different from what you indicate:

UC7 can be read in your notation as:

"MODIFY merged onto a file that has been REPLACEd in an not-yet merged
change on either branch"

As far as I can see this case does not present new problems for update:
1. There has been a REPLACE and a MODIFY in two different revisions on
the archive. Updating should pull these changes in consecutively and
there should not be a conflict.
2. There has been a REPLACE on the archive, and a local MODIFY. Update
reduces to UC2 (merge a move onto a modified file).
3. There has been a MODIFY on the archive, and a local REPLACE. Update
reduces to UC1 (merge a modification on to a file being moved away).

However, there are problems for merging between branches:
1. There has been a REPLACE and a MODIFY in two different revisions on
the source branch. Merging should pull these changes in consecutively and
there should not be a conflict.
2a. There has been a REPLACE on the source branch, and a MODIFY on the 
target.
Merging the REPLACE onto the source reduces to UC5.
2b. There has been a REPLACE and a MODIFY on the source branch.
Merging the MODIFY is a new case:

          r1      r2       r3            r4
             x->a   edit x    merge r2:3
source:   x(x)    a(x)     a(x')
          a(a)

target:   x(x)    x(x)     x(x)          x(x')    OR?    x(x)
          a(a)    a(a)     a(a)          a(x)            a(x')

Notation: f(x) is a file with name "f" and contents "x". Files with the
same "identity" are written on the same line.

It is not easy to determine the right behaviour here. (I would favour
the first of the two options, because one could merge r1:2 later on and
would end up with two identical branches, which would be a good thing.)
The user could be warned to make the right call.

3. There has been a MODIFY on the source branch, and a REPLACE on target.
Merging the MODIFY onto the target is a new use case:

          r1      r2       r3            r4
                     edit a    merge r2:3
source:   x(x)    x(x)     x(x)
          a(a)    a(a)     a(a')

             x->a
target:   x(x)    a(x)     a(x)          a(x)   OR?    a(a')
          a(a)

It is not easy to determine the right behaviour here. (I would favour the
first of the two options, because merging r1:2 from target to source
would bring both branches into sync.) 
The user could be warned to make the right call.

The problem with cases 2b and 3 is that the detection that works for all
other cases (seeing that a modify is to be merged onto a file that is
scheduled for deletion or is not there at all, or merging a delete on a
file that differs from the file being deleted), does not work here:
this is the perfectly "normal" case of a textual change being
merged on top of a file that does exist.

The only way to determine that these cases are actually conflicts (or at
the very least require special treatment) is to take the complete history
of the pair of files to be merged into account and determine if they share
a common history.

In case 2b a(x') on source and a(a) on target do not share a history,
because they started out as x(x) and a(a), respectively.

In case 3 a(a') on source and a(x) on target do not share a history,
because they started out as a(a) and x(x), respectively.

Some final remarks on UC4-6:
----------------------------

UC4:
----
In my opinion UC4 is obviously a tree conflict: you are trying to merge
a change onto a file that does not exist in the target branch. Something
weird must be going on (a tree conflict).

UC5: (move merged onto a file that has some changes in the target branch)
---
The condition for a conflict here could be that the file in the target
branch differs from the file in the source branch just before the delete.
However, this condition is only necessary because Subversion treats such
a merge as a copy from source to target, completely ignoring the
content of the original file on the target branch.

A better merge algorithm would be:
1. If the corresponding file on target exists (and shares a history),
perform the move on the target branch (instead of modeling it as a copy
from the source branch).
2. Merge the optional changes that may be in the same revision onto the
moved file on the target branch.

Example:
source/x(x) -> source/y(x') (arrow indicates a D/A+ pair)

Should be merged onto x(x'') as follows:

target/x(x'') -> target/y(x''') [where x''' stands for the textual merge 
of
delta(x,x') onto x'']

Instead of the current behaviour:

source/y(x') -> target/y(x')

Note that this requires the merge algorithm to "understand" how to
translate source/x(x) -> source/y(x) to target/x(x) -> target/y(x).
This is trivial if it is just a rename in the same directory, but more
complex if it is a move across directories (the destination directory
on the target may differ from the destination directory on the source).
Again, the notion of sharing history is crucial here, but here the
identity of the target parent directory is involved.

UC6: again, obviously always a tree conflict.
---

[...]
> TESTS
> 
> I was looking at the Python tests in the tree-conflicts branch. It's
> great that 
> you've already written tests.
> 
> I noticed that the test function "set_up_tree_conflicts()" claims to
> be setting 
> up for use cases 1, 2 and 3, but it does so by using "delete" 
> commands whereas 
> the use cases call for "move". I know that a "move" and a "delete" will 
both 
> get handled by the same code path in your implementation because they 
both 
> contain a delta-editor "delete-file" command, but I think we should 
write the 
> use-case tests to describe as accurately as possible the actual use 
cases. In 
> addition, we can have tests for other similar and different actions that 
we 
> think ought to trigger the conflict detection as well.

I agree, a move should be treated as a first class citizen: for detecting
conflicts it doesn't matter, but for resolving them (semi)automatically, 
it
does.

Just my 2 cts.

- Nico