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

tree conflict use cases

From: Stefan Sperling <stsp_at_elego.de>
Date: 2007-10-24 20:58:28 CEST

Hello list,

does anybody feel a twitch in their tummy when I say "tree conflicts"?

If you don't know what I'm talking about, see here for the longest
mailing list thread we could find on the issue:
http://subversion.tigris.org/servlets/BrowseList?list=dev&by=thread&from=362008

And see here for the corresponding issue #2282, "handle file
delete/edit/add conflicts: tree changes and conflicts":
http://subversion.tigris.org/issues/show_bug.cgi?id=2282

The problem is still unsolved, and hinders adoption of Subversion in at
least one corporate environment we know of. It especially presents a
major hassle for people who do a lot of refactoring, but even if you
don't do a lot of that you may run into the issue sooner or later.

We have funding, good relations to CollabNet and are willing to throw
developers at the problem. "We" is elego, a company based in Berlin,
Germany. Some of you may have met us at SubConf 2007. See
http://www.elego.de if you are interested in who we are and what we do.

We'd like to propose the use cases below as a basis for further design
discussion, with the goal of fixing the tree conflicts problem in time
for Subversion 1.6.

The use cases are based on a scenario paper "SVN move/rename problems &
suggested improvements" submitted by a corporate Subversion user.

The paper has been attached to issue 2282 by Michael Pilato, (see
"Additional comments from C. Michael Pilato Tue Oct 23 07:15:06 -0700
2007"), and is in PowerPoint format. We have converted and adapted the
diagrams in the original paper into ASCII for your convenience so you
can easily view them in your mail reader. It really helps to be able to
continuously refer to the diagrams while reading the use case
descriptions. We've also rephrased the use case descriptions to try to
make them as accessible as possible.

As a first step, we concern ourselves with the first three of the six
use cases described in the paper. We plan to handle the remaining three
use cases later.

We still recommend viewing the original paper if possible as an
additional source of information. But note that in our description, we
have modified the use cases in the paper so that developer A always
commits first, and developer B always has to clean up the conflicts. In
our opinion this makes it easier to think about the different use cases
consistently and how they relate to one another.

We have reproduced the behaviour described in each use case with the
current trunk. (I personally think that writing recipes for these use
cases is a great way to learn about them.) We also have cmdline test
cases reflecting the current trunk behavior.

We're open to any kind of questions, criticism and suggestions you may
have. Feel free to reply inline inside the use case descriptions.
Thanks for your time, it is appreciated :)

Regards,
Steve Butler <sbutler@elego.de>
Stefan Sperling <stsp@elego.de>

= Use Case Descriptions =

== Use Case 1 ==

During an update, a file modification is merged onto a file move.

=== Current behavior UC 1 ===

Developer A modifies Foo.c and commits it to the repository.

Developer B has simultaneously moved Foo.c to Bar.c in his working
copy.

B cannot commit because the working copy is out of date, so B runs 'svn
update'. The update will apply A's modifications to Foo.c in the
repository to Foo.c in B's working copy.

=== Problems with current behavior UC 1 ===

First problem:

A's modification of Foo.c will effectively be reverted by B's new
revision. Foo.c will be deleted in the new revision, and Bar.c will be
added with the content of the original Foo.c before A's modifications.
Hence A will likely get angry with B.

Second problem:

B is not explicitly warned about reverting A's modification of Foo.c.
The only visible warning is that Foo.c is left behind unversioned in
B's working copy because it has "local" modifications (which were in
fact made by A). This will likely escape B's attention.

=== Diagram of current behavior UC 1 ===

            (edit)
  wcA -- Foo.c' ------->
              / |
             / |commit
  repos / v
  -- Foo.c -------------- Foo.c' --------------- Bar.c --->
            \ | ^
             \ |update |commit
              \ v |
  wcB -- +Bar.c ---------- +Bar.c ---- Bar.c --->
           (move) -Foo.c -Foo.c' ?Foo.c' (unversioned)

=== Desired behavior UC 1 ===

When user B updates, A's modifications to Foo.c should be merged into
Bar.c. Signal a text conflict if necessary.

Foo.c should be deleted from B's working copy.

A tree conflict should be signalled to inform B of the new changes
to Bar.c, so that B can review the modified Bar.c before committing it.

