blob: 78e67409eb0c141aad36627b95a48ded85bed083 [file] [log] [blame]
WC to WC Copy
=============
In 1.6 a wc-to-wc copy of a directory first does a plain copy,
including the admin directory, and then adjust the metadata to make it
a copy. With a centralised db the metadata has to be copied
separately and explicitly.
When copying a mixed revision working copy the source may have nodes
that are in states such as absent, excluded, not-present or
incomplete, as well as nodes at different revisions and nodes with
local modifications.
Consider copying and committing
$ svn cp wc/S wc/X
$ svn ci wc/X
where S contains a child T. When the copy is committed certain
changes have to be made in the repository. Some examples:
Source Commit after copy
Parent Child Parent Child
/S@N /S/T@N A /X (from /S@N)
or
A /X (from /S@N) M /X/T
(with local mods)
/S@N /S/T@M A /X (from /S@N)
(if server finds T@M is same thing as T@N)
or
A /X (from /S@N) A /X/T (from /S/A@M)
or
A /X (from /S@N) R /X/T (from /S/A@M)
(the FS layer converts
A to R if required)
/S@N added A /X (from S@N) A /X/T
or
A /X (from S@N) R /X/T
/S@N copied A /X (from S@N) A /X/T (from G@M)
or
A /X (from S@N) R /X/T (from G@M)
/S@N not-present A /X (from /S@N) D /X/T
/S@N excluded A /X (from S@N)
/S@N base-deleted A /X (from S@N) D /X/T
A single revision source produces a copy that is a gets committed as a
single copy. Local modifications, before or after the copy, get
committed as modifications to the copied nodes.
A mixed revision copy is represented as multiple copies when
committed. We could represent this with a single copy operation root
in the working tree by using the copyfrom_revision field in the
working node.
Child nodes added, copied or replaced in the source can remain added,
copied or replaced in the copy. Since these adds, copies and replaces
are root operations in the source they will be root operations in the
copy. This means that a single copy operation will produce a working
tree that contains several operation roots. We could allow these
child operation roots to be individually reverted in the copy.
There is a subtle difference between committing a copy from a mixed
revision source and from a source with a locally added or replaced
child. In both cases the commit must either add or replace the child
and if the copy is from a source that is locally added or replaced the
client can make the distinction and send a delete before adding the
replacement. For a mixed revision, as the client doesn't know whether
the child existed in its parent's revision and so can't distinguish
between add and replace, it always sends an add and the FS layer
converts to a replace as required (for details see 2010-04-19 comments
in issue 3314). We will probably have to continue rely on this in
WC-NG as there is not enough information in the source to determine
whether or not the child also exists in the parent's revision.
If the mixed-rev source has a "not-present" child (effectively the
same as "updated to r0"), then the copy schedules this as "delete".
The client doesn't know whether the child existed in its parent's
revision, so it can't distinguish between delete and no-op, so it
always sends a delete.
### This current fails, in both 1.6 and trunk.
### TODO: The server needs to silently elide a delete, or the client
needs to detect the error and recover from it and continue if that
is possible.
Child nodes not-present in the source become not-present working nodes
in the copy, this ensures that they get deleted by the commit. We
might want to use a new not-copied state instead, since these deletes
cannot be reverted.
Child nodes that are excluded in the source can remain excluded in the
copy.
Child nodes that are base-deleted in the source become not-present in
the copy. These deletes can be individually reverted.
Child nodes that are incomplete in the source become incomplete in the
copy. Some operations, like delete, could be possible on the
incomplete node. Could "svn up" retrieve the missing information and
make them complete? The commit processing would probably choose not
to allow incomplete directories.
Child nodes that are absent in the source cannot be copied and
committed. During the commit the copy of the parent will fail with an
authz error since Subversion requires read access to the whole tree
being copied.
--
URL-to-wc copy is equivalent to a single revision wc-to-wc copy.
--
The child /S/T may also be switched wrt the parent /S. At present
this is handled badly by 1.6.
$ svn sw ^/G wc/S/T
$ svn cp wc/S wc/X
the working copy X/T will look like /G but the switch status is lost.
If X/T is unmodified then the commit will add /X (from /S@N) and do
nothing for /X/T so /X/T in the repository looks like /S/T. (This is
rather like committing a non-copied switch and so is not necessarily a
bug, although whether users would expect it I don't know--I had to
experiment to verify the behaviour.)
If X/T is a modifed file the commit fails with a checksum error, the
wrong text-base is used. If X/T is a directory that is modified or
contains modified children the commit is unreliable as again changes
are made against the wrong base.
How should a copied, switched node be handled? The switch could be
preserved so that the copied node points to the same node as switched
source node. This would almost certainly require extending the client
commit code to handle this. It's not currently possible to switch an
added node so is it sensible for copy to do it?
An alternative would be to convert the switch into a replace.
Relatively easy to do but it would mean that node is no longer really
switched.
--