hg rollback / hg revert / hg ?? a merge - hg merge could tell it to the user

5,453 views
Skip to first unread message

rupert.thurner

unread,
Jun 25, 2010, 9:24:42 AM6/25/10
to merc...@selenic.com
it would be very nice if mercurial would give a hint on how to abort a
merge. maybe it could write:

$ hg merge
(branch merge, don't forget to commit. abort with hg rollback)

and then one tries to:

$ hg revert --all
abort: uncommitted merge - please provide a specific revision

$ hg rollback
(rolls back the last checked in revision and merges something into the
merge as well ...)

rupert.
_______________________________________________
Mercurial mailing list
Merc...@selenic.com
http://selenic.com/mailman/listinfo/mercurial

Mads Kiilerich

unread,
Jun 25, 2010, 9:55:10 AM6/25/10
to rupert.thurner, merc...@selenic.com
On 06/25/2010 03:24 PM, rupert.thurner wrote:
> it would be very nice if mercurial would give a hint on how to abort a
> merge. maybe it could write:
>
> $ hg merge
> (branch merge, don't forget to commit. abort with hg rollback)

That is however not correct.

rollback will roll back a commit, but merge will not do a commit.
rollback will thus roll something else back - so don't do that.

A right way to undo a merge is "hg update -C". That is however the
answer to the general "how do I drop the uncommitted changes I have in
my working directory" question, so it would be a bit strange to say that
explicitly here. It would perhaps be just as relevant in all "hg status"
output.

I think that Mercurial generally seems to be less verbose than for
example git. We have at most one line of suggestions in the output. We
try to make Mercurial so simple that you don't need more than that ;-)

/Mads

Jason Harris

unread,
Jun 25, 2010, 10:07:35 AM6/25/10
to Mads Kiilerich, rupert.thurner, Mercurial Mailing-list
Yep.

'hg undo' would be nice here to just do the right thing...

Cheers,
Jas

Mads Kiilerich

unread,
Jun 25, 2010, 10:16:18 AM6/25/10
to Jason Harris, rupert.thurner, Mercurial Mailing-list
On 06/25/2010 04:07 PM, Jason Harris wrote:
> Yep.
>
> 'hg undo' would be nice here to just do the right thing...

Yes, we really need a "hg dwim" command.

Michael Diamond

unread,
Jun 25, 2010, 11:57:52 AM6/25/10
to Mads Kiilerich, Mercurial Mailing-list
On Fri, Jun 25, 2010 at 7:16 AM, Mads Kiilerich <ma...@kiilerich.com> wrote:
On 06/25/2010 04:07 PM, Jason Harris wrote:
Yep.

'hg undo' would be nice here to just do the right thing...

Yes, we really need a "hg dwim" command.

Why not just create an alias mapping 'undo' or 'dwim' to 'hg update -C'?

Matt Mackall

unread,
Jun 25, 2010, 12:48:55 PM6/25/10
to Michael Diamond, Mads Kiilerich, Mercurial Mailing-list
On Fri, 2010-06-25 at 08:57 -0700, Michael Diamond wrote:
> On Fri, Jun 25, 2010 at 7:16 AM, Mads Kiilerich <ma...@kiilerich.com>
> wrote:
> On 06/25/2010 04:07 PM, Jason Harris wrote:
> Yep.
>
> 'hg undo' would be nice here to just do the right
> thing...
>
>
> Yes, we really need a "hg dwim" command.
>
>
>
> Why not just create an alias mapping 'undo' or 'dwim' to 'hg update
> -C'?
> http://www.selenic.com/mercurial/hgrc.5.html#alias

Because "clobber all my local changes" is rarely equivalent to "do what
I mean".

Generally speaking, we don't know how to "undo" a merge. We only know
how to clobber it.


--
Mathematics is the supreme nostalgia of our time.

rupert THURNER

unread,
Jun 26, 2010, 7:42:52 AM6/26/10
to Mads Kiilerich, merc...@selenic.com
On Fri, Jun 25, 2010 at 15:55, Mads Kiilerich <ma...@kiilerich.com> wrote:
> On 06/25/2010 03:24 PM, rupert.thurner wrote:
>>
>> it would be very nice if mercurial would give a hint on how to abort a
>> merge. maybe it could write:
>>
>> $ hg merge
>> (branch merge, don't forget to commit. abort with hg rollback)
>
> That is however not correct.
>
> rollback will roll back a commit, but merge will not do a commit. rollback
> will thus roll something else back - so don't do that.
>
> A right way to undo a merge is "hg update -C". That is however the answer to

i needed aborting a merge 3 times in four years. every single time i
tried to look up the command and did not find it again. but hg merge
tells me that i should not forget a commit, which i need once a day. i
created a patch to include this as well in the output.

> the general "how do I drop the uncommitted changes I have in my working
> directory" question, so it would be a bit strange to say that explicitly
> here. It would perhaps be just as relevant in all "hg status" output.

oh? i thought that is "hg revert"? the comment for revert says:

"
(Use update -r to check out earlier revisions, revert does not change the
working directory parents.)
"

and is what should happen: i do not want to change the working
directory parents, it should be the same as before the merge. just
like "hg add" and all other actions can be undone with a revert.

from a technical standpoint, the "update -C" is ok, but unfortunately
it is difficult to understand and remember.

rupert.

Wagner Bruna

unread,
Jun 26, 2010, 9:23:37 PM6/26/10
to rupert THURNER, merc...@selenic.com
rupert THURNER wrote:
> On Fri, Jun 25, 2010 at 15:55, Mads Kiilerich <ma...@kiilerich.com> wrote:
>> On 06/25/2010 03:24 PM, rupert.thurner wrote:
>>> it would be very nice if mercurial would give a hint on how to abort a
>>> merge. maybe it could write:
>>>
>>> $ hg merge
>>> (branch merge, don't forget to commit. abort with hg rollback)
>> That is however not correct.
>>
>> rollback will roll back a commit, but merge will not do a commit. rollback
>> will thus roll something else back - so don't do that.
>>
>> A right way to undo a merge is "hg update -C". That is however the answer to
>
> i needed aborting a merge 3 times in four years. every single time i
> tried to look up the command and did not find it again. but hg merge
> tells me that i should not forget a commit, which i need once a day. i
> created a patch to include this as well in the output.
>
>> the general "how do I drop the uncommitted changes I have in my working
>> directory" question, so it would be a bit strange to say that explicitly
>> here. It would perhaps be just as relevant in all "hg status" output.
>
> oh? i thought that is "hg revert"? the comment for revert says:
>
> "
> (Use update -r to check out earlier revisions, revert does not change the
> working directory parents.)
> "
>
> and is what should happen: i do not want to change the working
> directory parents, it should be the same as before the merge.

But the merge itself changed the parents: it added the other revision as the second
parent! Try "hg parents" before and after a merge.

As suggested, to "undo" a merge, meaning "go back to the state just before the
merge", you typically run "hg update --clean .", meaning "give me back the original
revision I had before (update .), throwing away all this stuff (--clean)".

Regards,
Wagner

Mads Kiilerich

unread,
Jun 28, 2010, 9:06:16 AM6/28/10
to rupert THURNER, merc...@selenic.com
On 06/26/2010 01:42 PM, rupert THURNER wrote:
> On Fri, Jun 25, 2010 at 15:55, Mads Kiilerich<ma...@kiilerich.com> wrote:
>> On 06/25/2010 03:24 PM, rupert.thurner wrote:
>>>
>>> it would be very nice if mercurial would give a hint on how to abort a
>>> merge. maybe it could write:
>>>
>>> $ hg merge
>>> (branch merge, don't forget to commit. abort with hg rollback)
>>
>> That is however not correct.
>>
>> rollback will roll back a commit, but merge will not do a commit. rollback
>> will thus roll something else back - so don't do that.
>>
>> A right way to undo a merge is "hg update -C". That is however the answer to
>
> i needed aborting a merge 3 times in four years. every single time i
> tried to look up the command and did not find it again. but hg merge
> tells me that i should not forget a commit, which i need once a day. i
> created a patch to include this as well in the output.

Yes, merge might be the place where it is most likely that users will
need "up -C" most often - and for the first time.

For this reason it might make sense to mention it.

> from a technical standpoint, the "update -C" is ok, but unfortunately
> it is difficult to understand and remember.

I tend to agree. Perhaps a more convenient alias could be added, but
right now "hg update --clean ." is the right way to do it.

/Mads

Greg Ward

unread,
Jun 29, 2010, 9:57:33 AM6/29/10
to Mads Kiilerich, rupert THURNER, merc...@selenic.com
On Mon, Jun 28, 2010 at 9:06 AM, Mads Kiilerich <ma...@kiilerich.com> wrote:
> I tend to agree. Perhaps a more convenient alias could be added, but right
> now "hg update --clean ." is the right way to do it.

IMHO there should not be a convenient alias for "update -C .". The
whole purpose of "update -C ." is to destroy information. It throws
away any uncommitted changes in your working directory. It's
*dangerous*! It's also essential, of course, which is why it exists.
And yes, it should definitely be mentioned in the help for merge,
using words like "discard uncommitted changes with no way to recover
them". I'm neutral on mentioning it in an advisory message: that
seems like inviting some poor unsuspecting soul to destroy their
uncommitted changes when that's not really what they meant to do.

Greg

rupert THURNER

unread,
Jul 1, 2010, 5:11:27 PM7/1/10
to Greg Ward, merc...@selenic.com
On Tue, Jun 29, 2010 at 15:57, Greg Ward <gre...@gerg.ca> wrote:
> On Mon, Jun 28, 2010 at 9:06 AM, Mads Kiilerich <ma...@kiilerich.com> wrote:
>> I tend to agree. Perhaps a more convenient alias could be added, but right
>> now "hg update --clean ." is the right way to do it.
>
> IMHO there should not be a convenient alias for "update -C .".  The
> whole purpose of "update -C ." is to destroy information.  It throws
> away any uncommitted changes in your working directory.  It's
> *dangerous*!  It's also essential, of course, which is why it exists.

the first try was "revert" which has the same effect - it is what the
user wants to do.

rupert.

anatoly techtonik

unread,
Jul 7, 2012, 3:26:42 AM7/7/12
to mercuria...@googlegroups.com, merc...@selenic.com
On Saturday, June 26, 2010 3:42:52 PM UTC+4, rupert.thurner wrote:
On Fri, Jun 25, 2010 at 15:55, Mads Kiilerich <mads@kiile....com> wrote:
> On 06/25/2010 03:24 PM, rupert.thurner wrote:
>>
>> it would be very nice if mercurial would give a hint on how to abort a
>> merge. maybe it could write:
>>
>> $ hg merge
>> (branch merge, don't forget to commit. abort with hg rollback)
>
> That is however not correct.
>
> rollback will roll back a commit, but merge will not do a commit. rollback
> will thus roll something else back - so don't do that.
>
> A right way to undo a merge is "hg update -C". That is however the answer to

i needed aborting a merge 3 times in four years. every single time i
tried to look up the command and did not find it again.

So true. Such a time waste.. and a needless distraction.

$ hg rollback
repository tip rolled back to revision 2699 (undo commit)
working directory now based on revisions 2694 and 2699
$ hg up
abort: outstanding uncommitted merges
$ hg st
M CHANGELOG
M pyglet/__init__.py
...
$ hg revert --all
abort: uncommitted merge with no revision specified
(use "hg update" or see "hg help revert")
$ hg revert -R . -f
hg revert: option -f not recognized
$ hg rollback
no rollback information available
$ hg help revert
...
$ hg update -h
...
$ google-chrome
 

from a technical standpoint, the "update -C" is ok, but unfortunately

it is difficult to understand and remember.

+1

The message for this use case is misleading:
'abort: uncommitted merge with no revision specified
(use "hg update" or see "hg help revert")'

"hg help revert" won't help here as well as "hg update". And even if changed to "hg update -C" (which would solve my problem) - it won't make Mercurial any less mystic. I naturally tried --force flag to "revert bloody anything I don't care", which IMHO is better than magical git-like "update -C".

Adrian Buehlmann

unread,
Jul 7, 2012, 4:23:24 AM7/7/12
to rupert THURNER, merc...@selenic.com
On 2010-06-26 13:42, rupert THURNER wrote:
> On Fri, Jun 25, 2010 at 15:55, Mads Kiilerich <ma...@kiilerich.com> wrote:
[...]
>> A right way to undo a merge is "hg update -C ." [...]
>
> i needed aborting a merge 3 times in four years. every single time i
> tried to look up the command and did not find it again. [...]

Please have a look at http://selenic.com/repo/hg/rev/eac141407b85

which is:

# HG changeset patch
# User Matt Mackall <m...@selenic.com>
# Date 1277678503 18000
# Node ID eac141407b854b90b81eef4e6e6ecc86f7ab06f1
# Parent 51021f4c80b5dcf608626ddc24b21c155df2cae8
merge: document how to 'undo' a merge

diff -r 51021f4c80b5 -r eac141407b85 mercurial/commands.py
--- a/mercurial/commands.py Sun Jun 27 23:12:05 2010 +0200
+++ b/mercurial/commands.py Sun Jun 27 17:41:43 2010 -0500
@@ -2570,6 +2570,10 @@
head, the other head is merged with by default. Otherwise, an
explicit revision with which to merge with must be provided.

+ To undo an uncommitted merge, use :hg:`update --clean .` which
+ will check out a clean copy of the original merge parent, losing
+ all changes.
+
Returns 0 on success, 1 if there are unresolved files.
"""

That change was committed on 2010-06-28 on Mercurial's stable branch and
first appeared in Mercurial 1.6, which was released a few days after
that. So that help text has been there for two years now.

So, you probably must have done your 3 merge aborts with a version of
Mercurial < 1.6, or you didn't really read 'hg help merge'.

For your reference, the full help text can also be read at:
http://selenic.com/repo/hg/help/merge

anatoly techtonik

unread,
Jul 7, 2012, 4:41:23 AM7/7/12
to mercuria...@googlegroups.com, rupert THURNER, merc...@selenic.com
On Sat, Jul 7, 2012 at 11:23 AM, Adrian Buehlmann <adr...@cadifra.com> wrote:
> On 2010-06-26 13:42, rupert THURNER wrote:
>> On Fri, Jun 25, 2010 at 15:55, Mads Kiilerich <ma...@kiilerich.com> wrote:
> [...]
>>> A right way to undo a merge is "hg update -C ." [...]
>>
>> i needed aborting a merge 3 times in four years. every single time i
>> tried to look up the command and did not find it again. [...]
>
> Please have a look at http://selenic.com/repo/hg/rev/eac141407b85
>
> which is:
>
> # HG changeset patch
> # User Matt Mackall <m...@selenic.com>
> # Date 1277678503 18000
> # Node ID eac141407b854b90b81eef4e6e6ecc86f7ab06f1
> # Parent 51021f4c80b5dcf608626ddc24b21c155df2cae8
> merge: document how to 'undo' a merge

...

> That change was committed on 2010-06-28 on Mercurial's stable branch and
> first appeared in Mercurial 1.6, which was released a few days after
> that. So that help text has been there for two years now.
>
> So, you probably must have done your 3 merge aborts with a version of
> Mercurial < 1.6, or you didn't really read 'hg help merge'.
>
> For your reference, the full help text can also be read at:
> http://selenic.com/repo/hg/help/merge

Thanks. But I am running 2.2.2. And if you read my command log once
more you'll see that I haven't even tried to read `hg help merge`.
Most likely because Mercurial misguided me to 'hg update' and 'hg help
revert'. It is still a waste of time two years later.
--
anatoly t.

Adrian Buehlmann

unread,
Jul 7, 2012, 4:59:48 AM7/7/12
to anatoly techtonik, mercuria...@googlegroups.com, rupert THURNER, merc...@selenic.com
According to your "command log"

On 2012-07-07 09:26, anatoly techtonik wrote:
> So true. Such a time waste.. and a needless distraction.
>
> $ hg rollback
> repository tip rolled back to revision 2699 (undo commit)
> working directory now based on revisions 2694 and 2699
> $ hg up
> abort: outstanding uncommitted merges
> $ hg st
> M CHANGELOG
> M pyglet/__init__.py
> ...
> $ hg revert --all
> abort: uncommitted merge with no revision specified
> (use "hg update" or see "hg help revert")
> $ hg revert -R . -f
> hg revert: option -f not recognized
> $ hg rollback
> no rollback information available
> $ hg help revert
> ...
> $ hg update -h
> ...
> $ google-chrome

you first tried a rollback.

What was your motivation for doing that?

The help text of rollback is:

<paste>
hg rollback

roll back the last transaction (dangerous)

This command should be used with care. There is only one level of
rollback, and there is no way to undo a rollback. It will also restore
the dirstate at the time of the last transaction, losing any dirstate
changes since that time. This command does not alter the working
directory.
</paste>

So why would you use that?

The help text of rollback is pretty clear:

(a) ".... (dangerous)"
(b) "... no way to undo a rollback"
(c) "... does not alter the working directory"

If you blindly go trying random commands, starting with "hg rollback" and
then claim Mercurial for having wasted your time, then you are rather
wasting our time here, I'd say.

anatoly techtonik

unread,
Jul 7, 2012, 5:08:13 AM7/7/12
to Adrian Buehlmann, mercuria...@googlegroups.com, rupert THURNER, merc...@selenic.com
Why people are doing rollbacks? Probably because they've done
something wrong. In my case it was wrong merge. I've done it from the
wrong tip after update (which brought double heads) and couldn't
understand the diff, so I had to make it from the other tip.

Augie Fackler

unread,
Jul 7, 2012, 10:57:32 AM7/7/12
to anatoly techtonik, mercuria...@googlegroups.com, rupert THURNER, merc...@selenic.com
On Jul 7, 2012, at 5:08 AM, anatoly techtonik wrote:

> On Sat, Jul 7, 2012 at 11:59 AM, Adrian Buehlmann <adr...@cadifra.com> wrote:
>> On 2012-07-07 10:41, anatoly techtonik wrote:
>>> On Sat, Jul 7, 2012 at 11:23 AM, Adrian Buehlmann <adr...@cadifra.com> wrote:
>>>> On 2010-06-26 13:42, rupert THURNER wrote:
>>>>> On Fri, Jun 25, 2010 at 15:55, Mads Kiilerich <ma...@kiilerich.com> wrote:
>>>> [...]
>>>>>> A right way to undo a merge is "hg update -C ." [...]
>>>>>
FYI, for 3 years we've printed how to abandon the merge as soon as a
conflicted merge is produced:
http://www.selenic.com/hg/rev/9fe7e6acf525

Was this not a conflicted merge that you wanted to abort?

Adrian Buehlmann

unread,
Jul 7, 2012, 3:25:21 PM7/7/12
to anatoly techtonik, mercuria...@googlegroups.com, rupert THURNER, merc...@selenic.com
I've sent a proposal for a patch

http://selenic.com/pipermail/mercurial-devel/2012-July/042542.html

'''
rollback: require --force if there is an uncommitted merge (BC)

This change now causes rollback to abort with

$ hg rollback
abort: uncommitted merge
(use 'hg update -C .' to undo the merge and lose all changes, or -f to force)

on uncommitted merges.

Option -f/--force is now required in this situation to do the rollback.
'''

anatoly techtonik

unread,
Jul 7, 2012, 8:34:09 PM7/7/12
to Augie Fackler, Adrian Buehlmann, mercuria...@googlegroups.com, rupert THURNER, merc...@selenic.com
Yes, the merge was non-conflicting, but that doesn't mean application was
still operational after that. Merge was made from the wrong tip and I could
not validate that changes are merged correctly and without anything
that may could have been standing uncommited. I was distracted during the
process and this contributed to the lost sense of confidence. So I
decided to rollback and redo the merge properly from the right tip.

As I was distracted, I couldn't not remember if HG should complain about
had uncommitted changes before the merge. Now I think it should, but I
couldn't scroll back to see if my copy was clean (I usually run `hg
st` before anything important), because resulting `hg diff` output
appeared too huge to fit the buffer. So I've executed `hg rollback`.
--
anatoly t.

anatoly techtonik

unread,
Jul 7, 2012, 8:41:50 PM7/7/12
to Adrian Buehlmann, mercuria...@googlegroups.com, rupert THURNER, merc...@selenic.com
On Sat, Jul 7, 2012 at 10:25 PM, Adrian Buehlmann <adr...@cadifra.com> wrote:
> I've sent a proposal for a patch
>
> http://selenic.com/pipermail/mercurial-devel/2012-July/042542.html
>
> '''
> rollback: require --force if there is an uncommitted merge (BC)
>
> This change now causes rollback to abort with
>
> $ hg rollback
> abort: uncommitted merge
> (use 'hg update -C .' to undo the merge and lose all changes, or -f to force)
>
> on uncommitted merges.
>
> Option -f/--force is now required in this situation to do the rollback.
> '''

In my case I did rollback on committed merge. The merge went fine, so
I've commited it and only then realized that the modified files are
outside of my changes scope. What will help is --force parameter to
revert, because rollback for the second time gives:

Adrian Buehlmann

unread,
Jul 8, 2012, 2:47:31 AM7/8/12
to anatoly techtonik, mercuria...@googlegroups.com, rupert THURNER, merc...@selenic.com
On 2012-07-08 02:41, anatoly techtonik wrote:
> On Sat, Jul 7, 2012 at 10:25 PM, Adrian Buehlmann <adr...@cadifra.com> wrote:
>> I've sent a proposal for a patch
>>
>> http://selenic.com/pipermail/mercurial-devel/2012-July/042542.html
>>
>> '''
>> rollback: require --force if there is an uncommitted merge (BC)
>>
>> This change now causes rollback to abort with
>>
>> $ hg rollback
>> abort: uncommitted merge
>> (use 'hg update -C .' to undo the merge and lose all changes, or -f to force)
>>
>> on uncommitted merges.
>>
>> Option -f/--force is now required in this situation to do the rollback.
>> '''
>
> In my case I did rollback on committed merge. The merge went fine, so
> I've commited it and only then realized that the modified files are
> outside of my changes scope.

I admit I overlooked that first, but I think my proposed change is still
an improvement. Because of your second rollback call (which you by now
should have understood that it was the wrong command to use in that
situation). Read on.

> What will help is --force parameter to
> revert, because rollback for the second time gives:
>
> $ hg rollback
> no rollback information available

While my proposed change may not have forced you to do less of mess (and
finally start reading help pages before just blindly trying random
commands after the first rollback), what you say above about my proposed
change is not entirely correct.

You first did:

> $ hg rollback
> repository tip rolled back to revision 2699 (undo commit)
> working directory now based on revisions 2694 and 2699

What happened there is, the rollback rolled back the commit of the bad
merge.

So what you had after that was an _uncommitted merge_, as Mercurial told
you that the working directory had *two* parents after that first
rollback (2694 and 2699).

[myself.TODO: Ponder if it's really a good idea to let rollback set two
parents when rolling back a merge commit. I strongly suspect it is a
good idea.]

Then, after first doing some more tries, you also did a second rollback:

> $ hg rollback
> no rollback information available

I happen to have made my proposed change for rollback (lucky me?) so
that the 'uncommitted merge' check is done before anything else.

So, with my proposed change, your second (misapplied) rollback still
would have gone like this:

$ hg rollback
abort: uncommitted merge
(use 'hg update -C .' to undo the merge and lose all changes, or -f to
force)

So this would have hinted you there how to get out of that uncommitted
merge state you were in (after the first rollback).

I'm still convinced my proposed change is an improvement, as it also
covers the more frequent (I believe) case where people wrongfully reach
for rollback after they have decided that 'hg merge' was not what they
want and they want to get out of the uncommitted merge state they are in.

This is not to say that further improvements may not be possible. But we
have already spent considerable time improving the abort messages on
revert. I the end, we can't really do much if users don't read help pages.

Adrian Buehlmann

unread,
Jul 8, 2012, 3:26:48 AM7/8/12
to anatoly techtonik, mercuria...@googlegroups.com, rupert THURNER, merc...@selenic.com
On 2012-07-08 02:41, anatoly techtonik wrote:
> [..] What will help is --force parameter to
> revert, [..]

(I need to address that in a separate email. That's a discussion about
"revert")

You said you did:

> $ hg revert --all
> abort: uncommitted merge with no revision specified
> (use "hg update" or see "hg help revert")

Revert never changes the parent revision(s).

It also happens to be the case that the --all option is the equivalent
for "force" on that command.

With --all on revert you are saying to Mercurial "I don't care what
files I may have modified, revert *everything*". That's already forcing.

But you still need to understand what revert is supposed to do.

Again: Revert isn't supposed to change parent revisions. So that command
possibly can't help to get you out of an uncommitted merge state.

Mercurial there tried to convince you to read the help for revert, which
starts with:

$ hg help revert
hg revert [OPTION]... [-r REV] [NAME]...

restore files to their checkout state

Note:
To check out earlier revisions, you should use "hg update
REV". To cancel a merge (and lose your changes), use
"hg update --clean .".

[...]

anatoly techtonik

unread,
Jul 8, 2012, 4:55:46 AM7/8/12
to Adrian Buehlmann, mercuria...@googlegroups.com, rupert THURNER, merc...@selenic.com
On Sun, Jul 8, 2012 at 10:26 AM, Adrian Buehlmann <adr...@cadifra.com> wrote:
> On 2012-07-08 02:41, anatoly techtonik wrote:
>> [..] What will help is --force parameter to
>> revert, [..]
>
> (I need to address that in a separate email. That's a discussion about
> "revert")
>
> You said you did:
>
>> $ hg revert --all
>> abort: uncommitted merge with no revision specified
>> (use "hg update" or see "hg help revert")
>
> Revert never changes the parent revision(s).
>
> It also happens to be the case that the --all option is the equivalent
> for "force" on that command.
>
> With --all on revert you are saying to Mercurial "I don't care what
> files I may have modified, revert *everything*". That's already forcing.
>
> But you still need to understand what revert is supposed to do.
>
> Again: Revert isn't supposed to change parent revisions. So that command
> possibly can't help to get you out of an uncommitted merge state.

I don't know how parent revisions are involved. From the user point of
view 'rollback' is used to cancel commit and bring back working copy
to dirty state. 'revert --all' is used to bring working copy to the
clean state. I don't understand why revert is supposed to threat merge
case somewhat differently. You should agree that "revert possibly
can't help" is not an good explanation.

If you mean that information which tip revision is lost when how
"update -C" figures out which parent revision should be made the tip?

> Mercurial there tried to convince you to read the help for revert, which
> starts with:
>
> $ hg help revert
> hg revert [OPTION]... [-r REV] [NAME]...
>
> restore files to their checkout state
>
> Note:
> To check out earlier revisions, you should use "hg update
> REV". To cancel a merge (and lose your changes), use
> "hg update --clean .".
>
> [...]

We've started with the point that it is possible to make HG interface
more intuitive rather than require users to read up on magic keys and
command details. If you see I actually called `hg revert -h` and I can
name two reason why I missed this info:

1. hg still doesn't have paginated output, so the note just slipped away
2. the first sentence is not related to my use case, so I
automatically skipped this paragraph

If I had time to enjoy reading docs, I'd of course wouldn't skim them,
but when you don't have a clear entrypoint you never know how much
reading you need to exercise. And here Google is the best friend.
Instead of proper documentation I found this thread.
--
anatoly t.

Adrian Buehlmann

unread,
Jul 8, 2012, 5:30:09 AM7/8/12
to anatoly techtonik, mercuria...@googlegroups.com, rupert THURNER, merc...@selenic.com
On 2012-07-08 10:55, anatoly techtonik wrote:
> On Sun, Jul 8, 2012 at 10:26 AM, Adrian Buehlmann <adr...@cadifra.com> wrote:
>> On 2012-07-08 02:41, anatoly techtonik wrote:
>>> [..] What will help is --force parameter to
>>> revert, [..]
>>
>> (I need to address that in a separate email. That's a discussion about
>> "revert")
>>
>> You said you did:
>>
>>> $ hg revert --all
>>> abort: uncommitted merge with no revision specified
>>> (use "hg update" or see "hg help revert")
>>
>> Revert never changes the parent revision(s).
>>
>> It also happens to be the case that the --all option is the equivalent
>> for "force" on that command.
>>
>> With --all on revert you are saying to Mercurial "I don't care what
>> files I may have modified, revert *everything*". That's already forcing.
>>
>> But you still need to understand what revert is supposed to do.
>>
>> Again: Revert isn't supposed to change parent revisions. So that command
>> possibly can't help to get you out of an uncommitted merge state.
>
> I don't know how parent revisions are involved.

I'd say that's probably the key point for understanding what the working
directory is and how it works.

The working directory has one parent revision after a commit. It's the
revision the working directory is updated to.

If you do a 'hg merge' the working directory is in a intermediate state,
where it has to parent revisions. The revisions that have been merged
into the working directory (or you are still working on trying to achive
that by resolving conflicts).

If you are done preparing the merge (all conflicts resolved, build and
tests pass) you finish and "freeze" the work done for the merge and
commit it.

But until the "freeze" (the commit) has done yet, the working directory
is in a "uncommitted merge" state, where it has *two* parent revisions.

The uncommitted merge state is required to be able to make manual
changes for fixing a merge (e.g. resolving conflicts).

Use the 'hg parents' command to see the parents revisions of the working
directory.

After you have done the commit, the working directory has again one
single parent.

> From the user point of
> view 'rollback' is used to cancel commit and bring back working copy
> to dirty state.

Sort of. It's not just for commit. Every transaction can be rolled back.
For example, rollback will also roll back a pull.

So, if you did a commit, followed by a pull which actually *did* pull
some changesets, rollback will roll back the pulled changes, not the commit.

> 'revert --all' is used to bring working copy to the
> clean state.

No. That's a too simplistic understanding of revert. You can use revert
to set the contents of all files (by using --all) to *any* revision,
thereby possibly introducing changes compared to the parent revision.

Let's say the working directory is "updated to" revision 35 (single parent).

Using "revert --all -r 27" I can for example set all files to their
contents as of revision 27. Files that are different compared to
revision 35 will then show up as modified when using 'hg status'.

When you have an uncommitted merge, you can for example use revert to
set the contents of all files to one of the parent revisions. But you
have to say to which, because there are two parents. None of the two
parents are given a preference.

The revert command is more powerful than you probably think.

> I don't understand why revert is supposed to threat merge
> case somewhat differently. You should agree that "revert possibly
> can't help" is not an good explanation.

Perhaps that alone is not a good explanation. But for some reasons we
have help texts.

And on the help text for revert you will see that it won't change parent
revisions.

To throw away an uncommitted merge, you have to get rid of the second
parent.

Since revert won't change parents, you can't possibly get rid of the
second parent by using revert.

> If you mean that information which tip revision is lost when how
> "update -C" figures out which parent revision should be made the tip?

I can't figure out what you are trying to say with that. Can you try again?

>> Mercurial there tried to convince you to read the help for revert, which
>> starts with:
>>
>> $ hg help revert
>> hg revert [OPTION]... [-r REV] [NAME]...
>>
>> restore files to their checkout state
>>
>> Note:
>> To check out earlier revisions, you should use "hg update
>> REV". To cancel a merge (and lose your changes), use
>> "hg update --clean .".
>>
>> [...]
>
> We've started with the point that it is possible to make HG interface
> more intuitive rather than require users to read up on magic keys and
> command details. If you see I actually called `hg revert -h` and I can
> name two reason why I missed this info:
>
> 1. hg still doesn't have paginated output, so the note just slipped away
> 2. the first sentence is not related to my use case, so I
> automatically skipped this paragraph
>
> If I had time to enjoy reading docs, I'd of course wouldn't skim them,
> but when you don't have a clear entrypoint you never know how much
> reading you need to exercise. And here Google is the best friend.
> Instead of proper documentation I found this thread.

I'm still convinced that help texts need to be read for understanding
what the commands are supposed to do.

Perhaps, reading a book might also help to get some basic understanding.

If you don't do that, then you indeed waste your time by just trying out
commands. But then please don't complain.

anatoly techtonik

unread,
Jul 8, 2012, 6:48:36 AM7/8/12
to Adrian Buehlmann, mercuria...@googlegroups.com, rupert THURNER, merc...@selenic.com
That's clear. The question not being answered is why revert *is not
supposed* to revert merge of two parent revisions into single one in
incomplete commit? The revert help is:

$ hg revert -h
hg revert [OPTION]... [-r REV] [NAME]...

restore files to their checkout state

Isn't it a restoring files to their checkout state?

>> From the user point of
>> view 'rollback' is used to cancel commit and bring back working copy
>> to dirty state.
>
> Sort of. It's not just for commit. Every transaction can be rolled back.
> For example, rollback will also roll back a pull.
>
> So, if you did a commit, followed by a pull which actually *did* pull
> some changesets, rollback will roll back the pulled changes, not the commit.

Then a good argument against "rollback" is that it operates on
revisions level, not on incomplete states of working copy (which is
more level below).

>> 'revert --all' is used to bring working copy to the
>> clean state.
>
> No. That's a too simplistic understanding of revert.

I prefer Mercurial and recommend it over Git, because I like the
simplistic understanding. But I am ready to switch if you insist. =)

> You can use revert
> to set the contents of all files (by using --all) to *any* revision,
> thereby possibly introducing changes compared to the parent revision.

Isn't it a job of "update -r"??

> Let's say the working directory is "updated to" revision 35 (single parent).
>
> Using "revert --all -r 27" I can for example set all files to their
> contents as of revision 27. Files that are different compared to
> revision 35 will then show up as modified when using 'hg status'.

So it basically applying a reverse diff for changes in range 27:35.

> When you have an uncommitted merge, you can for example use revert to
> set the contents of all files to one of the parent revisions.

Right.

> But you
> have to say to which, because there are two parents. None of the two
> parents are given a preference.

There is a specific parent that have been tip before the merge. Are
you're saying that this information is lost? But the diff resulting
from a merge depends on which revision is parent - it is different for
each case.

> The revert command is more powerful than you probably think.

Yes, but that use case you gave is not related to merge reverting.

>> I don't understand why revert is supposed to threat merge
>> case somewhat differently. You should agree that "revert possibly
>> can't help" is not an good explanation.
>
> Perhaps that alone is not a good explanation. But for some reasons we
> have help texts.
>
> And on the help text for revert you will see that it won't change parent
> revisions.
>
> To throw away an uncommitted merge, you have to get rid of the second
> parent.
>
> Since revert won't change parents, you can't possibly get rid of the
> second parent by using revert.

Well, merge is a special operation to make a mess with working copy. I
still fail to see why you'd need yet another command to revert this
mess. I mean - it is ok - the parent is not a commit yet. It is dirty
state of working copy that spreads over to temporary state of revision
tree. This state is half-way from low level wc operation (revert) to
high level revision control (rollback). You can bring more low level
features to rollback interface or add another low level clean up
feature to revert. I am for the latter.

>> If you mean that information which tip revision is lost when how
>> "update -C" figures out which parent revision should be made the tip?
>
> I can't figure out what you are trying to say with that. Can you try again?

If you specify "update -C" - it's not necessary to specify parent to
move to, isn't it?
I've read both the book and help at least once. But I don't remember
all these gory details, and I don't have time to reread that every
time. I am not convinced that there are any technical reasons against
making HG interface more intuitive (hg revert --force). So if that a
political issue then it's up to you as a developer to listen or not.
My arguments as a user are listed. I have nothing more to add.

Adrian Buehlmann

unread,
Jul 8, 2012, 7:55:36 AM7/8/12
to anatoly techtonik, mercuria...@googlegroups.com, rupert THURNER, merc...@selenic.com
Yes. But only the files. Not the parent revisions inside .hg/dirstate.

See also http://mercurial.selenic.com/wiki/DirState#File_format
in case you're interested.

>>> From the user point of
>>> view 'rollback' is used to cancel commit and bring back working copy
>>> to dirty state.
>>
>> Sort of. It's not just for commit. Every transaction can be rolled back.
>> For example, rollback will also roll back a pull.
>>
>> So, if you did a commit, followed by a pull which actually *did* pull
>> some changesets, rollback will roll back the pulled changes, not the commit.
>
> Then a good argument against "rollback" is that it operates on
> revisions level, not on incomplete states of working copy (which is
> more level below).

Right. rollback doesn't alter the working directory (as explained in the
help text :-).

>>> 'revert --all' is used to bring working copy to the
>>> clean state.
>>
>> No. That's a too simplistic understanding of revert.
>
> I prefer Mercurial and recommend it over Git, because I like the
> simplistic understanding. But I am ready to switch if you insist. =)

If you want to say that hg is easier to use than git, then I agree. But
even for hg it's required to read and understand some help texts :-).
Especially, if you forget how to get rid of a failed merge.

I also forget at times how a specific command works and I have no
problem using the built-in help to quickly read it. The help of
Mercurial commands is pretty short and usually very carefully written. A
lot of thought has ben put into things.

If you want me to insist on something, then I insist on reading the help
texts.

>> You can use revert
>> to set the contents of all files (by using --all) to *any* revision,
>> thereby possibly introducing changes compared to the parent revision.
>
> Isn't it a job of "update -r"??

update -r <rev> will set the first parent of the working dir to <rev>
and the second partent to the nullrev and merge the files of the given
revision into your uncommitted changes.

So if you are currently at revision 356 and you have made some
uncommitted change to file X, update to revision 467 will merge changes
of X into your uncommitted X. Many people don't use update when they
have uncommitted changes though.

Revert never does such complicated things. Revert is pretty "dumb". It
just sets file contents to the contents as per the given revision.

But revert is not what you want if you want to get rid of an uncommitted
merge.

>> Let's say the working directory is "updated to" revision 35 (single parent).
>>
>> Using "revert --all -r 27" I can for example set all files to their
>> contents as of revision 27. Files that are different compared to
>> revision 35 will then show up as modified when using 'hg status'.
>
> So it basically applying a reverse diff for changes in range 27:35.

I'm not sure why that would explain things simpler than what I said
(setting the contents of the files to what they had in revision 27).

>> When you have an uncommitted merge, you can for example use revert to
>> set the contents of all files to one of the parent revisions.
>
> Right.
>
>> But you
>> have to say to which, because there are two parents. None of the two
>> parents are given a preference.
>
> There is a specific parent that have been tip before the merge. Are
> you're saying that this information is lost? But the diff resulting
> from a merge depends on which revision is parent - it is different for
> each case.
>
>> The revert command is more powerful than you probably think.
>
> Yes, but that use case you gave is not related to merge reverting.

There is no such concept as merge reverting. You have to use update to
update has some rules to pick a default revision where to update to. If
you don't specify "." (=current first parent of working directory), then
you might possibly be surprised.
That's surprising. Given how much time you invest to write here :-)

> I am not convinced that there are any technical reasons against
> making HG interface more intuitive (hg revert --force).

There are no technical reasons, no. But you would have to make a
convincing point for what change exactly would be needed to make things
better and why the change would make things better. At the moment I -
for one - haven't seen a convincing argument yet.

Like I already said, "--all" on revert plays the role of the "force" option.

Matt and I had extensive discussions about these things in the past. The
result is what you have in Mercurial now. You might find these
discussions in the archives of the mercurial-devel mailing list.

> So if that a
> political issue then it's up to you as a developer to listen or not.
> My arguments as a user are listed. I have nothing more to add.

Nothing political here, just expressing my thoughts. I'm just a
contributor and I'm a user too.

Angel Ezquerra

unread,
Jul 8, 2012, 9:33:25 AM7/8/12
to Adrian Buehlmann, mercuria...@googlegroups.com, anatoly techtonik, rupert THURNER, merc...@selenic.com
On Sun, Jul 8, 2012 at 1:55 PM, Adrian Buehlmann <adr...@cadifra.com> wrote:
> On 2012-07-08 12:48, anatoly techtonik wrote:
>> On Sun, Jul 8, 2012 at 12:30 PM, Adrian Buehlmann <adr...@cadifra.com> wrote:
>>> On 2012-07-08 10:55, anatoly techtonik wrote:
>>>> On Sun, Jul 8, 2012 at 10:26 AM, Adrian Buehlmann <adr...@cadifra.com> wrote:
>>>>> On 2012-07-08 02:41, anatoly techtonik wrote:

[...]

>>> I'm still convinced that help texts need to be read for understanding
>>> what the commands are supposed to do.
>>>
>>> Perhaps, reading a book might also help to get some basic understanding.
>>>
>>> If you don't do that, then you indeed waste your time by just trying out
>>> commands. But then please don't complain.
>>
>> I've read both the book and help at least once. But I don't remember
>> all these gory details, and I don't have time to reread that every
>> time.

I think Adrian has explained everything really well, but let me tell
you the way I see and explain this when I'm asked about it at work.

I think that you give too much meaning to the name "revert" of the
revert command. revert does not mean being able to "undo" anything. It
can only revert, i.e. "change" the contents of files on the working
directory, nothing more, nothing less.

Mercurial repositories have 3 elements:

- The actual repository history (i.e. a DAG or "tree" of revisions),
stored in the .hg folder.
- The working directory (i.e. the files that you see on your file
explorer outside of the .hg folder).
- The current "parent revision" list, which usually points to a single
revision, but after a merge points to 2 revisions (that is in fact the
only case in which the parent revision list points to more than 1
revision). The parent revision links the working directory to the
repository history. It tells mercurial on top of which revision new
commits will be created, and to which revision it must compare the
working directory when you run hg status, etc.

Generally speaking, mercurial core commands modify either the
repository history or the working directory. For example, commit
modifies the repository history, but does not change the working
directory. pull, and push modify the repository history (of the local
or the remote repository), but do not change the working directory. On
the other hand, update, revert and merge change the working directory
but do not change the repository history.

Similarly, some commands modify the parent revisions, but others do
not. There are few commands that _do not_ change the parent revision,
and revert is among them, while update and merge _do_ change the
parent revision.

The following table tries to summarize this for the most common
"active" mercurial commands

Repository history Working directory Parent revision
-----------------------------------------------------------------------
commit x x
update x x
revert x
rollback x x
merge x x
pull x
push x

The table only shows "active" commands, i.e. those that modify either
of the 3 elements of the repository (status, diff, annotate, grep, etc
are "passive" because they just show you info, they do not modify the
repo at all)

In the table you can see that the only two commands that modify both
the working directory and the parent revision are merge and update.
This means that update is the only command that could possibly "undo"
everything that merge does. revert on the other hand changes the
working directory but does not change the parent revision. Thus it is
clear that revert _cannot_ be used to "undo" a merge.

Anyway I think that remembering this table helps a lot in
understanding which command must be used at any given time. In fact I
tend to add an additional column to the table, which is whether the
command may need network access or is an strictly local command:

Repository history Working directory Parent
revision Local command
-----------------------------------------------------------------------------------------
commit x x
x
update x x
x
revert x
x
rollback x x
x
merge x x
x
pull x
push x

I hope this helps!

Angel

rupert THURNER

unread,
Jul 8, 2012, 2:11:17 PM7/8/12
to Adrian Buehlmann, mercuria...@googlegroups.com, merc...@selenic.com, anatoly techtonik

Imo it would be much more intuitive if revert --all would have additional intelligence and revert the dirstate as well. If this is not possible one might question why a merge without commit already changes something in .hg. Undo a merge or merge commit are rare examples where mercurial exposes its implementation to the user interface.

Merge is such a central concept in mercurial, that it might be worth considering to give reverting it a little more love.

Rupert.

Martin Geisler

unread,
Jul 9, 2012, 3:45:25 AM7/9/12
to anatoly techtonik, mercuria...@googlegroups.com, rupert THURNER, merc...@selenic.com
anatoly techtonik <tech...@gmail.com> writes:

> On Sun, Jul 8, 2012 at 12:30 PM, Adrian Buehlmann <adr...@cadifra.com> wrote:
>
>> You can use revert to set the contents of all files (by using --all)
>> to *any* revision, thereby possibly introducing changes compared to
>> the parent revision.
>
> Isn't it a job of "update -r"??

No, that does something different.

Think of 'hg revert foo' as 'hg cat foo > foo'. That way it should be
very clear that 'hg revert' is a read-only operation in the repository
followed by a write operation in the working directory.

In other words: there is no difference between running 'hg revert foo'
and opening 'foo' in your text editor and modifying it to look like it
did in the working copy parent revision.

The 'hg update' command changes the working copy parent revision. Any
outstanding changes are merged into the target revision: you typically
have no outstanding changes and so 'hg update -r REV' makes the the
files in the working directory look like they did in REV. The working
copy parent is also updated -- a new commit will have REV as the parent
changeset.

I've also written about this here:

http://stackoverflow.com/a/2565996/110204

I hope that helps!

--
Martin Geisler

aragost Trifork
Commercial Mercurial support
http://aragost.com/mercurial/

Adrian Buehlmann

unread,
Jul 10, 2012, 6:09:59 PM7/10/12
to rupert THURNER, mercuria...@googlegroups.com, anatoly techtonik, merc...@selenic.com
On 2012-07-08 20:11, rupert THURNER wrote:
> Imo it would be much more intuitive if revert --all would have
> additional intelligence and revert the dirstate as well.

But then, current "revert --all" would need some other (additional?)
option, as we can't change what "revert --all" currently does (see
http://mercurial.selenic.com/wiki/CompatibilityRules). We can't suddenly
start switching the parent revision(s) with that, that would break
already shipped behavior. We don't do that.

And we would start duplication functionality which is already covered
with "update --clean .".

"update" implies "act on all files" (there is no partial update) and
it's the command which is responsible for switching parent revisions.

> If this is not
> possible one might question why a merge without commit already changes
> something in .hg.

We *do* have to remember _which_ two revisions got merged. See for
example "hg resolve [--tool TOOL] FILE..." which can be used for a
re-merge attempt at a still unresolved merge conflict. You want to feed
the correct revisions of the file into the merge tool (local, base, other).

But nothing in the _store_ is changed yet (.hg/store). So it's not yet
burned into history.

> Undo a merge or merge commit are rare examples where
> mercurial exposes its implementation to the user interface.

I don't think it does. The only concept you have to understand is that
the working directory has one or two parent revision and these get
burned into history as soon as you commit. I don't think that's that
hard to understand.

You don't even need to know where these things are saved. I just
mentioned it in the hope it would increase understanding.

(see also http://hgbook.red-bean.com/read/behind-the-scenes.html#x8-640004)

> Merge is such a central concept in mercurial, that it might be worth
> considering to give reverting it a little more love.

It's not like the commands hadn't gotten a lot of love already. Things
are pretty well thought out.

What might be possible is improving the help texts a bit (I sent some
patches to the -devel list for consideration). But the way to cancel an
uncommitted merge is "update --clean .".
Reply all
Reply to author
Forward
0 new messages