Google Summer of Code '19: Add functionality to store an unresolved merge-state

Navaneeth Suresh navaneeths1998 at
Wed May 15 08:10:10 EDT 2019

On Tue, May 14, 2019 at 5:51 PM Pierre-Yves David <
pierre-yves.david at> wrote:

> On 5/12/19 8:31 PM, Navaneeth Suresh wrote:
> > Hello everyone,
> >
> > I am Navaneeth Suresh, one of the GSoC '19 students with Mercurial. I
> > wanted to discuss my project on adding functionality to store an
> > unresolved merge-state[1]
> > <
>> with
> > the community. Having gone through past mailing list archives on similar
> > issues, I got some ideas on the implementation of the project. However,
> > there can be other alternatives and I might encounter some issues which
> > I might not aware of. So, I'm sharing my idea of implementation.
> >
> > As said by @marmoute, we are storing only one active unresolved
> > merge-state.
> Yes, the active merge state exists in .hg/merge/. It is used for the
> operation the triggered a merge (hg merge, hg rebase, etc) and will
> exist until the merge is concluded or aborted.
> As far as I understand your project, is to offer a third alternative:
> delaying the merge resolution until later. Right ?

Yes. For example, if a user wants to fix an urgent bug without losing their
partly done enormous conflict resolution, this project will help them to
store the conflicts and resume the resolution after fixing the bug. In the
current scenario, they are only allowed to either fully discard or complete
the partly done resolution to perform a new commit.

> How do you see the final user experience? What is the workflow to delay
> and later conclude/abort a merge? (note: there are some UX details from
> you later in this email, but it probably worth being explained
> independently).

>From the UI point of view, it appeared to me as shelving with conflicts. I
thought of introducing two commands `hg store-conflicts` and `hg
restore-conflicts`. For the user, it should be pretty easy to get things
done. But, as you told, it should require much work and the internal
workflow might be complex. (in the later part of the mail)

> > I am thinking to store it as a visible commit under a
> > bookmark having the prefix `conflict/`.
> That seems strange. We usually don't do this "data behind a bookmark
> namespace" in Mercurial. We have a "internal" phase dedicated to commit
> that are internal by product. That would be more appropriate.
> However, I am not sure we actually need a special commit. We could store
> conflict directly into the commit they intend to be part once resolved.
> That would simplify the storage and the UX. (more on that later)

We might require a special commit as this changeset shows properties which
are different from normal commits (not publishable nature, etc.) But, we
can make use of tools you suggested such as extra mapping.

> > This should contain metadata
> > about the files which are marked as resolved/unresolved by the user. I
> > have coded this and made this work by respecting both parents without
> > changing the default behavior of `localrepo.commit()` (adding metadata
> > about conflicts part is left.)
> What format do you intend to use. What do you plan to do to preserve the
> file content

I had a look at the old Imerge extension's format which was used to split a
merge into pieces and it looked good to me. In my proposed method, it
shouldn't allow another merge after `hg store-conflicts` until the user
triggers `hg restore-conflicts`. So, the merge-state living at .hg/merge
can be used for `hg restore-conflicts`. (Note that my official proposal
doesn't include bookmarks and it deals with hidden commits for conflicts)

> > This conflicted state can be later
> > restored by rebasing the tip on the top of the commit just before the
> > conflict commit and stripping the conflict commit from the DAG. The
> > restoring functionality is much hypothetical at the moment and there are
> > things to investigate on that.
> Okay, the workflow is a bit clearer to me now. However it seems quite
> complicated. I would propose a slightly different approach. Let me start
> with a simple example:
> You are trying to do a merge but there are conflict.
>    $ hg merge
>    3 files updated, 2 files merged, 0 files removed, 2 files unresolved
> Some of the file can be resolved, but one of the conflict remains
> difficult and you need to delay its resolution
>    $ hg resolve -l
>    R foo
>    U bar
> My idea would be add a flag to make it possible to commit anyway.
> Something like:
>    $ hg commit --unresolved


> At that point we have a "regular" merge commit but with some
> "unresolved" flag. And the related data can also be stored there.
> At that point, this "unresolved" commit cannot move to the public phase.
>    $ hg phase --public

IIRC, @pulkit told me that the new changeset by the user after committing
the unresolved files shouldn't come as a child of the "unresolved" commit.
This is to stop getting the "unresolved" commits published.

> However it can get resolved.
>    $ hg up YOURMERGE
>    $ hg resolve -l
>    R foo
>    U bar
>    $ hg resolve bar
>    $ hg resolve -l
>    R foo
>    R bar
> And the merge can be concluded (not sure of the UI)
>    $ hg merge --continue
> or maybe.
>    $ hg amend

`hg amend` sounds sweet to me. But, as of now, a user is not allowed to
amend changeset with children. (Note that the DAG has other changesets
after "conflict" commit. I think you assumed the user has commits directly
on top of the "conflict" commit)

> > If anyone of you has other thoughts on the implementation, I would love
> > to hear that. Also, pros, cons, feasibility, etc. on this proposed way
> > of implementation are also welcome.
> We need a plan that works well for:
>    * hg merge
>    * hg rebase & co (similar to merge, but a bit different)
>    * hg update
>    * hg shelve
> The approach of "just do a regular commit" works well for `hg merge` and
> `hg rebase`. It is a bit less clear with `hg shelve` and `hg update` and
>   need more thinking.
> The idea also comes with interesting properties, for example, you can
> shelve an unresolved merge.

IIUC, shelving an unresolved merge and unshelving that later constitutes
the main part of the project. I stopped thinking about that approach
because this also involves sharing the "conflict" changesets with other
users so that they can help with the resolution (I thought of adding
something like --with-conflicts to push and pull commands.)

> The main technical questions are:
> A) How do we flag a changesets as "unresolved"

The extra mapping {'internal' : 'unresolved'} looks good to me.

> b) Where do we store the usual merge-state information ?

I thought of reusing the merge-state information stored at .hg/merge. To be
curious, is allowing a merge after storing a file with conflict required?
Otherwise, we can use the same information.

> c) Where we store the multiple alternative content for the unresolved
> file (local version, current version, [remote version])

.hg/merge (if we are not cleaning the merge-state and thereby not allowing
a merge before restoring the "conflict" commit)

> I believe all of the above can be solved with a combination of existing
> tools. changesets, extra, manifest flag, revlog metadata.
> I can also see a couple of other technical questions.
> * preventing unresolved changeset publishing

This project also involves "conflict" changeset publishing feature when
explicitly called by the user. (I have already talked about this)

> * propagating unresolution (what happen when you rebase a change to a
> file unresolved

> And of course the general question of the user experience and comand
> workflow
> If you like the plan, we can discuss it more. Can help you to clarify
> the remaining questions and design the technical bits. I suggest we
> focus on `hg merge` for now. This is the simplest case.

I quite liked the plan. I always wanted to split things into pieces and
work on one by one. This isn't possible per se in my proposed method(which
is still incomplete). However, some things aren't clear enough at this
point. I would like to go with your method. I hope now you have a better
idea of the project. From now on, I would like to focus on your proposed
method starting from `hg merge`. Thank you for this. What should be a
kickstart in your opinion?

> Cheers,
> --
> Pierre-Yves David
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the Mercurial-devel mailing list