Patchwork rollback: add reference to "hg commit --amend"

login
register
mail settings
Submitter Martin Geisler
Date July 17, 2013, 8:53 a.m.
Message ID <85d4ebb3d89e29657c4d.1374051190@go>
Download mbox | patch
Permalink /patch/1910/
State Accepted
Commit b2b08be5f5569e3b0879d30e6ccd5cc3b58d38aa
Headers show

Comments

Martin Geisler - July 17, 2013, 8:53 a.m.
# HG changeset patch
# User Martin Geisler <martin@geisler.net>
# Date 1374050974 -7200
#      Wed Jul 17 10:49:34 2013 +0200
# Node ID 85d4ebb3d89e29657c4d7365174d9120ba88ad34
# Parent  ea4342d0e6fea19c8c4b7651f36929cd682afae7
rollback: add reference to "hg commit --amend"

Now that rollback is deprecated (yay!) users might need a pointer to
the alternative for 99% of the cases where I used rollback.
Alexander Plavin - July 17, 2013, 10:02 a.m.
2013/7/17 Martin Geisler <martin@geisler.net>:
> # HG changeset patch
> # User Martin Geisler <martin@geisler.net>
> # Date 1374050974 -7200
> #      Wed Jul 17 10:49:34 2013 +0200
> # Node ID 85d4ebb3d89e29657c4d7365174d9120ba88ad34
> # Parent  ea4342d0e6fea19c8c4b7651f36929cd682afae7
> rollback: add reference to "hg commit --amend"
>
> Now that rollback is deprecated (yay!) users might need a pointer to
> the alternative for 99% of the cases where I used rollback.
>
> diff --git a/mercurial/commands.py b/mercurial/commands.py
> --- a/mercurial/commands.py
> +++ b/mercurial/commands.py
> @@ -5016,6 +5016,9 @@
>  def rollback(ui, repo, **opts):
>      """roll back the last transaction (DANGEROUS) (DEPRECATED)
>
> +    Please use :hg:`commit --amend` instead of rollback to correct
> +    mistakes in the last commit.

May be not 'last commit', but 'parent of the working directory', like
in help for hg commit --amend?

> +
>      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
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
Martin Geisler - July 17, 2013, 12:08 p.m.
Alexander Plavin <me@aplavin.ru> writes:

> 2013/7/17 Martin Geisler <martin@geisler.net>:
>> # HG changeset patch
>> # User Martin Geisler <martin@geisler.net>
>> # Date 1374050974 -7200
>> #      Wed Jul 17 10:49:34 2013 +0200
>> # Node ID 85d4ebb3d89e29657c4d7365174d9120ba88ad34
>> # Parent  ea4342d0e6fea19c8c4b7651f36929cd682afae7
>> rollback: add reference to "hg commit --amend"
>>
>> Now that rollback is deprecated (yay!) users might need a pointer to
>> the alternative for 99% of the cases where I used rollback.
>>
>> diff --git a/mercurial/commands.py b/mercurial/commands.py
>> --- a/mercurial/commands.py
>> +++ b/mercurial/commands.py
>> @@ -5016,6 +5016,9 @@
>>  def rollback(ui, repo, **opts):
>>      """roll back the last transaction (DANGEROUS) (DEPRECATED)
>>
>> +    Please use :hg:`commit --amend` instead of rollback to correct
>> +    mistakes in the last commit.
>
> May be not 'last commit', but 'parent of the working directory', like
> in help for hg commit --amend?

Making the messages similar sounds good at first, but on second thought
I think it's better to make the message specific for rollback. The
rollback command was (is!) often abused for redoing the very last commit
since (unlike 'hg commit --amend'), it cannot be used for redoing other
commits.
Antoine Pitrou - July 17, 2013, 2:07 p.m.
Martin Geisler <martin <at> geisler.net> writes:

> 
> # HG changeset patch
> # User Martin Geisler <martin <at> geisler.net>
> # Date 1374050974 -7200
> #      Wed Jul 17 10:49:34 2013 +0200
> # Node ID 85d4ebb3d89e29657c4d7365174d9120ba88ad34
> # Parent  ea4342d0e6fea19c8c4b7651f36929cd682afae7
> rollback: add reference to "hg commit --amend"
> 
> Now that rollback is deprecated (yay!) users might need a pointer to
> the alternative for 99% of the cases where I used rollback.

