[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: [RFC] v2 Tree conflict resolver spec.

From: Julian Foad <julian.foad_at_wandisco.com>
Date: Mon, 15 Feb 2010 11:05:32 +0000

On Wed, 2010-02-10, Neels J Hofmeyr wrote:
> Hi TC folks,
>
> I tried to put the tree-conflicts design information so far into tables.

Thanks, Neels. This is a really useful way to present the info.

> Find the result attached: a tc-cheatsheet up for discussion. If it gets
> initial approval I'll check it into notes/tree-conflicts/ so we can edit.

[...]

> plain text document attachment (tc-cheatsheet.txt)
> TREE CONFLICT CHEAT SHEET (DESIGN PHASE)
>
>
> After tree | 'theirs' | 'mine' is | 'svn status' shows
> conflict during | is found in | found in | TC and is otherwise
> -----------------+-------------------+----------------+---------------
> | | |
> update/switch | checked-out state | check-in state | adapted to be a
> | | (unchanged) | mod of the new
> | | | checked-out state
> | | |
> merge | conflict info | check-in state | unchanged
> | | (unchanged) |
> | | |
>
>
>
>
> Upon recording | ... changed during |
> a tree conflict, is | update/switch? | merge? |
> ----------------------------+----------------+----------------+
> checked-out state | Yes | No |
> check-in state | No | No |
> 'svn status' other than TC | Yes | No |
>
>
>
>
> When resolving a | ...which was caused by a |
> tree-conflict with | switch/update | merge |
> | , the check-in state is |
> ----------------------+-----------------------------------+
> | | |
> --accept=theirs | cleared | reset to theirs |
> | | |
> --accept=mine | unchanged | unchanged |
> | | |
> 'svn revert' | cleared | cleared |
> | | |

All the above: +1.

> <future depends-on="editor-v2" status="needs-review">
>
> Assuming that we have full info on copy/move (i.e. an add here is really
> just an add and *not* possibly part of a copy/move), then:
>
> When resolving a |
> tree-conflict of |
> local vs. | incoming | offer these --accept= resolution options
> ===========+===========+=====================================================
> | |
> (all combinations of) |
> add | add | theirs, mine, move-theirs, move-mine
> copy-here | copy-here |
> move-here | move-here |

We also want to offer some kind of "auto-merge" option which keeps one
version (just like "theirs" and like "mine") if both are identical, and
offers some kind of merging if they differ. Or which re-prompts if they
differ. Or the initial prompt should differ depending on whether the two
added things differ. It gets complex with directories, and with
differences in copy-from but identical content, etc.

> | |
> -----------+-----------+-----------------------------------------------------
> | |
> delete | delete | (is not a tree-conflict)

I agree that most users will want this silently allowed. That's a
sensible behaviour for "svn".

Theoretically, however, that's only true in the same sense that
add-on-add is not a tree conflict if the same node is added twice: it's
an assumption that the user doesn't ever want to know about this kind of
conflict. Some users in some merging tasks will want a strict mode,
where they are not expecting any double-deletes and would like it
flagged if it happens.

Somehow I want to introduce a "conflict rules" framework, not
necessarily accessible through the "svn" UI, but within the
implementation and APIs. The rules will be a read-only context passed in
from the client that is like a table saying "delete-delete is to be a
silent delete, add-add is to be flagged as a conflict, edit-rename is to
be a silent edit of the renamed file, ...".

Then it will be easy for people to write a client that behaves more or
less strictly without having to first rev all our APIs.

And a second issue with "delete + delete": in a merge, we have to
consider whether the two things being deleted were identical. I haven't
yet tried to expand the rules to take account of that.

I *think* the same considerations also apply to all the other cases that
involve a delete during a merge.

> | |
> -----------+-----------+-----------------------------------------------------
> | |
> (line-wise) |
> delete | move-away | (is not a tree-conflict)
> move-away | delete |
> | |
> -----------+-----------+-----------------------------------------------------
> | |
> (line-wise) |
> delete | edit | theirs, mine
> edit | delete |
> | |
> -----------+-----------+-----------------------------------------------------
> | |
> move-away | edit | mine, both, merge-here, merge-there,
> | | merge-there-keep-here, merge-there-merge-here
> | | [1] [2]
> | | grain of salt ---> .

Heh!

But "merge-there" is surely the almost universal wish, just like "delete
+ delete -> delete" and "add + add -> add" when the two adds are
identical are almost universal wishes.

"merge-here" just means the same as "theirs", doesn't it? We need to
keep options called "mine" and "theirs" in every menu, because they
always make sense, even if we annotate them with extra description such
as "theirs (undo the move and merge the incoming edit here)".

What is "merge-there-keep-here" for? I can't think of a realistic use
case.

What is "merge-there-merge-here" for? In the case of a copy rather than
a move, then yes I can see users wanting the incoming change applied to
both copies, but for a move?

Ugh. Moves and copies get very complex. Partly because any move can have
an edit as well. Partly because the destination location might also be a
location from where something was moved away at the same time (perhaps
also being in conflict, in which case we'd require that it be resolved
first ... unless it's a cycle of moves like A>B, B>A or A>B, B>C, C>A in
which case they might have to be resolved all at the same time).
Seriously, the design has to cope with not falling over in these cases,
though we certainly don't have to give special friendly options, just so
long as there is some way for the user to resolve it.

> -----------+-----------+-----------------------------------------------------
> | |
> edit | move-away | theirs, both, merge-here, merge-there,
> | | merge-there-keep-here, merge-there-merge-here
> | | [1] [2]
> | | grain of salt ---> .
> -----------+-----------+-----------------------------------------------------
> | |
> move-away | move-away | theirs, mine, both, merge-at-theirs, merge-at-mine,
> | | merge-at-theirs-keep-mine, merge-at-mine-keep-theirs,
> | | merge-at-both
> | | (not a tree-conflict when move targets match)
> | | [1] [2]
> | | grain of salt ---> .

Ugh. This case gets even more complex.
> -----------+-----------+-----------------------------------------------------
>

We'll need to define copies as well :-/

>
> Where the --accept= options mean:
>
> mine Enforce my change, make sure theirs is lost/undone.
> theirs Agree to theirs, make sure mine is lost.
> move-theirs Keep both additions, but move theirs to another path.
> move-mine Keep both additions, but move mine to another path.
> both Keep both new move-targets (one becomes a simple "A +").
> merge-there Apply the edit to the moved-away path.
> merge-here Discard the move-away, but still merge text/prop mods.
> merge-there-keep-here Apply text/prop mods to the moved-away path, but
> keep an unmerged copy at this path.
> merge-there-merge-here Apply text/prop mods to the moved-away path, and
> keep another, also merged, copy at this path.
> merge-at-theirs Apply the edits on my moved-away path to their moved-
> away path, discard my move.
> merge-at-mine Apply the edits on their moved-away path to my moved-
> away path, discard their move.
> merge-at-theirs-keep-mine Apply the edits on my moved-away path to their moved-
> away path, but keep my move-away with only *its* edits.
> merge-at-mine-keep-theirs Apply the edits on their moved-away path to my moved-
> away path, but keep their move-away with only *its*
> edits.
> merge-at-both Apply all edits to all moved-away paths and keep them.
>
> [1] I am not sure whether resolution should only care about *this* path.
> Some of the resolution options suggest that we would undo the add-part
> of a move-away, at the *other* path, or apply edits to the *other* path.
> While it would be nicer if we could get away with only resolving *this*
> path, users might get annoyed with having to do two steps to get what
> they wanted (i.e. manually modify the other path to the desired result)
> when the resolver had all the information there and could have just done
> the job automatically.
>
> [2] The merge-* options indicate a mixture of text/prop mods with tree
> conflicts. They say whether to keep the respective sides' text/prop mods
> when resolving the tree-conflict. These options would entail that we
> have to run an apply-textdelta-ish code that can introduce new text/prop
> conflicts.
> Should we really go there? What are the alternatives? We won't get away
> without defining what happens to text/prop mods at two different paths
> that are related via moves.
> ### Analogy to copies?
>
> </future>
>

- Julian
Received on 2010-02-15 12:06:16 CET

This is an archived mail posted to the Subversion Dev mailing list.