| This file describes handling of all add-vs.-add tree conflict situations |
| on 2010-jul-20 (previously 2010-jul-01, r959735). Maybe someone will update it |
| and put another date here some day, maybe not. |
| |
| Add-vs.-add tree conflicts handling introduces a new meaning for |
| svn_wc__db_status_not_present. Apart from the usual "node deleted and |
| committed and parent not updated yet", a not_present BASE_NODE can also mean: |
| This node was intended to be added during update/switch/checkout, but there |
| was an unversioned obstruction in the local working copy at that path. A tree |
| conflict with reason == svn_wc_conflict_reason_unversioned is flagged on such |
| nodes. If such a tree conflict with _reason_unversioned is found on a |
| not_present node during update/checkout/switch, and if furthermore there is no |
| unversioned obstruction in the WC anymore (the user moved it away), then |
| complete_directory() automatically removes the tree conflict, after which the |
| running update/switch/checkout will pull that node in. |
| |
| |
| All add vs. add cases: |
| ---------------------- |
| (see a legend below) |
| |
| all add-vs.-add | incoming ADD of a | incoming COPY of a | |
| tree conflict | file | symlink | dir (2) | file | symlink | dir (2) | |
| situations |co up sw |co up sw |co up sw |co up sw |co up sw |co up sw | |
| ------------------+---------+---------+---------+---------+---------+---------+ |
| locally file |?C*?C*?C*|?C*?C*?C*|?C+?C+?C+|?C*?C*?C*|?C*?C*?C*|?C+?C+?C+| |
| UNVER- symlink |?C*?C*?C*|?C*?C*?C*|?C+?C+?C+|?C*?C*?C*|?C*?C*?C*|?C+?C+?C+| |
| SIONED dir |?C*?C*?C*|?C*?C*?C*|?C+?C+?C+|?C*?C*?C*|?C*?C*?C*|?C+?C+?C+| |
| ------------------+---------+---------+---------+---------+---------+---------+ |
| locally file |Ex Ex RC*|RC*RC*RC*|:( :( :( |Ex RC*RC*|RC*RC*RC*|:( :( :( | |
| ADDED symlink |RC*RC*RC*|Ex Ex RC*|:( :( :( |RC*RC*RC*|Ex RC*RC*|:( :( :( | |
| (2) dir |:( :( :( |:( :( :( |Ex Ex Ex |:( :( :( |:( :( :( |Ex Ex Ex | |
| ------------------+---------+---------+---------+---------+---------+---------+ |
| DIFFERENT file |RC*RC*RC*|RC*RC*RC*|:( :( :( |RC*RC*RC*|RC*RC*RC*|:( :( :( | |
| COPY symlink |RC*RC*RC*|RC*RC*RC*|:( :( :( |RC*RC*RC*|RC*RC*RC*|:( :( :( | |
| of a (2) dir |:( :( :( |:( :( :( |AC AC AC |:( :( :( |:( :( :( |AC AC AC | |
| ------------------+---------+---------+---------+---------+---------+---------+ |
| IDENTICAL file | |RC*Ex*RC*| | | |
| COPY of symlink | (see above) | |RC*Ex*RC*| | |
| a (1) (2) dir | | | |AC AC AC | |
| |
| |
| "*" The cases changed in r959735 marked with a * on their right. |
| "+" The cases most recently changed are marked with a + on their right. |
| |
| (1) Where both local and incoming are copies and both copies are from the |
| exact same copyfrom URL@REV, the node kinds must also match. The colums |
| against incoming simple-add are identical to "different copy" and omitted. |
| |
| (2) Since we can only deal with replace-by-different-kind properly after we |
| moved to single-db, some of these rows/columns are still ':(' or 'AC'. |
| |
| |
| In the table above, each cell shows three letter pairs for, |
| checkout, update, switch operations, respectively. |
| |
| The letter pairs are: |
| RC = tree conflict where local add/copy becomes a schedule-replace, |
| i.e. status reports: |
| 'R C' -> that's why this is called 'RC' |
| ' > local add, incoming add upon update|switch' |
| Resolving is easy. 'svn revert' gives theirs, 'svn commit' replaces |
| theirs with mine. (this is new!) |
| |
| ?C = tree conflict against locally unversioned, adds a not_present BASE |
| node. Status reports |
| '? C' |
| ' > local unversioned, incoming add upon update|switch' |
| Resolving is easy. Just move away the obstruction and run 'update'. |
| The tree conflict is removed automagically. (this is new!) |
| |
| Ex = "Existed": local add and incoming add are seen as identical, there |
| will be a text/prop merge and possibly a text conflict. |
| |
| :( = svn bails with an error, interrupting the operation. The parent is |
| left '!' == incomplete. Removing the obstruction and running the |
| operation again fixes the node as expected. |
| |
| AC = Though a tree conflict is flagged, the node is skipped and the working |
| copy is left in a state where it doesn't notice that the incoming add |
| is still missing. After a revert, it is necessary to update back to an |
| older revision and then again back to HEAD to restore the file. |
| This is the old behaviour for all caught add-vs-add tree conflicts. |
| i.e. status reports |
| 'A C' |
| or 'A + C', |
| ' > local add, incoming add upon update|switch' |
| |
| So "Ex Ex RC*" would mean: |
| "During checkout and update, the local add is merged with the incoming add. |
| During switch, an easily resolvable tree conflict is flagged. |
| r959735 only changes the 'switch' behavior." |
| |
| A note on checkout: It *is* possible to checkout a URL onto a working copy of |
| the same URL, which can have local adds scheduled. Then, checkout presumably |
| is like an update -- almost. Note the incoming copy columns during checkout |
| saying 'Ex' and 'RC' in some wrong places. That's because during checkout, |
| add_file() gets no copy_from info and the incoming action always looks like a |
| simple add. #TODO: we should discuss this non-feature. |
| Note that tree conflicts from a checkout wrongly say "upon update". |
| |
| Notably, earlier servers provide no copy_from info to add_file() either, so |
| 'update' then acts the same way as 'checkout' -- fails to flag same-kind tree |
| conflicts with local-add vs. incoming-copy, and fails to not flag conflicts on |
| matching copies. #TODO: we should discuss this, too. |
| |
| The reasoning with 'switch' is that when 'switch' merges a local add |
| with an incoming add, it is "lost" in the sense that switching back wants to |
| simply delete that node, not re-schedule it for addition. So switch should |
| *always* flag tree conflicts, never merge local adds away, so that the user is |
| (hopefully not annoyed but) made aware of the situation. |
| |