Rollback is deprecated? What is the recommended way to undo a bogus
commit (especially a merge or graft)?
AFAICT, "strip" isn't part of the core command set.

Regards

Antoine.
Antoine Pitrou - July 17, 2013, 3:56 p.m.
Kevin Bullock <kbullock+mercurial <at> ringworld.org> writes:
> > 
> > Rollback is deprecated? What is the recommended way to undo a bogus
> > commit (especially a merge or graft)?
> > AFAICT, "strip" isn't part of the core command set.
> 
> The same way we've always recommended: clone up to the parent of the
bad revision (and any other heads), then
> throw away the old clone.

That's a terribly obnoxious solution compared to "hg rollback".

Regards

Antoine.
Matt Mackall - July 17, 2013, 3:56 p.m.
On Wed, 2013-07-17 at 14:07 +0000, Antoine Pitrou wrote:
> Martin Geisler <martin <at> geisler.net> writes:
> 
> > 
> > # HG changeset patch
> > # User Martin Geisler <martin <at> geisler.net>
> > # Date 1374050974 -7200
> > #      Wed Jul 17 10:49:34 2013 +0200
> > # Node ID 85d4ebb3d89e29657c4d7365174d9120ba88ad34
> > # Parent  ea4342d0e6fea19c8c4b7651f36929cd682afae7
> > rollback: add reference to "hg commit --amend"
> > 
> > Now that rollback is deprecated (yay!) users might need a pointer to
> > the alternative for 99% of the cases where I used rollback.
> 
> Rollback is deprecated?

Yes.

Please be aware that Mercurial's approach to deprecation is very
different from some other projects. We're not going to spam you with
warnings when you use it and it doesn't indicate that the command is
going away either. It's simply not listed in 'hg help' (unless you use
-v).

If you hadn't been following the list today, you might not have ever
noticed.
Jordi GutiƩrrez Hermoso - July 17, 2013, 6:13 p.m.
On 17 July 2013 10:07, Antoine Pitrou <solipsis@pitrou.net> wrote:
> AFAICT, "strip" isn't part of the core command set.

Sure it is, "hg --config extension.mq= strip --keep ." works for
people who are afraid of editing an hgrc.

- Jordi G. H.
Matt Mackall - July 17, 2013, 7:58 p.m.
On Wed, 2013-07-17 at 14:55 -0500, Kevin Bullock wrote:
> On 17 Jul 2013, at 10:56 AM, Antoine Pitrou wrote:
> 
> > Kevin Bullock <kbullock+mercurial <at> ringworld.org> writes:
> >>> 
> >>> Rollback is deprecated? What is the recommended way to undo a bogus
> >>> commit (especially a merge or graft)?
> >>> AFAICT, "strip" isn't part of the core command set.
> >> 
> >> The same way we've always recommended: clone up to the parent of the
> > bad revision (and any other heads), then
> >> throw away the old clone.
> > 
> > That's a terribly obnoxious solution compared to "hg rollback".
> 
> It's a solution that works at the level of other user-facing commands,
> rather than digging dangerously into the internals of how revlogs
> work. It has -always- been our first recommended way of undoing a
> changeset you don't want.

More precisely, it's in keeping with the append-only avoid-dataloss
approach of the rest of our core commands. In other words, the same
reason that strip is NOT in core.
Matt Mackall - July 17, 2013, 7:59 p.m.
On Wed, 2013-07-17 at 10:53 +0200, Martin Geisler wrote:
> # HG changeset patch
> # User Martin Geisler <martin@geisler.net>
> # Date 1374050974 -7200
> #      Wed Jul 17 10:49:34 2013 +0200
> # Node ID 85d4ebb3d89e29657c4d7365174d9120ba88ad34
> # Parent  ea4342d0e6fea19c8c4b7651f36929cd682afae7
> rollback: add reference to "hg commit --amend"

