[RFC] How to better assist users in resolving conflicts

Vincent Ladeuil v.ladeuil+lp at free.fr
Wed Jan 13 08:28:47 GMT 2010


>>>>> "martin" == Martin Pool <mbp at canonical.com> writes:

    martin> 2010/1/13 Vincent Ladeuil <v.ladeuil+lp at free.fr>:
    >> So far we have only one command when it comes to resolving the
    >> conflicts: 'bzr resolve' with 'resolved' alias.

    martin> It would be a bit confusing to have 'resolve' and
    martin> 'resolved' exist as different commands, so I'd like
    martin> to see if we can I think, as part of
    martin> <https://bugs.edge.launchpad.net/bzr/+bug/506265> we
    martin> should remove the 'resolved' alias.

    martin> It looks like you're planning to keep the general
    martin> model that after a merge your working tree is marked
    martin> with some things as conflicted, which I think is
    martin> fine.  We can then let the user deal with the
    martin> conflicts either by running a sequence of
    martin> non-interactive commands, or by popping into
    martin> something that asks them questions about a whole
    martin> series of conflicts.

So I stepped back from doing so in the core and decided to leave
that for GUIs.

The rationale is that:
1) We need to provide a scripted way to access the feature,

2) As soon as we let the user modify the working tree *during* an
interactive session, there are a lot more checking that needs to
be done and a lot more work to make the code more robust.

GUIs can build interactive sessions on top of that as long as we
provide the necessary steps:

- list the conflicts,
- list the possible actions for a given conflict,
- resolve a given conflict with a given action.

Implementing a GUI presenting the list of conflicts with a menu
containing the possible actions for each one should then become
quite easy.

Having the GUI take a lock on the tree for each action should
also make the error handling easier than in the core. Performance
should not be a concern there.

    martin> That interactive resolution could even be optionally
    martin> automatically kicked off by merge.  Even in
    martin> interactive mode, it should be able to save out the
    martin> current conflict state into the tree so that you can
    martin> come back to it later.

Saving the state after any resolution is simple and already taken
into account.

    martin> This also relates a bit to remerge, which could be
    martin> cast as letting you restart the merge process on a
    martin> particular file or directory, either because you want
    martin> to try different options or because you made a
    martin> mistake.

That's another tricky area I prefer to left as is for now. Once
we get a better solution for resolving a single conflict we can
come back to it.

<snip/>

    martin> istm that for a simple text conflict in a source
    martin> file, it's actually a bit of a waste to make the
    martin> person specifically mark it as resolved.  

That's what --auto is about and it seems we could generalize it.

    martin> If they're happy with the new diff, and in particular
    martin> if they've removed all the conflict markers, I think
    martin> we should treat it as resolved.  I don't feel that
    martin> requiring 'bzr resolve' as we do at the moment is a
    martin> particularly good tradeoff, and increasing that work
    martin> by requiring 'bzr resolve --done' would be a step in
    martin> the wrong direction.

We can hook --auto into commit or even status then.

    martin> There might be some people who do want this special
    martin> step as an option.

Agreed.

    martin> Making commit do some kind of automatic resolution
    martin> could be handled separately from your work though.

Yup, as a final step, with sugar on top.

    martin> Some people might want to know all the files that
    martin> were ever conflicted in the current merge, even if
    martin> they've now resolved the conflict.  For example they
    martin> might want to review their diff especially closely.

I'm less sure about that one as I think people want to get rid of
the conflicts and just focus on the remaining ones.

But if we want to do it, we'll need to keep some sort of state in
the conflicts objects or add a separate file to support that.

Introducing a separate file may help address the transition from
one format to the other though...

<snip/>

    martin> I kind of like mine and theirs, as consistent with
    martin> missing, but perhaps they're confusing when the other
    martin> branch came from the person now running the resolve
    martin> command.

I switch from this/other to mine/theirs as I thought it made them
more "personal". When I merge a branch into my current working
tree, I clearly know which is "mine" and from there I deduce what
is "theirs" without thinking about *who* is theirs :)

<snip/>

    martin> Those sound pretty reasonable to fix.

    martin> I guess this leaves me wondering: what happens if I
    martin> just say 'bzr resolve F' without saying how to
    martin> resolve it?  Maybe it should tell me what my options
    martin> are?

That's an option. I proposed using 'bzr conflicts -v FILE' for
that.

    martin> There's a related bug about making sure people don't
    martin> accidentally add .moved etc files.  Perhaps that can
    martin> be handled by making sure they're unversioned, having
    martin> a special category of conflict files, and refusing to
    martin> add or commit them.

Yes, I didn't mention it as it requires better support to make
sure the conflict objects unambiguously knows which files have
been generated. NonDirectoryParent for example does not store the
'.new' path forcing us to guess it at resolution time. There is
also ParentLoop that deals with '.moved' dirs where both paths
*are* versioned which make the decision harder (if '.moved' was
'.THIS or '.OTHER' it would be clearer though).

Also, I toyed a bit with following idea: for text conflicts, bzr
leave the working tree in a unusable state (rightly so IMO) by
leaving conflicted regions (you're not supposed to be able to
compile such files). We don't do that for all tree shape
conflicts, instead there is HandledPathConflict (the base class
for many conflict classes) that pre-resolve the conflict (in
essence doing --keep-mine or --take-theirs upfront).

When possible, I'd like to *avoid* doing that and instead leave
FILE.THIS and FILE.OTHER in the working tree (ParentLoop may be
problematic though) so the user can better understand what is
coming from where and what the conflict is about[1]. The drawback
is that the working tree is less usable after a merge.

     Vincent



More information about the bazaar mailing list