=== Diagram of desired behaviour UC 1 ===

            (edit)
  wcA -- Foo.c' ------->
              / |
             / |commit
  repos / v
  -- Foo.c --------------- Foo.c' ------------------------ Bar.c' --->
            \ | ^ ^
             \ |update |commit |commit
              \ v |(fails) |
  wcB -- +Bar.c ------------ +Bar.c' -------------->
           (move) -Foo.c -Foo.c ^
                                                      |
                                                   resolved

== Use Case 2 ==

During an update, a file move is merged onto a file modification.

This is essentially the same as Use Case 1, with the difference that
this time, B does the edit and A does the move.

=== Current behavior UC 2 ===

Developer B modifies Foo.c in his working copy.

Developer A has simultaneously moved Foo.c to Bar.c and commits
the move to the repository.

B cannot commit because his working copy is out of date, so B runs
'svn update'. The next update will add Bar.c (with the same content
as the original Foo.c) to B's working copy, and delete Foo.c from
B's working copy. Since B made local modifications to Foo.c,
it will not be deleted from disk but left behind unversioned.

=== Problems with current behavior UC 2 ===

Developer B may not notice that Foo.c fell out of version control.
B's source tree in the working copy likely builds fine because
Foo.c is still present on disk.
So B may commit an incomplete change set, possibly breaking the tree.
Everybody will get angry with B if this happens.

=== Diagram of current behaviour UC 2 ===

            (move)
  wcA -- +Bar.c ------->
              / -Foo.c |
             / |commit
  repos / v
  -- Foo.c --------------- Bar.c ----------------------->
            \ | ^
             \ |update |commit
              \ v |(no-op)
  wcB -- Foo.c' ------------ Bar.c ------->
           (edit) ?Foo.c' (unversioned)

=== Desired behavior UC 2 ===

In B's working copy, the update should add Bar.c and merge the local
modifications to Foo.c into Bar.c. Signal a text conflict if necessary.

Foo.c should be deleted from B's working copy.

A tree conflict should be signaled to inform B that Foo.c has been
renamed to Bar.c

=== Diagram of desired behaviour UC 2 ===

            (move)
  wcA -- +Bar.c ------->
              / -Foo.c |
             / |commit
  repos / v
  -- Foo.c --------------- Bar.c -------------------------- Bar.c'--->
            \ | ^ ^
             \ |update |commit |commit
              \ v |(fails) |
  wcB -- Foo.c' ------------+Bar.c' ------------------------>
           (edit) -Foo.c ^
                                                       |
                                                    resolved

== Use Case 3 ==

During an update, a file move is merged onto a conflicting file move.

=== Current behavior UC 3 ===

Developer A moves Foo.c to Bar.c and commits the move to the repository.

Developer B has moved Foo.c to Bix.c in his working copy.

B cannot commit because his working copy is out of date, so B runs
'svn update'. The update will add Bar.c to B's working copy and
delete Foo.c from B's working copy (the latter is a no-op).

=== Problems with current behavior UC 3 ===

After B's next commit, the content of the original Foo.c
will exist twice in the source tree under two different paths,
namely Bar.c and Bix.c, respectively.

This may not have been intended.

=== Diagram of current behavior UC 3 ===

           (move)
  wcA -- +Bar.c ------>
              / -Foo.c |
             / |commit
  archive / v
  -- Foo.c --------------- Bar.c ------------------ Bar.c --->
            \ | ^ Bix.c
             \ |update |commit
              \ v |
  wcB -- +Bix.c ---------- +Bix.c ------->
           (move) -Foo.c Bar.c

=== Desired behavior UC 3 ===

A tree conflict should be signaled to inform B of the conflicting rename
operation. B can now decide on deleting either file or committing both.

=== Diagram of desired behavior UC 3 ===

           (move)
  wcA -- +Bar.c ------>
              / -Foo.c |
             / |commit
  archive / v
  -- Foo.c --------------- Bar.c -------------------------- Bar.c -->
            \ | ^ ^ (or Bix.c,
             \ |update |commit |commit or both)
              \ v |(fails) |
  wcB -- +Bix.c ---------- +Bix.c -------------->
           (move) -Foo.c Bar.c ^
                                                  |
                                               resolved

-- 
Stefan Sperling <stsp@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

  • application/pgp-signature attachment: stored
Received on Wed Oct 24 20:58:47 2007

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