here's an investigation on our recent discussion on #svn-dev, about
providing the user with the URL_at_revision "at which source-left did not
exist" to report a tree conflict with a locally added node.
$ svn info parent/added_node
Tree conflict: local add, incoming add upon [update|switch]
Source left: (none) ^/parent/added_node_at_123
Source right: (file) ^/parent/added_node_at_125
We said that it's rather difficult to say which revision should be shown at
source-left. At least, for a working copy with no mixed revisions, no
switches and no sparse nodes, source-left should give the added, so far
nonexistent, URL, and as the revision number the "checked-out" revision
number of the op_root of the add operation. (Since we're only going to
report a tree conflict on the op_root of an add, I'm going to only say "the
node's parent" from now on. Note how a whole bunch of complexity just
disappeared with the previous sentence.)
No matter which special cases are around, an 'svn add' will at first always
tie the added node to its parent folder. But it is likely that the parent
changed its state by the time we run into a tree-conflict.
So, what special cases do we have?
(I am assuming that copy/move will, once wc-ng is fully rolled out, not
differ from a normal add, in that we won't get mixed up between the
"checked-out" node and the copied-here node.)
(Don't start replying before you've read the conclusion at the bottom)
(1) Sparse checkout
- A folder was checked out with --depth=empty
- A local 'svn add foo' added a node
- An update wants to bring in a node at the same path
Clearly, the checked out folder's revision should be used for source-left info.
Interesting current behavior:
If the node already existed in the repository in the same revision that was
checked out (and did not come along because of --depth=empty), then 'svn
update' does not conflict at all, but acts as if those nodes don't exist in
the repos. It says 'At revision N', with status 'A foo', although a
different foo exists in the repos at that revision N. Only 'commit' hits an
But IMtheoreticalHO, here, too, a tree-conflict should come up and report
the same revision, to indicate that source-left wanted that revision to be
node-kind == none, while source-right says that the same revision exists and
has a node kind != none.
(2) Switched working copy
(2.1) Add to a switched folder
Adding inside the switched folder is no different from adding inside a
non-switched folder. The child node doesn't care if its parent is switched
or not, all it sees is a URL and a revision.
(2.2) Sparsely switching a parent folder away from over an added child node.
Now we theoretically have two URL_at_REVs: The URL at which the folder was when
the child was added (say, the originally intended URL_at_REV), and the new
switch URL_at_REV. Switch should preserve/rebase/transfer the mods onto the
switch target, but this is a sparse switch, meaning that the child nodes
should still want to be added at the original folder's URL + /child, i.e.
the would-be added-URL and parent's revision at the time of 'svn add'.
Testing shows that added nodes are not tied that closely to the parent --
the added child still goes to the original URL after the parent was switched
away. This makes deciding on the revision difficult: The added node's
revision is not tied to anything, it is just waiting for the HEAD revision
at the time of commit. It would make sense to be the revision the original
parent had before the switch, but that information does not exist anymore.
(2.3) Switching (non-sparsely) a parent folder of an added child
(Talking about switching the WC without creating a tree-conflict, i.e. this
is a switch in-between an initial 'svn add' and another switch/update later
that causes a tree conflict)
The child's URL_at_REV should now be as if it was added to the parent after the
switch operation. (s.b)
(3) Update / Mixed-revision working copy
(3.1) The WC was mixed before adding nodes, now updating all to HEAD.
Simple case, we should take the parent folder's current "checked-out"
revision to report the tree-conflict's source-left when we hit a
tree-conflict in this update.
(3.2) Sparsely updating a parent of an added child (depth=empty).
Since this is 'update', the URLs are identical. But again, two @REVs: The
update should not include the parent's children, because that's what depth
asks for. So theoretically, the added nodes should "still want to be added
to the original @REV". Theoretically. Same as with (2.2), the revision at
the time of 'svn add' is no longer available -- unknown. (s.b.)
(3.3) Updating non-sparsely
Analogous to (2.3) (also s.b.)
["s.b." means read here:] ---> The URLs are not a problem. They are closely
tied to an added node in the WC state and (a) stay the same during update
plus (b) even stay the same during a sparse switch of the parent.
But with the revisions, we're basically requesting a new feature here. The
WC has no concept of "the revision of the parent at the time this node was
locally added", let alone updating such revision on non-sparse 'update' and
'switch' operations. If we don't add this field (or (mis)use added nodes'
'revision' field that is currently always 0), then there is no way to
reliably get the source-left revision that the user presumably wants to see.
I'd like to note that 'merge' does not have this problem, since source-left
is clearly defined by the lowest end of the revision range being merged (it
is something that is already fixed in the repos and explicitly or implicitly
defined in the merge args). So we always know at which URL_at_REV a given added
node was expected to be nonexistent with a merge. The sparse operations
possible in the WC destroy that clarity for 'update'/'switch' (heh, 'uptch'
Maybe we should take the same approach with 'uptch': Always report the
revision at which the incoming add was added minus one? But such revision
does not exist/make sense in the sparse-checkout example above. Also, when
an update leaps over a whole range of revisions that saw an add and then
some modifications, or even multiple adds and removes, of the node in
question, this becomes undefined / overly difficult to determine.
We're in a twist with that darn revision. Unless we introduce added nodes'
"revision at which I was added" storage (and update thereof during 'uptch'),
we can only sanely report SVN_INVALID_REVNUM for a tree-conflict upon
'uptch' on a locally added node. (And get rid of the ASSERT that currently
enforces a valid revnum for source-left conflict versions.)
Would anyone endorse giving up REVISION == 0 for added nodes for this
feature? I'm not sure that I care enough. However, if any other code could
benefit from knowing "the revision after which a node wants to be added",
then this might even be an option. Actually, it could "clarify" whether a
locally added node is up-to-date and can be committed! (note that for
modified/deleted nodes, svn says 'out of date', where for added nodes, it
says 'already exists' -- i.e. there is a tiny asymmetry of where/how the
conflict is reported: normally during update, but for added nodes during
commit as well?)
Have I stared at this problem for too long or am I onto something?
Received on 2010-02-09 03:24:59 CET