Queued for default, thanks. Bikeshedding by follow-up patch please.
Angel Ezquerra - July 17, 2013, 9:25 p.m.
On Jul 17, 2013 9:58 PM, "Matt Mackall" <mpm@selenic.com> wrote:
>
> On Wed, 2013-07-17 at 14:55 -0500, Kevin Bullock wrote:
> > On 17 Jul 2013, at 10:56 AM, Antoine Pitrou wrote:
> >
> > > Kevin Bullock <kbullock+mercurial <at> ringworld.org> writes:
> > >>>
> > >>> Rollback is deprecated? What is the recommended way to undo a bogus
> > >>> commit (especially a merge or graft)?
> > >>> AFAICT, "strip" isn't part of the core command set.
> > >>
> > >> The same way we've always recommended: clone up to the parent of the
> > > bad revision (and any other heads), then
> > >> throw away the old clone.
> > >
> > > That's a terribly obnoxious solution compared to "hg rollback".
> >
> > It's a solution that works at the level of other user-facing commands,
> > rather than digging dangerously into the internals of how revlogs
> > work. It has -always- been our first recommended way of undoing a
> > changeset you don't want.
>
> More precisely, it's in keeping with the append-only avoid-dataloss
> approach of the rest of our core commands. In other words, the same
> reason that strip is NOT in core.

I think that recloning to undo the last commit is clunky and user
unfriendly, particularly if your working directory contains untracked files
which are costly to regenerate.

For example, I work with projects that contain xilinx ip cores that take
more than an hour to generate from a newly cloned repo. Losing an hour to
undo a commit seems excessive. You could copy those untracked files to the
new repo, or something similar, but that would be error prone. Or you could
use strip but then isn't that bypassing mercurial's append only approach
anyway?

It is true that amend is a better solution most of the time but it seems
that there are still some legitimate use cases of rollback...

Maybe rollback (or an equivalent evolution command) could turn the rolled
back revision hidden instead of removing it?

Angel
Pierre-Yves David - July 17, 2013, 9:49 p.m.
On 17 juil. 2013, at 23:25, Angel Ezquerra wrote:

> Maybe rollback (or an equivalent evolution command) could turn the rolled back revision hidden instead of removing it?

`hg rollback` get rid of stuff by undoing the latest repository transaction (for whatever that means) it will do it for ever and it was a very bad idea to expose it to the user.

`hg prune` (current name in evolve). Get rid of a changeset by the creation of an obsolescence marker. The changeset because obsolete and hidden to the user.

`hg uncommit` (current name in evolve). Extract change from a commit. The commit is rewritten without extracted changes and the working copy files are left untouched (so they get back to "M"). (the older version of the commit is obsolete).
Matt Mackall - July 17, 2013, 10:33 p.m.
On Wed, 2013-07-17 at 23:25 +0200, Angel Ezquerra wrote:
> 
> On Jul 17, 2013 9:58 PM, "Matt Mackall" <mpm@selenic.com> wrote:
> >
> > On Wed, 2013-07-17 at 14:55 -0500, Kevin Bullock wrote:
> > > On 17 Jul 2013, at 10:56 AM, Antoine Pitrou wrote:
> > >
> > > > Kevin Bullock <kbullock+mercurial <at> ringworld.org> writes:
> > > >>>
> > > >>> Rollback is deprecated? What is the recommended way to undo a
> bogus
> > > >>> commit (especially a merge or graft)?
> > > >>> AFAICT, "strip" isn't part of the core command set.
> > > >>
> > > >> The same way we've always recommended: clone up to the parent
> of the
> > > > bad revision (and any other heads), then
> > > >> throw away the old clone.
> > > >
> > > > That's a terribly obnoxious solution compared to "hg rollback".
> > >
> > > It's a solution that works at the level of other user-facing
> commands,
> > > rather than digging dangerously into the internals of how revlogs
> > > work. It has -always- been our first recommended way of undoing a
> > > changeset you don't want.
> >
> > More precisely, it's in keeping with the append-only avoid-dataloss
> > approach of the rest of our core commands. In other words, the same
> > reason that strip is NOT in core.
> 
> I think that recloning to undo the last commit is clunky and user
> unfriendly, particularly if your working directory contains untracked
> files which are costly to regenerate.

