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

Re: An analysis of possible tree conflicts during update

From: Stefan Sperling <stsp_at_elego.de>
Date: Wed, 2 Dec 2009 11:39:14 +0100

On Wed, Dec 02, 2009 at 08:53:00AM +0100, Daniel Näslund wrote:
> [[[
> * When "svn update" or "svn switch" raises a tree conflict, it shall update
> the victim's "base" version from OLD to THEIRS, and leave the "working"
> version in a state that would be committable (but for the explicit check
> that prevents committing an item marked as in conflict) and that, if
> committed, would restore the item to how it looked in "mine". This may
> involve changing the scheduling of the item, e.g. to be re-added if "update"
> applied a delete.
> ]]]
>
> Does the tree conflict code do that?

Yes it does, at least in the following case:

If the update tries to delete a locally modified file, the file in
working is schedule for re-add.
$ svn st
M alpha
$ svn up
   C alpha
At revision 3.
Summary of conflicts:
  Tree conflicts: 1
$ svn st alpha
A + C alpha
> local edit, incoming delete upon update
$ svn info alpha | grep Copied
Copied From URL: file:///tmp/svn-sandbox/repos/trunk/alpha
Copied From Rev: 2

> When running my test cases I could
> just use 'svn resolved <file>' but I may have missed some edge cases.

In the above case you can use 'svn resolved alpha' to keep alpha.
You'd have to use 'svn revert alpha' to get rid of alpha.

> A bit early but I was wondering about this piece from resolution.txt:
>
> [[[
> "Options" lists resolution options that ought to be available. The
> resolution options "THEIRS" and "MINE" should be available in every case (so
> that a user can resolve a whole tree at once with one of those options) and
> should be implemented internally. Any other options listed here may be
> recipes for the user to apply manually. These recipes are starting from the
> state in which the WC should be left by Subversion after raising a conflict.
> ]]]
>
> Is this still the way we want it? THEIRS and MINE is handled in our
> code, the other options is text that explains what to do and leaves it
> to the user to do it?

I guess this is just about keeping possible other options in mind.
I'm not sure if we can always guess a suitable resolution, it really
depends on the situation.
Does the text even give examples for what the other options might be?

Let's keep it simple. Make the resolver deal with the simple cases,
because right now, usability sucks even in the simple cases.
If we did make the resolution callback provide 'theirs' and 'mine'
options with auto-resolution in *all* file cases, we'd be pretty good.
Note that this will get very difficult when dealing with directories,
at least in the 1.6.x (and possibly 1.7.x) world.

What should definitely be there is a 'postpone' option, meaning "leave
the conflict markers in place and leave the WC in this state, I'll deal
with it manually". But I don't think the option needs to explain anything
or suggest ways to go about solving the conflict. What if we get it
wrong and give wrong advice? Users won't be happy. We'll have to rely
on them to engage their brain instead.

We might also want to provide an option to view the revision log of
any file or its parent directory from within the menu, so people can
dig in the history without having to open another terminal etc.

>
> Categories of conflicts
> ========================
> 1. Locale add, incoming add
> 2. Locale del, incoming del
> 3. Locale del, incoming edit
> 4. Locale edit, incoming del

s/Locale/Local/g

> 1. Locale add, incoming add
> ============================
> Some use cases:
> - I have already applied the patch - their item is identical to mine.
> -> want to do it just once -> THEIRS.

... or MINE, since the item is identical?

> - Two different new items happened to be given the same name. ->
> accept theirs & rename mine -> RENAME-MINE.

What about keeping my name, and renaming the incoming file instead?
This would result in:
R myfile
A + theirfile

