Hi, here's an investigation on our recent discussion on #svn-dev, about providing the user with the u...@revision "at which source-left did not exist" to report a tree conflict with a locally added node.
Talking about: [[[ $ svn info parent/added_node Name: added_node ... Tree conflict: local add, incoming add upon [update|switch] Source left: (none) ^/parent/added_n...@123 Source right: (file) ^/parent/added_n...@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 error. 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 u...@revs: The URL at which the folder was when the child was added (say, the originally intended u...@rev), and the new switch u...@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. (s.b.) (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 u...@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 u...@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' -- gesundheit). 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? Thanks, ~Neels
signature.asc
Description: OpenPGP digital signature