I'm glad rollback works for you. You will NOT be affected by this
change.

We have lots of evidence that rollback does not work for beginners and
we have weighed the pros and cons about hiding it from them and that is
ALL that deprecating does.
Martin Geisler - July 18, 2013, 8:29 a.m.
Kevin Bullock <kbullock+mercurial@ringworld.org> writes:

> On 17 Jul 2013, at 9:07 AM, Antoine Pitrou wrote:
>
>> Martin Geisler <martin <at> geisler.net> writes:
>> 
>>> 
>>> # HG changeset patch
>>> # User Martin Geisler <martin <at> geisler.net>
>>> # Date 1374050974 -7200
>>> #      Wed Jul 17 10:49:34 2013 +0200
>>> # Node ID 85d4ebb3d89e29657c4d7365174d9120ba88ad34
>>> # Parent  ea4342d0e6fea19c8c4b7651f36929cd682afae7
>>> rollback: add reference to "hg commit --amend"
>>> 
>>> Now that rollback is deprecated (yay!) users might need a pointer to
>>> the alternative for 99% of the cases where I used rollback.
>> 
>> Rollback is deprecated? What is the recommended way to undo a bogus
>> commit (especially a merge or graft)?
>> AFAICT, "strip" isn't part of the core command set.

You should be able to use 'hg commit --amend' in those case too. I just
tested it and I can amend both a merge commit and a graft commit just
fine with Mercurial 2.6.3.

So I believe the better answer to your question is to use --amend. It is
only if you need to really get rid of a commit (as opposed to correcting
it) that --amend falls short.

> The same way we've always recommended: clone up to the parent of the
> bad revision (and any other heads), then throw away the old clone.

That advice may be technically true, I think it is only half the truth.

Even for a very small project like Mercurial where 'make local' takes
seconds, you typically need more than what you describe here: you need
to copy your .hg/hgrc file (mine contains useful paths), copy any patch
queues (plural) you have around and maybe copy .hg/strip-backsups. Did I
forget to copy something related to evolve -- I'm not 100% sure.

So it is not just a matter of

  cd ..
  hg clone -r '.^' foo foo-stripped
  rm -r foo
  mv foo-stripped foo

(four commands!) to remove a commit.

You probably know this already, but things become more complex when the
working copy contain costly build artifacts. Please don't ignore that by
telling people to "just clone and throw away the old repo".
Antoine Pitrou - July 18, 2013, 8:36 a.m.
Hi,

Pierre-Yves David <pierre-yves.david <at> ens-lyon.org> writes:
> 
> `hg prune` (current name in evolve). Get rid of a changeset by the
creation of an obsolescence marker. The
> changeset because obsolete and hidden to the user.
> 
> `hg uncommit` (current name in evolve). Extract change from a commit. The
commit is rewritten without
> extracted changes and the working copy files are left untouched (so they
get back to "M"). (the older
> version of the commit is obsolete).

That sounds promising. Any idea when this will be available in hg?
(or have I missed something about that?)

Regards

Antoine.
Angel Ezquerra - July 18, 2013, 9:39 a.m.
On Thu, Jul 18, 2013 at 10:29 AM, Martin Geisler <martin@geisler.net> wrote:
> Kevin Bullock <kbullock+mercurial@ringworld.org> writes:
>
>> On 17 Jul 2013, at 9:07 AM, Antoine Pitrou wrote:
>>
>>> Martin Geisler <martin <at> geisler.net> writes:
>>>
>>>>
>>>> # HG changeset patch
>>>> # User Martin Geisler <martin <at> geisler.net>
>>>> # Date 1374050974 -7200
>>>> #      Wed Jul 17 10:49:34 2013 +0200
>>>> # Node ID 85d4ebb3d89e29657c4d7365174d9120ba88ad34
>>>> # Parent  ea4342d0e6fea19c8c4b7651f36929cd682afae7
>>>> rollback: add reference to "hg commit --amend"
>>>>
>>>> Now that rollback is deprecated (yay!) users might need a pointer to
>>>> the alternative for 99% of the cases where I used rollback.
>>>
>>> Rollback is deprecated? What is the recommended way to undo a bogus
>>> commit (especially a merge or graft)?
>>> AFAICT, "strip" isn't part of the core command set.
>
> You should be able to use 'hg commit --amend' in those case too. I just
> tested it and I can amend both a merge commit and a graft commit just
> fine with Mercurial 2.6.3.
>
> So I believe the better answer to your question is to use --amend. It is
> only if you need to really get rid of a commit (as opposed to correcting
> it) that --amend falls short.

