Replacing a directory with a symlink fails after status
Bug #174027 reported by
Matthew Z Haralovich
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Bazaar |
Fix Released
|
Medium
|
Robert Collins |
Bug Description
The following script breaks with 1.0~rc1-3bazaar1. Somehow the problem only occurs when status is called before the second commit.
#!/bin/bash
bzr init
mkdir red
mkdir red/green
touch red/green/blue
touch red/green/yellow
bzr add
bzr commit -m "first\!"
rm red/ -rf
ln -s /tmp red
bzr status
bzr commit -m "Changed red to a link."
Changed in bzr: | |
status: | Incomplete → Fix Released |
assignee: | nobody → Robert Collins (lifeless) |
milestone: | none → 1.18rc1 |
To post a comment you must log in.
Just to follow up, this gives me: jameinel/ dev/,tmp/ foobar/ 20071204222254- c1dyqoauqny7znz 5-4'
Committing to: /Users/
modified red
deleted red/green
deleted red/green/blue
deleted red/green/yellow
bzr: ERROR: dirstate: inconsistent delta, with tree 0. 'red/green/yellow' 'yellow-
If I look closely at the dirstate file just before the commit, (after status) it has noticed that 'red' is a symlink, and updated its node to mark it as such.
But then it thinks that red/green is still an existing directory (because you didn't do 'bzr rm red' to indicate otherwise).
At that point the dirstate claims that:
red => symlink
red/greed => directory
red/green/blue => file
red/green/yellow => file
So we need to think a little about how to fix this. Possible problems are:
bzr init
mkdir -p red red/green
touch red/green/blue red/green/yellow
bzr add
bzr commit -m "init"
At this point if you did:
mv red other
ln -s other red
At that point, you really want to run "bzr mv --after red other"
to let us know that red was actually renamed, and not just transformed into a symlink.
If you ran 'bzr status' and we noticed it turn into a symlink, and then auto-removed the children, the mv would not see that the child files were renamed as well, because they would have already been marked as deleted.
Or put another way, doing:
mv red other
ln -s other red
bzr status
#oops
rm red
mv other red
bzr status
Should end up as a no-op (no changes).
But that does mean in the short term the dirstate would consider itself "invalid" because it has files that are children of a node which is not a directory. (note the same thing happens if you mv red other; touch red).