Stefan and I wanted to get some move updating into 1.8. Our plan was limited to getting some simple cases working but it keeps getting more and more complex as I think about it. The basic plan is as follows:
In wc.db a move A-to-B looks like this: op-depth local-relpath presence revision moved-to moved-here 0 normal 3 0 A normal 3 0 A/f normal 3 1 A deleted B 1 A/f deleted 1 B normal 3 1 1 B/f normal 3 1 When update attempts to modify the A tree it changes the op-depth=0 tree and raises a tree-conflict on A stored in the actual node: op-depth local-relpath presence revision moved-to moved-here 0 normal 6 0 A normal 6 0 A/f normal 6 1 A deleted B 1 A/f deleted 1 B normal 3 1 1 B/f normal 3 1 The plan for move updating is that the tree-conflict resolver would merge the changes causing the tree-conflict into the working files and update the B nodes rows. The text/property changes can be derived from the "before" tree (B) and "after" tree (A) as both are present in wc.db. The result is a wc.db without a tree-conflict that looks like: op-depth local-relpath presence revision moved-to moved-here 0 normal 6 0 A normal 6 0 A/f normal 6 1 A deleted B 1 A/f deleted 1 B normal 6 1 1 B/f normal 6 1 Two problems occurred to me over the weekend. First, we have to update the nodes rows even when there is no tree-conflict otherwise the source and destination no longer match. Second, we cannot simply use the trees in wc.db to drive the merge into the working files as we don't know whether A/f@3 and A/f@6 are the same node. In order to merge the changes properly the resolver is going to have to contact the repository (only the tree changes are required, all the content changes are already in the wc.db). The underlying problem is that move only makes sense when source and destination are the same single-revision while update is a node-by-node, interruptable, operation that causes single-revision trees to go through mixed-revision states. Why only single-revision moves? The delete half of a move can only be committed it if is equivalent to HEAD which means the move source has to be single revision (or a mixed-revision where the revisions are equivalent to HEAD). The destination part of a move should be the same revision as the source part otherwise it is not the same object being moved. So mixed-revision moves don't make sense at commit time. Mixed-revision copies are OK, we represent them as a set of nested copies both in the working copy and at commit. In wc.db each copy is a single-revision, single-op-depth copy so the mixed-revision copy is a multiple op-depth copy. Using that representation, even transiently, for mixed-revision moves is hard. It would look more like a single-revision move with nested copies as modifications on top of the move, and any such representation would clash with a user's modifications. I suppose we could introduce a single-op-depth, mixed-revision representation for moves that could be updated in parallel with the single-op-depth, mixed-revision base node layer. I've been trying to avoid that as it means all the working copy code has to become aware that such a representation is valid. The alternative is that we have to handle "broken" moves where the source and destination revision do no match. In the end the user has to update to a committable state so provided we get the move properly updated at that point things should work. So I think a "broken" move has to be stored as a conflict, or detected on the fly, and should cause the commit to be impossible until the move is fixed. This has been a rather rambling email, really I'm trying to get my thoughts in order. -- Certified & Supported Apache Subversion Downloads: http://www.wandisco.com/subversion/download