The problem with using --amend in this scenario is that it is not that
easy to use it to uncommit a file. AFAIK the only way to do so is to
revert that file to the its parent revision state and then use
--amend.

I think that until we get a proper uncommit or purge command into
mercurial core --amend will not be a very good solution to this
problem.

>> The same way we've always recommended: clone up to the parent of the
>> bad revision (and any other heads), then throw away the old clone.
>
> That advice may be technically true, I think it is only half the truth.
>
> Even for a very small project like Mercurial where 'make local' takes
> seconds, you typically need more than what you describe here: you need
> to copy your .hg/hgrc file (mine contains useful paths), copy any patch
> queues (plural) you have around and maybe copy .hg/strip-backsups. Did I
> forget to copy something related to evolve -- I'm not 100% sure.
>
> So it is not just a matter of
>
>   cd ..
>   hg clone -r '.^' foo foo-stripped
>   rm -r foo
>   mv foo-stripped foo
>
> (four commands!) to remove a commit.
>
> You probably know this already, but things become more complex when the
> working copy contain costly build artifacts. Please don't ignore that by
> telling people to "just clone and throw away the old repo".

My thoughts exactly. Although as Matt told me it is nice that
mercurial's approach to deprecating commands does not stop me from
keeping using rollback until a better obsolete-based alternative gets
into mercurial core.

Cheers,

Angel
Martin Geisler - July 18, 2013, 2:01 p.m.
Angel Ezquerra <angel.ezquerra@gmail.com> writes:

> On Thu, Jul 18, 2013 at 10:29 AM, Martin Geisler <martin@geisler.net> wrote:
>> Kevin Bullock <kbullock+mercurial@ringworld.org> writes:
>>
>>> On 17 Jul 2013, at 9:07 AM, Antoine Pitrou wrote:
>>>
>>>> Martin Geisler <martin <at> geisler.net> writes:
>>>>
>>>>>
>>>>> # HG changeset patch
>>>>> # User Martin Geisler <martin <at> geisler.net>
>>>>> # Date 1374050974 -7200
>>>>> #      Wed Jul 17 10:49:34 2013 +0200
>>>>> # Node ID 85d4ebb3d89e29657c4d7365174d9120ba88ad34
>>>>> # Parent  ea4342d0e6fea19c8c4b7651f36929cd682afae7
>>>>> rollback: add reference to "hg commit --amend"
>>>>>
>>>>> Now that rollback is deprecated (yay!) users might need a pointer
>>>>> to the alternative for 99% of the cases where I used rollback.
>>>>
>>>> Rollback is deprecated? What is the recommended way to undo a bogus
>>>> commit (especially a merge or graft)? AFAICT, "strip" isn't part of
>>>> the core command set.
>>
>> You should be able to use 'hg commit --amend' in those case too. I
>> just tested it and I can amend both a merge commit and a graft commit
>> just fine with Mercurial 2.6.3.
>>
>> So I believe the better answer to your question is to use --amend. It
>> is only if you need to really get rid of a commit (as opposed to
>> correcting it) that --amend falls short.
>
> The problem with using --amend in this scenario is that it is not that
> easy to use it to uncommit a file. AFAIK the only way to do so is to
> revert that file to the its parent revision state and then use
> --amend.

Yes, that is unfortunately the way one has to use --amend. In other
words

  $ hg commit --amend -X foo

is not the same as

  $ hg rollback
  $ hg commit -X foo

