A sane way to rename a directory in subversion working copy
While somehow versed in VCS (regular svn, git and git-svn user) I can't seem to wrap my head around this peculiar SVN behav开发者_StackOverflowior.
Whenever I need to rename a directory in my SVN working copy from an otherwise 'clean' state - i.e svn status
returns nothing and all other modifications have been commited - like so (which is what the svn doc suggests):
svn mv foo bar
svn commit
SVN complains loudly:
Adding bar
Adding bar/toto
Deleting foo
svn: Commit failed (details follow):
svn: Item '/test/foo' is out of date
As you wish:
svn update
Which gives:
C foo
At revision 46.
Summary of conflicts:
Tree conflicts: 1
There's a tree conflict, while no third-party change happened. Obviously, the only way to get out of this tree conflict mess is generically (from the svn red book):
svn resolve --accept working -R .
svn commit
Renaming it remotely on the repo then updating my working copy seems quite braindead:
url=$(svn info | grep -e '^URL:' | sed 's/^URL: //') svn mv $url/foo $url/bar
svn update
Is there a sanctioned, more streamlined way to rename a folder that I'm missing? What is the root cause behind that particularly surprising tree conflict state?
svn mv
works for me:
C:\svn\co>svn mv my_dir new_dir
A new_dir
D my_dir\New Text Document.txt
D my_dir
C:\svn\co>svn commit -m foo
Raderar my_dir
Lägger till new_dir
Arkiverade revision 2.
C:\svn\co>
Sorry for the Swedish output of svn.
There must be something else that is wrong in your case.
Edit:
As pointed out in the comments by Lloeki
To reproduce the behavior you also need to update and commit a file contained in the folder, but not update the folder itself.
file commit creates a new rev n on the repo, but local metadata is not updated (as it has always be, see svn log after any commit) , thus dir metadata is at rev n-1. It follows that svn won't commit because of the metadata diff, and it won't update because there's indeed a conflict on the dir: update metadata vs delete.
The behavior is "expected" and the "solution" is to update the working copy before issuing the svn rename
command.
OK, I bumped into this - and can finally reconstruct the problem with a simple terminal session: the problem happens if you svn mv
(move/rename) a file; then commit that change; then (without doing an svn update
first), svn mv
the parent directory of the file whose move/rename was previously committed - and finally do an svn commit
on the change of the directory name - or as accepted answer puts it: "you also need to update and commit a file contained in the folder, but not update the folder itself"; but all of this executed in a parent (or rather, ancestor) directory. Here's command line log demonstrating the problem:
$ cd /tmp
$ svnadmin create myrepo
$ svn co file:///tmp/myrepo myrepo-wc
Checked out revision 0.
$ cd myrepo-wc/
$ mkdir -p dir1/dir2/dir3
$ svn add dir1/
A dir1
A dir1/dir2
A dir1/dir2/dir3
$ svn ci -m 'add dir1/'
Adding dir1
Adding dir1/dir2
Adding dir1/dir2/dir3
Committed revision 1.
$ echo test1 >> dir1/dir2/dir3/test1.txt
$ echo test2 >> dir1/dir2/dir3/test2.txt
$ svn add dir1/
svn: warning: 'dir1' is already under version control
$ svn add dir1/*
svn: warning: 'dir1/dir2' is already under version control
$ svn add dir1/dir2/dir3/*
A dir1/dir2/dir3/test1.txt
A dir1/dir2/dir3/test2.txt
$ svn status
A dir1/dir2/dir3/test2.txt
A dir1/dir2/dir3/test1.txt
$ svn ci -m 'add dir1/dir2/dir3/*'
Adding dir1/dir2/dir3/test1.txt
Adding dir1/dir2/dir3/test2.txt
Transmitting file data ..
Committed revision 2.
$ svn mv dir1/dir2/dir3/test2.txt dir1/dir2/dir3/test2X.txt
A dir1/dir2/dir3/test2X.txt
D dir1/dir2/dir3/test2.txt
$ svn status
D dir1/dir2/dir3/test2.txt
A + dir1/dir2/dir3/test2X.txt
$ svn ci -m 'mv dir1/dir2/dir3/test2.txt dir1/dir2/dir3/test2X.txt'
Deleting dir1/dir2/dir3/test2.txt
Adding dir1/dir2/dir3/test2X.txt
Committed revision 3.
$ svn status
$ svn mv dir1/dir2/dir3 dir1/dir2/dir3X
A dir1/dir2/dir3X
D dir1/dir2/dir3/test2X.txt
D dir1/dir2/dir3/test1.txt
D dir1/dir2/dir3
$ svn status
D dir1/dir2/dir3
D dir1/dir2/dir3/test2X.txt
D dir1/dir2/dir3/test1.txt
A + dir1/dir2/dir3X
D + dir1/dir2/dir3X/test2.txt
$ svn ci -m 'mv dir1/dir2/dir3 dir1/dir2/dir3X'
Deleting dir1/dir2/dir3
svn: Commit failed (details follow):
svn: Directory '/dir1/dir2/dir3' is out of date
$ svn status
D dir1/dir2/dir3
D dir1/dir2/dir3/test2X.txt
D dir1/dir2/dir3/test1.txt
A + dir1/dir2/dir3X
D + dir1/dir2/dir3X/test2.txt
$ svn up
C dir1/dir2/dir3
At revision 3.
Summary of conflicts:
Tree conflicts: 1
And this is how it should have been - doing an svn up
after the file move/rename was comitted; note how the version numbers reported by svn status -v
change after the svn update
command:
$ cd /tmp
$ rm -rf myrepo*
$ svnadmin create myrepo
$ svn co file:///tmp/myrepo myrepo-wc
Checked out revision 0.
$ cd myrepo-wc/
$ mkdir -p dir1/dir2/dir3
$ svn add dir1/
A dir1
A dir1/dir2
A dir1/dir2/dir3
$ svn ci -m 'add dir1/'
Adding dir1
Adding dir1/dir2
Adding dir1/dir2/dir3
Committed revision 1.
$ echo test1 >> dir1/dir2/dir3/test1.txt
$ echo test2 >> dir1/dir2/dir3/test2.txt
$ svn add dir1/dir2/dir3/*
A dir1/dir2/dir3/test1.txt
A dir1/dir2/dir3/test2.txt
$ svn status
A dir1/dir2/dir3/test2.txt
A dir1/dir2/dir3/test1.txt
$ svn ci -m 'add dir1/dir2/dir3/*'
Adding dir1/dir2/dir3/test1.txt
Adding dir1/dir2/dir3/test2.txt
Transmitting file data ..
Committed revision 2.
$ svn mv dir1/dir2/dir3/test2.txt dir1/dir2/dir3/test2X.txt
A dir1/dir2/dir3/test2X.txt
D dir1/dir2/dir3/test2.txt
$ svn status
D dir1/dir2/dir3/test2.txt
A + dir1/dir2/dir3/test2X.txt
$ svn ci -m 'mv dir1/dir2/dir3/test2.txt dir1/dir2/dir3/test2X.txt'
Deleting dir1/dir2/dir3/test2.txt
Adding dir1/dir2/dir3/test2X.txt
Committed revision 3.
$ svn status
$ svn status -v
0 0 ? .
1 1 username dir1
1 1 username dir1/dir2
1 1 username dir1/dir2/dir3
3 3 username dir1/dir2/dir3/test2X.txt
2 2 username dir1/dir2/dir3/test1.txt
$ svn up
At revision 3.
$ svn status -v
3 3 username .
3 3 username dir1
3 3 username dir1/dir2
3 3 username dir1/dir2/dir3
3 3 username dir1/dir2/dir3/test2X.txt
3 2 username dir1/dir2/dir3/test1.txt
$ svn mv dir1/dir2/dir3 dir1/dir2/dir3X
A dir1/dir2/dir3X
D dir1/dir2/dir3/test2X.txt
D dir1/dir2/dir3/test1.txt
D dir1/dir2/dir3
$ svn status
D dir1/dir2/dir3
D dir1/dir2/dir3/test2X.txt
D dir1/dir2/dir3/test1.txt
A + dir1/dir2/dir3X
$ svn ci -m 'mv dir1/dir2/dir3 dir1/dir2/dir3X'
Deleting dir1/dir2/dir3
Adding dir1/dir2/dir3X
Committed revision 4.
$ svn status
$ svn status -v
3 3 username .
3 3 username dir1
3 3 username dir1/dir2
4 4 username dir1/dir2/dir3X
4 4 username dir1/dir2/dir3X/test2X.txt
4 4 username dir1/dir2/dir3X/test1.txt
$ svn up
At revision 4.
$ svn status -v
4 4 username .
4 4 username dir1
4 4 username dir1/dir2
4 4 username dir1/dir2/dir3X
4 4 username dir1/dir2/dir3X/test2X.txt
4 4 username dir1/dir2/dir3X/test1.txt
And as OP said - should one forget to do the svn update
before a new move/rename+commit, and the "Commit failed" occured - then one can use svn resolve --accept working -R .
to be able to finish the commit action.
This worked for me:
vi someotherfile
...various changes to the other file
svn mv olddir newdir
svn commit -m"Moved olddir out of the way" olddir
svn commit -m"New location of olddir" newdir
svn update
svn commit -m"Changed someotherfile" someotherfile
I suspect that there were various other possible ways round, and that ensuring there was a clean working directory before doing the svn mv would also have done the trick.
One could think of a scenario where the directory has been changed in the repository by an other user. Renaming the same folder in your working copy may trigger tree conflicts during commit.
Resolving conflicts shows how to resolve 'tree conflicts' in subversion.
精彩评论