> - I was doing roughly the same thing but the item is a bit different.
> -> merge the two items -> manual 2-way merge (or 3-way if both are
> w/hist and it's the same copy-from source) -> MERGE.

Yeah, we should provide a merge option in that case.
Much like what update does today for text conflicts, but with support
for installing the merged file on top of some other file in WORKING.

Possible options after the merge (based on OpenBSD's sysmerge which
merges configuration files after a system update):

- edit the merged file again
- install the merged file in WORKING
- view a diff between a WORKING file and the merged file
- view a diff between a BASE file and the merged file
- re-do the merge
- view the merged file
- discard the merged file and go back to previous menu

> THEIRS
> --------
> Replace <file> in WORKING with the new BASE that comes in during the
> update.
> *Problems*: We may need to undo a local move or copy operation with
> destination <file>.

Let's ignore existing copies of the file for now.

> MINE
> -----
> WORKING-TARGET is already changed to a state that means the same as our
> previous WORKING.

In case of 'local add, incoming add', I believe what happens is that
the incoming file is installed in BASE, and the locally added file is
only in WORKING and ACTUAL.

So <file> in working has not been changed, only the BASE tree has been
changed and conflict markers have been installed.

> *Problems*: Are we guarenteed that this always holds? Can the
> rescheduling destroy the semantics of the change?

We just need to offer an option to either keep the current WORKING
file in WORKING or put the new BASE file in WORKING. Even if the local
add was the destination of a copy, there are only those two options.

We don't need to worry about destroying anything. Maybe keep an unversioned
backup of whichever file was overwritten.

> RENAME-MINE
> ------------
> Move the WORKING <file> to <renamed> and replace <file> with the new
> BASE that comes in during update.
>
> MERGE
> ------
> Merge BASE <file1> onto WORKING <file2>. Delete <file1> from WORKING.

See the options menu I suggested above.

> 2. Locale del, incoming del
> ============================
> Some use cases:
> - Already applied the patch -> want to do it just once -> THEIRS.

... or MINE, since both sides made the same change.

> - Renamed to two different names -> want to undo Their renaming and
> make it like Mine, as if we had a "Choose Mine" option that worked
> on whole rename operations. -> RENAME.

What about keeping their name?

>
> THEIRS
> -------
> Delete the WORKING <file>. If the WORKING <file> has been moved to
> <moved> then delete <moved> too.

No, let's not follow moves/copies for now. We can add that later.

> WORKING <file> is supposed to be
> deleted in all cases so perhaps there's no need to specify it here?
>
> MINE
> -----
> WORKING-TARGET is already changed to a state that means the same as our
> previous WORKING.
>
> RENAME
> -------
> Rename WORKING <file> to <renamed>. Merge BASE <file> onto WORKING
> <renamed> if there are changes. Remove BASE <file>?

Removing a file from BASE doesn't make any sense.
Local changes aren't expressed in BASE.

> 3. Locale del, incoming edit
> ============================
> Some use cases:
> - Locally renamed -> want to apply the incoming mod to a different
> item -> ELSEWHERE.

This should be handled automatically without even prompting the user.
wc-ng will provide this information.
Note that it will also tell us whether the local operation was a move
or a delete. In case of a true delete, the options below still apply.

>
> THEIRS
> -------
> Replace the deleted WORKING <file> with edited BASE <file>. If WORKING
> <file> has been moved to WORKING <moved>, delete <moved>

Again, don't bother checking for copies of the WORKING file for now.

>
> MINE
> -----
> WORKING-TARGET is already changed to a state that means the same as our
> previous WORKING.
>
> ELSEWHERE1
> -------------
> If WORKING <file> has been moved to WORKING <moved>. Merge BASE <file>
> onto WORKING <moved>. Does this preserve history?

It does preserve history, since in wc-ng, we can trace from the old
location of the WORKING file to where it has been moved to.
And the moved file will have copyfrom info.

>
> ELSEWHERE2
> -----------
> TODO:
>
> 4. Locale edit, incoming del
> ============================
> Some use cases:
> - The incoming change is (part of) a rename -> want to transfer my
> local mod to the renamed item -> MOVE-MY-MODS.

Or maybe keep my edit in the WOKRING file and move the new BASE file
somewhere else?

>
> THEIRS
> -------
> Remove WORKING <file>. If WORKING <file> has been moved to WORKING
> <moved>. Replace WORKING <moved> with BASE <moved>.

You don't know <moved>, unless the user knows and can tell you.

We can't tell the add-half of the rename for which you get the
incoming delete-half. We can only do this once the server can tell
us this information, i.e. we need wc-ng, and editorv2, and storing
renames on the server sorted out. The latter hasn't even been started.

>
> MINE
> -----
> WORKING-TARGET is already changed to a state that means the same as our
> previous WORKING.

Yes, it's A+ as shown above.

>
> MOVE-MY-MODS1
> -------------
> If BASE <file> has been moved to BASE <moved>: Merge WORKING <file> onto
> BASE <moved>. Delete WORKING <file>.
>
> MOVE-MY-MODS2
> --------------
> If BASE <file> has been moved to BASE <moved>: Merge BASE <moved> onto
> WORKING <file>. Delete BASE <moved>. Move WORKING <file> to WORKING
> <moved>.

Again, for incoming renames, you don't know the name of the move target
unless the user tells you.

Stefan
Received on 2009-12-02 11:39:50 CET

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

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.