Moving and deleting a dir causes a big problem
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Bazaar |
Fix Released
|
High
|
Unassigned |
Bug Description
Bazaar doesn't handle properly the following situation:
create some dir with files:
$ mkdir -p a/b
$ mkdir -p c/d
$ touch a/b/b1
$ touch c/d/d1
$ bzr add
added a
added c
added a/b
added c/d
added a/b/b1
added c/d/d1
$ bzr commit
Until here, it works ok. Now, we want to move d into a:
$ bzr mv c/d a
c/d => a/d
and delete the empty dir c:
$ rm c
bazaar reports correctly the state:
$ bzr status
removed:
c/
renamed:
c/d => a/d
but when we try to commit....
missing c
bzr: ERROR: The file id d-2007051514065
If we do an extra commit just before deleting the dir it works ok, but if not, the error is unrecoverable, and no more commits can be done. Even operations like revert fail. Maybe there's a way to recover from this, but I needed to rm -r .bzr and bzr init again :( In my opinion is a very infrequent but serious bug.
Vreixo
If you change the "rm c" to "rmdir c" it fails for me in the same way.
Just to make it easier to cut and paste to verify, the steps are:
bzr init test
cd test
mkdir -p a/b c/d
touch a/b/b1 c/d/d1
bzr add
bzr commit -m 1
bzr mv c/d a
rmdir c
bzr commit -m "goes boom"
Considering where the error occurs, this seems to actually be a duplicate of bug #94975.
Note also that this seems to be a specific problem with WT.unversion() (somewhat related to bug #114615).
I say that simply because if you use "bzr rm --force c" rather than a plain "rmdir c" then it succeeds. So it seems
to be a bug in our "auto-remove" code.
You need the '--force' because it sees the rename of 'd' as a change underneath 'c' so it doesn't want to delete a directory which has changes underneath. (It similarly complains if you just modified c/d/d1, etc). This may be a case we need to handle specially, since renaming *out* of 'c' shouldn't really prevent you from deleting 'c'.
Actually, what it also seems like, is when we auto-detect that 'c' is deleted, we recursively remove everything from the working inventory that *used* to be present as a child. So we remove 'c/d' and 'c/d/d1'. Which means it is not present when we get to 'a/d' and 'a/d/d1' to notice the rename.
If you use 'bzr rm c' rather than plain 'rmdir c' and have 'bzr commit' detect the deletion for you (also note bug #5158) then 'bzr rm' is smart enough to just remove the 'c' entry, and commit succeeds properly.