Making rollback safer

Matt Mackall mpm at
Tue Sep 13 16:51:42 CDT 2011

On Sun, 2011-09-11 at 21:45 -0400, Greg Ward wrote:
> Now for issue2998: commit, update back to an old changeset, then
> rollback. In that case, 'update' carefully and deliberately loses any
> changes made in your recent commit. That's its *job*, after all. Then
> 'rollback' does nothing at all to the working dir (part of *its*
> contract) and truncates the transaction. Result: the changes you just
> committed are utterly totally completely irretrievably lost. Oops.
> Yes, people should RTFM and not use rollback until they understand
> e-x-a-c-t-l-y what it does, but this is the real world. People make
> mistakes, misunderstand the docs, ignore the docs, assume Mercurial
> has got their back, etc.
> Proposed fix: at rollback time, we already know the revnum of the
> latest changeset that will be destroyed by rollback, since it's in
> undo.desc. Use that info: if working dir parent rev != rev in
> undo.desc, abort the rollback. As above, allow the user to do stupid
> things with --force. I don't have a patch for this yet, but it looks
> straightforward.

First note that undo.desc is not necessarily available. For instance,
undoing a transaction created by an old client.

Second, rolling back the dirstate should be seen as a side-effect of
truncating history: we don't want the dirstate to keep pointing at
truncated history. So if dirstate points at a revision that's not being
truncated, no action should be taken. Example:

hg co stable
echo foo > bar
hg ci -Am "add new file bar"
hg co default
hg rollback -> should remove tip commit without jumping to stable

Similarly, we shouldn't mess with rolling back the dirstate (or even
storing it!) if the last transaction had nothing to do with the
dirstate. Example:

hg pull
hg add foo
hg rollback -> shouldn't unadd foo

Neither of these cases should require --force.

Mathematics is the supreme nostalgia of our time.

More information about the Mercurial-devel mailing list