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

Re: Skipping considered harmful (was Re: Tree conflicts - problem handling when local directory is deleted)

From: Julian Foad <julianfoad_at_btopenworld.com>
Date: Mon, 02 Feb 2009 17:15:52 +0000

On Wed, 2009-01-28 at 21:39 +0100, Stephen Butler wrote:
> Quoting Julian Foad <julianfoad_at_btopenworld.com>:
> [...]
> >
> > On old conflicts, for now, I think it is acceptable to skip. I think we
> > have always skipped any updating of a text-conflicted file, and this is
> > analogous to that.
> Hold that thought! For now, please read my comments below in the
> spirit of "not skipping". As a thought experiment, to see if
> avoiding the skipping makes the design simpler.

Hi Stephen. Thanks for this brain-work.

May I start from the position that we've already agreed to make "update"
update the base and re-schedule the working version as necessary to
preserve it (issue #3334 for one case and an email thread for another

I think your proposal is to change the conceptual design from

  Update skips nodes that are already in conflict.


  Update attempts to update every node, even nodes already in conflict.
If the update would cause a second conflict on the node, then ... skip
it, I guess. If not, then ... update the base, merge the change into the
working version, and ... what about the tree conflict's "their" and
"mine" information?

I'm going to see if I can see the simplification. I think you expect:

  * to simplify the implementation of searching for tree conflicts in
the WC, by not having to discern whether a conflict is new or old;

> I'm worried that skipping old tree conflicts will put the user on
> the merry-go-round (can't commit, can't update; resolve && update
> recreates the tree conflict).

Ah, but I don't think old conflicts have much to do with the
merry-go-round. If we make sure we always update the base versions when
we raise a tree conflict, as we are now trying to do (issue #3334 for
one case and an email thread for another case) then resolving a tree
conflict will always make the result committable and updateable without
risk of re-raising the same conflict. That's all we need in order to
avoid the merry-go-round.

If we achieve that, then skipping an old tree conflict is at least safe.
(It won't harm the user's ability to resolve the old conflict and then
re-run the update in order to update the victim.)

If we can't manage to update the base of a tree conflict that we're
raising, then we can't hope to do so for an old tree conflict, because
there are the same issues to deal with plus many more cases.

But I'll read on.

> > > In the following table, X -> Y means "in the given use case, an item
> > > with schedule X will be transformed to schedule Y". rOLD is the
> > > item's old BASE revision, "base" is the base text and/or props, rNEW
> > > is the target revision of the update, "gone" means "the item and
> > > its metadata no longer exist, or the item is now unversioned", and
> > > "SKIP!" means to skip the item and its descendants.

> > > > We'd also revert our change to the dir-prop-conflict handling, to
> > > re-enable updating inside a dir that has a prop conflict. We made
> > > that change just for consistency's sake.

I can see that, in practice, it's almost always OK to continue the
update inside a dir which has a prop conflict, but consistency is

> > > > If update runs into a text or property conflict, it should skip
> > > the item. Or rather stop with an error? Then the user could
> > > 'svn resolve --accept=mine -R .' before updating again, so that
> > > those conflicts are up to date. Just trying to go the extra mile
> > > to avoid skipping.
> >
> > I haven't got the capacity to redesign or even think about new behaviour
> > for non-tree conflicts right now.
> I want to reduce the number of situations in which we create tree
> conflicts. I suppose restoring the 1.5 behavior (raising an error)
> is acceptable for now, to get us off the hot seat for releasing
> 1.6.0.

I don't follow. What case are you referring to? If it's a case where we
are raising a tree conflict that is not easily resolvable, and we're not
going to manage to fix it for 1.6, then, yes, restoring the 1.5
behaviour is probably preferable.

I don't want to reduce the number of tree conflicts that we raise if
they are easily resolvable. I think that would miss the point of the
feature. (Except I'd like double-delete and double-add to be
configurably ignorable.)

> > > As you can see, there's only one skip remaining in update. Can anyone
> > > see a simple workaround for it? Or point out any other weak spots?
> >
> > In this scheme, we are expecting to deal with a subsequent update to a
> > node on which a previous update caused a tree conflict that has not yet
> > been resolved. We will often get situations where the "action" (incoming
> > change) and the "reason" (schedule) in the update that is currently
> > running are not the same as the action and reason recorded in the
> > pre-existing tree conflict. For example, if an edit caused a tree
> > conflict (on a schedule-delete node), the new action on this subsequent
> > update is perhaps a delete. The "reason" can be different because the
> > user has had the opportunity to change the scheduling of the node.
> >
> > Because of this, we have to be very clear whether we're talking about
> > the action/reason of the pre-existing conflict, or of the current
> > update. And we have to say what we're doing when they differ.
> Via 'svn status', the user can see all the tree conflicts and their
> reasons. [...] In the future we could make it friendlier. [...]

Yes, I think the user experience will be OK. But I meant we, as in you
and me, need to be very clear in these design discussions.

> > > UC1 "local delete, incoming edit on update"
> > > > delete -> delete (rev=rNEW;
> > > base at rNEW;
> > > rNEW merged into working)
> >
> > This, "delete", is the expected schedule of any node that has a UC1 tree
> > conflict, and of any node inside such, if the user has not tinkered with
> > it.
> >
> > What incoming change are we talking about as the current update
> > operation here? "edit", I assume. What about other possible incoming
> > changes that could happen to a node that was once marked with such a
> > tree conflict and has been further updated but not yet marked as
> > resolved?
> If the user reverts the local delete, then the second update wouldn't
> find a tree conflict there. It'd continue as normal, possibly [...]

What I'm saying is: if we're going to design a scheme for applying
updates to a node that's in a state of tree conflict, then we have more
cases to think about than you have listed.

A. Schedule.

When we encounter an old UC1 conflict, we know that the node's schedule
was "delete" just before the conflict was raised, and was still "delete"
just afterwards.

After that, the user can have done things to the node that change its
schedule. Let's ignore reverting, because that would have cleared the
conflict, but let's assume the user scheduled some other node for
addition in its place, changing the schedule to "replace".

The user can also have done further updates to the node's base, and
these can also change its schedule. The exact effect of such further
updates is what we're trying to define now, but I assume they could
include at least "delete" which would necessarily have to change the
node's schedule to something other than "delete".

So the victim's schedule is not necessarily "delete" now when we
encounter it.

B. Incoming change.

When we encounter an old UC1 conflict, we know that the old incoming
change that caused the conflict was an "edit". However, the current
incoming change whose behaviour we're trying to specify can be another
edit, or a delete, or (because further updates may have deleted the node
in the meantime) it may now be an add.

> Here's an imaginary transcript of reverting a local deletion, then
> encountering new conflicts inside the old victim:
> $ svn status
> D C mydir
> > local delete, incoming edit upon update
> D mydir/alpha
> D mydir/beta
> $ svn add mydir # revert the deletion

(so it's now scheduled for "Replace")

> $ svn up
> D C mydir/alpha

So the incoming "edit" of "mydir" is ... to delete "alpha" and modify
"beta" ? No, maybe you just mean that "update" could show us alpha's
current status, not that there's an incoming change involving alpha.
(Subversion doesn't display status of nodes it's not touching.)

> C mydir/beta # here's the incoming edit
> Updated to revision 999.
> Summary of conflicts:
> Text conflicts: 1
> Tree conflicts: 2
> $ svn status
> C mydir
> > local delete, incoming edit upon update
> M C mydir/alpha
> > local edit, incoming delete upon update
> C mydir/beta

Right... but I'm not seeing what you think is good about this. To me,
it's difficult to imagine what that nested conflict really means in
terms of what was the "mine" state of the outer dir, for example.

Sending now, but I haven't fully responded to the rest of this below.

- Julian

> >
> > "rNEW merged into working" is inapplicable, because if the schedule is
> > "delete" the working version is nothing (except, if it's a directory, a
> > skeleton of directories whose base metadata should be updated by this
> > definition recursively).
> You're right, there's no merging or text/prop conflicts for
> schedule-delete items. I've just done some experiments with SVN 1.5.5
> to check the current behavior. The incoming (rNEW) text and prop
> changes are written in the working copy, overwriting whatever "working
> version" may remain.
> Note that if the user deleted the tree with --keep-local, then the
> whole tree remains visible in the working copy.
> >
> > What do we do with the other schedules that may be found if the user has
> > tinkered since the conflict was raised?
> >
> >
> > > UC2 "local edit, incoming delete on update"
> > > > normal -> add w/hist (rev=r0;
> > > base at rOLD;
> > > copyfrom=rOLD)
> >
> > Same concerns as for UC1 above.
> >
> > Issue #3334 is doing this for the case when the tree conflict is freshly
> > raised.
> Absolutely. I forgot to mention that this is the only line of this
> table that is already implemented (for the record, in the
> issue-3334-dirs branch).
> >
> >
> > > add -> add w/hist (rev=r0;
> > > base at rOLD;
> > > copyfrom=rOLD)
> > > > add w/hist -> add w/hist (rev=r0;
> > > base at rOLD;
> > > copyfrom= <no change!>)
> > > > delete -> "gone"
> >
> > These schedules can occur if the node has been tinkered with ... or are
> > you thinking about nodes inside a sub-tree that has a UC2 tree conflict
> > on its root?
> By "edit" we really mean "tinkered with", don't we? ;-)

(When I used the phrase "tinkered with", I meant the user changed the
node's local schedule after it became conflicted.)

> If the victim is a file, then only the "normal" schedule is applicable
> (otherwise it'd be a different use case).

No. That's where the difference between "use case of the original tree
conflict" and "use case occurring now, in the current update".

> If the victim is a directory tree, then we should treat each of its
> nodes according to the node's own schedule.
> Regards,
> Steve
> > > > UC3 "local delete, incoming delete on update"
> > > > delete -> "gone"
> > > > > "local add, incoming add on update"
> > > > add -> normal (rev=rNEW;
> > > base at rNEW;
> > > rNEW merged into working)
> > > > add w/hist -> SKIP!
> >

Received on 2009-02-02 18:16:33 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.