Philip Martin wrote:
Branko Čibej firstname.lastname@example.org writes:
This example is exactly why I keep saying that we should make svn mv
an atomic operation that *does not* generate a new node in the
filesystem. Then moves would become pure directory changes, and svn
merge has to resolve those before merging the files themselves, like
Philip said -- and so it would know before even starting the file merge
that it found a rename.
I'm the first to admit I'm no expert on the Subversion filesystem, the
model or the implementation. There are some things about atomic
rename that are not clear to me, perhaps you could elucidate. You
emphasise that a new node does not get created, is that simply an
optimisation? The elimination of a new node is not always possible,
$ svn mv zig/foo zig/bar
$ echo stuff zig/bar
$ svn ci zig
Of course it's not possible to eliminate a new node in this case. That's
because your example isn't a move, it's a move+modify.
obviously the move has to create a new node for zig/bar as it has
changed contents. If elimination of the new node is simply an
optimisation could it not be applied to copies as well?
The elimination is not simply an optimisation, and obviously can't be
applied to copies. The intent of a copy is to create a new node from a
known ancestor. The intent of a move, on the other hand, is to change
the /name /by which a node is referred to in the file system. Because
Subversion uses a Unix-like model of the file system, node names exist
only as properties of a directory; the files do not have an intrinsic
name. Changing svn mv to only affect directory entries is a move
towards a more correct implementation of that model.
Is there something more to atomic rename than elimination of the new
Yes. Renaming a node should not affect its history. The effect of a
cp+rm is to create a new branch in the node's history (and remove an old
one); that is obviously wrong, because, under our model, a rename does
not constitute a modification of the node, only a modification of its
(old and new) parent directory. In simple terms, after an svn mv in a
clean working copy, svn st should show one or two modified
directories, but no modified files.
(Of course, the user would want to know that the file was moved, so svn
st should show something for usability's sake; but what it shows should
not be a modified state but a renamed state. That means yet another
status letter, but perhaps not.)
Does it involve storing a some sort of move flag in the
No, not at all. What you get is simply a change in one or two
I'll try to illustrate the point. Imagine you have two directories A
and B, that are children of the root. A contains the files foo and
bar, B contains qux. I'll tag each node with its node revision number:
To understand this example, you should be aware that, within the file
system, directory entries are nothing but named pointers to node
revisions (those a.0.3 triplets); the names are not a property of the
node revisions themselves.
Now see what happens when we svn rename /A/foo /B/baz:
We created new revisions of A, B and / (because of bubble-up), and
the pointer to f.0.2 is now called baz rather than foo, but the
node itself did not change, and its immediate ancestor is still the
same, although you can't guess that ancestor's name from the current one
(note that the repository does know that name already). So we don't need
any new flags in the repository at all.
Finally what about a commit of part of the rename
$ svn mv zig/foo zag/foo
$ svn ci zig
I assume this has to be rejected by the filesystem/repository.
Now here we're talking about client-side implementation issues. If that
partial commit tells the file system to move zig, without a target,
then obviously the repository will reject the commit.
This partial-commit problem is in fact the main reason why I didn't
change the behaviour of svn mv yet. The client must be able to detect
this, which means that the working copy must record the fact that a file
was moved (on /both/ sides of the move), and the commit editor must
check that both sides of every move are included in the commit. It
becomes obvious why we're doing a cp+rm now; the two halves of that
operation can be committed separately, which makes the commit editor
much, much simpler.
With --force, we might possibly allow this case to degenerate from a
move to a copy+delete; but by default, the client should error out when
it detects a commit of a partial move like that.
Luckily, an URL-URL move doesn't have this problem, and we don't allow
moves between an URL and a WC anyway (and a good thing, too).
Brane Čibej brane_at_xbc.nu http://www.xbc.nu/brane/
To unsubscribe, e-mail: email@example.com
For additional commands, e-mail: firstname.lastname@example.org
Received on Sat Oct 14 02:05:01 2006