Thursday, 28 June 2007

subversion move/rename and branch merge problem

Fionn is reading writing books at the moment and I find myself trying to  express and craft a warning about svn. "We want to give instructions to people on how to avoid problems I think. (and not confuse them too much with details - keep the details for our reference) It's difficult to write something simple and yet cover the problem entirely! :)" - me

WARNING: Everyone should be cautious renaming or moving things in svn.

If someone is moving(or renaming)(or deleting) directories/files then all people working off of the same branch should be notified.  It would actually be best if all work was finished up and the move/rename done while there were as few other branches off of the same branch as possible. (as few as possible = zero! - :) ) If anyone has changes to files that are renamed or moved they should be aware that their changes will be lost by any merge.


Subversion rename/move is implemented as seperate Delete and Add and this means it is as if a new entity is added at the point the rename/move is comitted. Any changes to moved entities done in parallel (and comitted after move) will be merged out and lost.

A simplest example (not with branches/merge), but results in the same problem.
Essentially a directory move was committed.
Another user had edited the files in that directory.
When that user updated from trunk the file changes were "lost".

# mary edits file
"fudir/new-fu-file.c" 3 lines, 36 characters

mary$ svn status
M      fudir/new-fu-file.c

# Meanwhile Tom is reorganising stuff. (move dir and COMMIT)

tom$ svn mv fudir/ fu-moved/
A         fu-moved
D         fudir/new-fu-file.c
D         fudir

tom$ svn ci -m"mv fudir to fu-moved"
Deleting       fudir
Adding         fu-moved

Committed revision 12.

# Mary can see there are updates and she cannot commit until after update.

mary$ svn status
M      fudir/new-fu-file.c

mary$ svn status -u
       *            fu-moved/new-fu-file.c
       *            fu-moved
M              11   fudir/new-fu-file.c
       *       11   fudir
Status against revision:     12

mary$ svn ci -m"commit to file moved away by other checkout"
Sending        trunk
svn: Commit failed (details follow):
svn: Out of date: '/trunk' in transaction '12-1'

mary$ svn up
D    fudir
A    fu-moved
A    fu-moved/new-fu-file.c
Updated to revision 12.

# hey!  Mary's changes are not lost,
# but they are now unversioned and not in svn (still in fudir)
# and the fu-moved dir contains the new-fu-file.c version that was last seen by tom
# SO if they were part of many changes it would be easy to miss them
# the only clue to this problem is the "? fudir"

mary$ svn status -u
?                   fudir
Status against revision:     12

# The correct thing to do is for Mary to restore each of her changes by hand.
# Her svn status should as a general rule have the same number of Modified/Added/... files
#  before her checkin.
# She can copy in this case as there were no modifications to the file by Tom BUT
#  copying might be the wrong thing to do if there were changes.
#  (see svn manual Branching and Merging: Resurrecting Deleted Items)

mary$ cp fudir/new-fu-file.c fu-moved/

mary$ svn status -u
?                   fudir
M              12   fu-moved/new-fu-file.c
Status against revision:     13

mary$ svn ci -m"redo change to file after dir was moved"
Sending        trunk/fu-moved/new-fu-file.c
Transmitting file data .
Committed revision 14.

I'm very surprised this move problem is not in the manual or FAQ (or is it?)
svn manual: svn.c.move  svn.c.merge svn.branchmerge
I think it is covered in the manual:
 svn manual Branching and Merging: Resurrecting Deleted Items

This issue is documented in the wikipedia: (Current issues)
And in svn roadmap:
I guess this problem isn't an issue really unless a lot of parallel development and
branch/merging is being done as we are doing.
Anyway, I'm surprised it isn't highlighted more.

No comments: