blob: 57d77ad506b8547bcd90ce92736bac53de38a71c [file] [log] [blame]
-*- text -*-
TREE CONFLICTS USE CASES AND DESIRED BEHAVIOURS
Issue reference: https://issues.apache.org/jira/browse/SVN-2282
https://issues.apache.org/jira/browse/SVN-3630
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.
These notes were originally written during development of Subversion 1.6.
The original version focussed on detection of tree conflicts. The notes
have since been updated with behaviour changes up to Subversion 1.8.
Any 'desired behaviour' mentioned here is yet to be implemented.
--------------------------------------------------------------------------
==========
USE CASE 1
==========
Description
During an update, a file modification is merged onto a file move.
Behavior of Subversion <= 1.5
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 Behavior of Subversion <= 1.5
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 behavior of Subversion <= 1.5
(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)
Behaviour of Subversion >= 1.6
Foo.c will be deleted from B's working copy.
A tree conflict is signalled to inform B of the new changes to Bar.c,
so that B can review the modified Bar.c before committing it.
Behavior of Subversion >= 1.8
As above, a tree conflict is flagged on Foo.c.
When user B resolves the tree conflict on Foo.c, A's modifications
to Foo.c will be merged into Bar.c.
Text/Prop conflicts are signalled necessary.
Diagram of Behaviour of Subversion >= 1.8
(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.
Behavior of Subversion <= 1.5
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 behavior of Subversion <= 1.5
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 Behaviour of Subversion <= 1.5
(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)
Behavior of Subversion >= 1.6
When B updates, Bar.c is added to B's working copy, and a tree conflict
is flagged on Foo.c. B is expected to figure out that A renamed Foo.c
to Bar.c, and must resolve the conflict in some way before committing.
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.
Behavior of Subversion <= 1.5
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 behavior of Subversion <= 1.5
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 behavior of Subversion <= 1.5
(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
Behavior of Subversion >= 1.6
A tree conflict is signaled to inform B of the conflicting rename
operation. B can now decide on deleting either file or committing both.
Diagram of behavior of Subversion >= 1.6
(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
Problems with Behaviour of Subversion >= 1.6
The incoming move is labeled as 'incoming delete' in the tree
conflict description, rather than 'incoming move'. No assistance
is provided while resolving the tree conflict. Inexperienced users
are often unsure why the conflict occurred and don't know how to
proceed.
==========
USE CASE 4
==========
Description
A file modification is merged onto the source of a file move.
Behavior of Subversion <= 1.5
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 behavior of Subversion <= 1.5
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 behavior of Subversion <= 1.5
(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 ------ -->
Behavior of Subversion >= 1.6
A tree conflict is 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 Behaviour of Subversion >= 1.6
(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
Problems with Behaviour of Subversion >= 1.6
No assistance is provided while resolving the tree conflict.
Inexperienced users are often unsure why the conflict occurred
and don't know how to proceed.
Desired Behaviour
When user B merges, A's modifications to Foo.c should be merged into
Bar.c. Signal a text conflict if necessary.
==========
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.
Behavior of Subversion <= 1.5
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 behavior of Subversion <= 1.5
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 behavior of Subversion <= 1.5
(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'
Behavior Subversion >= 1.6
A tree conflict is signaled on Foo.c to inform B that Foo.c has been
renamed to Bar.c
Problems with Behaviour of Subversion >= 1.6
The incoming move is labeled as 'incoming delete' in the tree
conflict description, rather than 'incoming move'. No assistance
is provided while resolving the tree conflict. Inexperienced users
are often unsure why the conflict occurred and don't know how to
proceed.
Behavior of Subversion <= 1.8
Same as 1.6, but also for directories instead of just files.
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.
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.
Behavior of Subversion <= 1.5
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 behavior of Subversion <= 1.5
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 Behavior of Subversion <= 1.5
(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
Behavior of Subversion <= 1.6
A tree conflict is flagged on Foo.c in B's working copy.
Problems with Behaviour of Subversion >= 1.6
The incoming move is labeled as 'incoming delete' in the tree
conflict description, rather than 'incoming move'. No assistance
is provided while resolving the tree conflict. Inexperienced users
are often unsure why the conflict occurred and don't know how to
proceed.
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