blob: 3dcc11b45b620b79b80f99f2c8a9516090509754 [file] [log] [blame]
-*- text -*-
TREE CONFLICTS USE CASES AND DESIRED BEHAVIOURS
Issue reference: http://subversion.tigris.org/issues/show_bug.cgi?id=2282
(These use cases are based on a scenario paper "SVN move/rename
problems & suggested improvements" submitted by a corporate Subversion
user, which may be found attached to issue #2282.)
--------------------------------------------------------------------------
==========
USE CASE 1
==========
Description
During an update, a file modification is merged onto a file move.
Current Behavior
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
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
(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
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
(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
==========
Description
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
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
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
(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
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
(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
==========
Description
During an update, a file move is merged onto a conflicting file move.
Current Behavior
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
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
(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
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
(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
==========
USE CASE 4
==========
Description
A file modification is merged onto the source of a file move.
Current Behavior
Developer A modifies Foo.c and commits it to the repository.
Developer B moves Foo.c to Bar.c and commits it to the repository.
Developer B merges A's new revision into his working copy. The merge
will apply A's modification to Foo.c to the Foo.c in B's working
copy.
Problems With Current Behavior
First problem:
A's modification of Foo.c will not be merged to B's line of
development because the merge skips the absent file.
Second problem:
B is not explicitly warned about reverting A's modification of Foo.c,
except for a "skipped" warning in the output of the merge command,
which might not be noticed.
Diagram of current behavior
(edit)
urlA -- Foo.c' ------------------>
/ (r50) |
/ |
-- Foo.c - |merge -c50
\ |(Foo.c skipped)
\ |
urlB -- +Bar.c ------------|----------------->
(move) -Foo.c \ | ^
\ | |commit
\ v |(no-op)
wcB -- Bar.c -- Bar.c ------ -->
Desired behavior
When user B merges, A's modifications to Foo.c should be merged into
Bar.c. Signal a text conflict if necessary.
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
(edit)
urlA -- Foo.c' ------------------>
/ (r50) |
/ |
-- Foo.c - |merge -c50
\ |(tree conflict)
\ |
urlB -- +Bar.c -------------|-------------------- Bar.c' -->
(move) -Foo.c \ | ^ ^
\ | |commit |commit
\ v |(fails) |
wcB -- Bar.c -- Bar.c' --------------->
^
|
resolved
==========
USE CASE 5
==========
Description
A file move is merged onto a modification of the move-source.
This is essentially the same as Use Case 4, with the difference that
this time, B does the edit and A does the move.
Current Behavior
Developer A moves Foo.c to Bar.c and commits it to the repository.
Developer B modifies Foo.c and commits it to the repository.
Developer B merges A's new revision into his working copy. The merge
will add Bar.c (with the same content as the original Foo.c) and
will delete B's Foo.c.
Problems With Current Behavior
First problem:
B's has modified Foo.c in the past. This modification will be lost
unless B reviews the history of Foo.c and Bar.c at both URLs and
corrects the problem (e.g., via 'svn copy').
Diagram of current behavior
(move)
urlA -- +Bar.c ------------------->
/ -Foo.c |
/ (r50) |
-- Foo.c - |merge -c50
\ |
\ |
urlB -- Foo.c' -------------|------------ Bar.c --->
(edit) \ | ^
\ | |commit
\ v |
wcB -- Foo.c' -- +Bar.c ------>
-Foo.c'
Desired behavior
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
(move)
urlA -- +Bar.c ------------------->
/ -Foo.c |
/ (r50) |
-- Foo.c - |merge -c50
\ |(tree conflict)
\ |
urlB -- Foo.c' -------------|-------------------- Bar.c'-->
(edit) \ | ^ ^
\ | |commit |commit
\ v |(fails) |
wcB -- Foo.c' -- Bar.c' --------------->
-Foo.c' ^
|
resolved
==========
USE CASE 6
==========
Description
A file move is merged onto a conflicting file move.
Current Behavior
Developer A moves Foo.c to Bar.c and commits it to the repository.
Developer B moves Foo.c to Bix.c and commits it to the repository.
Developer B merges A's new revision into his working copy. The merge
will add Bar.c with history in B's working copy.
Problems With Current Behavior
After B's next commit, the content of the original Foo.c will exist
twice in the source tree under two different paths (Bar.c and
Bix.c). This may not have been intended.
Diagram of current behavior
(move)
urlA -- +Bar.c ------------------>
/ -Foo.c |
/ (r50) |
-- Foo.c - |merge -c50
\ |
\ |
urlB -- +Bix.c ------------|---------------- Bix.c --->
(move) -Foo.c \ | ^ Bar.c
\ | |commit
\ v |
wcB -- Bix.c -- Bix.c ---------->
+Bar.c
Desired behavior
A tree conflict should be signaled to inform B of the conflicting
rename operation. B can delete either file or commit both.
Diagram of desired behaviour
(move)
urlA -- +Bar.c ----------------->
/ -Foo.c |
/ (r50) |
-- Foo.c - |merge -c50
\ |(tree conflict)
\ |
urlB -- +Bix.c ------------|------------------------- Bar.c -->
(move) -Foo.c \ | ^ ^ (or Bix.c,
\ | |commit |commit or both)
\ v |(fails) |
wcB -- Bix.c -- Bix.c -------------->
+Bar.c ^
|
resolved