I propose the following logical semantics of the versioned move operation that is the basis of move tracking, independent of any implementation.
A versioned move of the node with node id “N”, with respect to two revisions rX and rY (X < Y), shall mean: * Same node id. A node with node id N exists in rX and in rY. It is “the same node”. It therefore has the same node kind. It may have content modifications. * No gap. There cannot be a gap in the range of revisions: node id N exists in every revision rX, rX+1, …, rY-1, rY. (Contrast with copy-and-delete, where there can be a gap between the delete and the copy.) (The possible “resurrection” extension to these semantics would permit a gap.) * Move and/or rename. Node N has either or both of: a different name (base name) in rX than in rY; and/or a different parent (parent directory node id) in rX than in rY. * Children follow. If N is a directory, each child (recursively) of N in rX remains a child of N in rY, with the same name, unless it is separately moved or deleted. Any or all of the children can be separately moved within or outside the subtree at N, at the same time as N is moved. * No null move. An attempted move which does not change the node's name or its parent node, with or without a modification, is not distinguished from a normal succession of history. === Move versus Rename === In the versioned data model semantics, “move” refers to a change of parent node and/or a change of name. At a higher level of semantics, for example when resolving conflicts during merge, it can be useful to distinguish between renaming and moving to a different parent node. === Can't Move a Child of a Copy === Moving a child of a copy, within the same revision, is not tracked: it is an unversioned operation. A versioned "move" takes a node that existed in the previous revision and places it in a new location. A copy, however, always creates new nodes, conceptually, even if the internal representation is a "lazy copy" pointer to the old node. Moving a child node therefore is a rearrangement of the new content. It is semantically the same as deleting the child node and creating a copy of it somewhere else. Compare with copying a node and then moving that copy somewhere else. If we perform a copy and then move a child of it, either in a WC or in a repository, this should create a copy with a deleted child, and then another copy somewhere else which is the "moved" child in its new path. Is this acceptable? This means that combining the two separately committed changes "copy" and "move a child" into a single commit will result in semantic data loss, which we are trying to avoid. Thoughts? - Julian