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

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

From: Julian Foad <julianfoad_at_btopenworld.com>
Date: Mon, 10 Mar 2008 20:33:23 +0000

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_at_subversion.tigris.org
For additional commands, e-mail: dev-help_at_subversion.tigris.org
Received on 2008-03-10 21:33:39 CET

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