since foo wont be excluded from the amended commit. I feel this is
surprising and unfortunate since I need to exclude entire files much
more frequently than I need to exclude changes to files when amending.
Also, from MQ works works like the rollback+commit sequence.
Pierre-Yves David - July 22, 2013, 9:10 a.m.
On 18 juil. 2013, at 16:01, Martin Geisler wrote:

> Angel Ezquerra <angel.ezquerra@gmail.com> writes:
> 
>> On Thu, Jul 18, 2013 at 10:29 AM, Martin Geisler <martin@geisler.net> wrote:
>>> Kevin Bullock <kbullock+mercurial@ringworld.org> writes:
>>> 
>>>> On 17 Jul 2013, at 9:07 AM, Antoine Pitrou wrote:
>>>> 
>>>>> Martin Geisler <martin <at> geisler.net> writes:
>>>>> 
>>>>>> 
>>>>>> # HG changeset patch
>>>>>> # User Martin Geisler <martin <at> geisler.net>
>>>>>> # Date 1374050974 -7200
>>>>>> #      Wed Jul 17 10:49:34 2013 +0200
>>>>>> # Node ID 85d4ebb3d89e29657c4d7365174d9120ba88ad34
>>>>>> # Parent  ea4342d0e6fea19c8c4b7651f36929cd682afae7
>>>>>> rollback: add reference to "hg commit --amend"
>>>>>> 
>>>>>> Now that rollback is deprecated (yay!) users might need a pointer
>>>>>> to the alternative for 99% of the cases where I used rollback.
>>>>> 
>>>>> Rollback is deprecated? What is the recommended way to undo a bogus
>>>>> commit (especially a merge or graft)? AFAICT, "strip" isn't part of
>>>>> the core command set.
>>> 
>>> You should be able to use 'hg commit --amend' in those case too. I
>>> just tested it and I can amend both a merge commit and a graft commit
>>> just fine with Mercurial 2.6.3.
>>> 
>>> So I believe the better answer to your question is to use --amend. It
>>> is only if you need to really get rid of a commit (as opposed to
>>> correcting it) that --amend falls short.
>> 
>> The problem with using --amend in this scenario is that it is not that
>> easy to use it to uncommit a file. AFAIK the only way to do so is to
>> revert that file to the its parent revision state and then use
>> --amend.
> 
> Yes, that is unfortunately the way one has to use --amend. In other
> words
> 
>  $ hg commit --amend -X foo
> 
> is not the same as
> 
>  $ hg rollback
>  $ hg commit -X foo
> 
> since foo wont be excluded from the amended commit. I feel this is
> surprising and unfortunate since I need to exclude entire files much
> more frequently than I need to exclude changes to files when amending.
> Also, from MQ works works like the rollback+commit sequence.

We already discussed that in the past. There is three state we need to takes in account:
1) current working directory (wc)
2) working directory parent (.)
3) parent of working directory parent (.^)

And it's hard to express that all at once in a single command. even harder when amend is an extra flag on the commit command. If the feature is so critical we can has it working separated from evolve.

Haivng two commands commit//uncommit give a very clear interface in my opinion. The MQ way bites people all the time.
Martin Geisler - July 22, 2013, 12:25 p.m.
Pierre-Yves David <pierre-yves.david@ens-lyon.org> writes:

