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_at_3 and A/f_at_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
Received on 2012-11-12 13:24:24 CET