> On 18 juil. 2013, at 16:01, Martin Geisler wrote:
>
>> Angel Ezquerra <angel.ezquerra@gmail.com> writes:
>> 
>>> On Thu, Jul 18, 2013 at 10:29 AM, Martin Geisler <martin@geisler.net> wrote:
>>>> Kevin Bullock <kbullock+mercurial@ringworld.org> writes:
>>>> 
>>>>> On 17 Jul 2013, at 9:07 AM, Antoine Pitrou wrote:
>>>>> 
>>>>>> Martin Geisler <martin <at> geisler.net> writes:
>>>>>> 
>>>>>>> 
>>>>>>> # HG changeset patch
>>>>>>> # User Martin Geisler <martin <at> geisler.net>
>>>>>>> # Date 1374050974 -7200
>>>>>>> #      Wed Jul 17 10:49:34 2013 +0200
>>>>>>> # Node ID 85d4ebb3d89e29657c4d7365174d9120ba88ad34
>>>>>>> # Parent  ea4342d0e6fea19c8c4b7651f36929cd682afae7
>>>>>>> rollback: add reference to "hg commit --amend"
>>>>>>> 
>>>>>>> Now that rollback is deprecated (yay!) users might need a pointer
>>>>>>> to the alternative for 99% of the cases where I used rollback.
>>>>>> 
>>>>>> Rollback is deprecated? What is the recommended way to undo a bogus
>>>>>> commit (especially a merge or graft)? AFAICT, "strip" isn't part of
>>>>>> the core command set.
>>>> 
>>>> You should be able to use 'hg commit --amend' in those case too. I
>>>> just tested it and I can amend both a merge commit and a graft
>>>> commit just fine with Mercurial 2.6.3.
>>>> 
>>>> So I believe the better answer to your question is to use --amend.
>>>> It is only if you need to really get rid of a commit (as opposed to
>>>> correcting it) that --amend falls short.
>>> 
>>> The problem with using --amend in this scenario is that it is not
>>> that easy to use it to uncommit a file. AFAIK the only way to do so
>>> is to revert that file to the its parent revision state and then use
>>> --amend.
>> 
>> Yes, that is unfortunately the way one has to use --amend. In other
>> words
>> 
>>  $ hg commit --amend -X foo
>> 
>> is not the same as
>> 
>>  $ hg rollback
>>  $ hg commit -X foo
>> 
>> since foo wont be excluded from the amended commit. I feel this is
>> surprising and unfortunate since I need to exclude entire files much
>> more frequently than I need to exclude changes to files when
>> amending. Also, from MQ works works like the rollback+commit
>> sequence.
>
> We already discussed that in the past.

I know we've discussed it before. I'm writing about it here since I'm
trying to figure out the best workflow with the --amend that we have
now. That's also why I'm contrasting with MQ and rollback: to figure out
how to best reimplement the old workflows in a safer way with --amend.

> There is three state we need to takes in account:
> 1) current working directory (wc)
> 2) working directory parent (.)
> 3) parent of working directory parent (.^)

I think you can add the working directory grandparent (.^^) to the list
of interesting revisions. If we imagine a recommit alias that does

  hg rollback; hg commit $@

then we can compare:

* I want to completely remove a.txt from the last commit but retain the
  changes in my working copy.

  With amend:

    $ hg revert -r '.^^' a.txt
    $ hg commit --amend
    $ mv a.txt.orig a.txt

  With recommit:

    $ hg commit --amend -X a.txt

* I want to fold all changes into the last commit without adding the
  changes in a.txt.

  With amend:

  $ hg commit --amend -X a.txt

  With recommit:

  $ hg diff a.txt > tmp  # stash
  $ hg recommit
  $ hg import --no-commit tmp

My impression (just an impression) is that I run into the first use case
much more than the second. When the second case happens, I've actually
never solved it with --amend, but always by reverting the change in my
editor. That way

  $ hg diff -r '.^^'

shows me what the commit will contain after commit --amend. Trying to
figure out what an amended commit will contain looks quite difficult
when -X is used: running

  $ hg diff -r '.^^' -X a.txt

will not give the correct result since it will exclude the changes in
a.txt made between '.^^' and '.^'.

In other words, I try hard to avoid ending up in the second case since I
don't know how to see the effect of 'hg commit --am' in that case!

> And it's hard to express that all at once in a single command. even
> harder when amend is an extra flag on the commit command. If the
> feature is so critical we can has it working separated from evolve.
>
> Haivng two commands commit//uncommit give a very clear interface in my
> opinion. The MQ way bites people all the time.

Thanks for the reminder, I should try to use 'hg uncommit' from evolve
more often.

Patch

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -5016,6 +5016,9 @@ 
 def rollback(ui, repo, **opts):
     """roll back the last transaction (DANGEROUS) (DEPRECATED)
 
+    Please use :hg:`commit --amend` instead of rollback to correct
+    mistakes in the last commit.
+
     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