Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rolling back to an old revision in Mercurial (like git reset)

Using git, I can throw away a mistaken or accidental commit using a command like

git reset --soft HEAD^

which resets the current branch (such as master) to the current revision's parent commit HEAD^ without touching the working tree – you can replace --soft with --hard if you want to obliterate the working tree as well.

In addition, if I want to get rid of more than one commit, I can use a command like

git reset --hard 53b94d0

which brings me back exactly to commit 53b94d0 as if I had never committed anything after that.

What's the Mercurial (hg) equivalent?

like image 581
Sophie Alpert Avatar asked Jul 04 '12 04:07

Sophie Alpert


1 Answers

Though Mercurial doesn’t provide an easy alternative and shies away from the idea of mutable history, there are a few ways to achieve something close. In this post, I’ll outline a few of them.

hg rollback

If you specifically want to undo your last commit, you can use:

hg rollback

which will undo the commit (which doesn't touch the working tree – you should be able to follow it with a hg revert --all or hg update -C if you want to reset the entire working directory as well).

hg clone -r

Suppose you want to reset your repository called giraffe to revision 77182fb7451f. If you cd into the parent directory and run:

hg clone -r 77182fb7451f giraffe new-giraffe
cp giraffe/.hg/hgrc new-giraffe/.hg/

then you'll end up with new-giraffe, a repository at revision 77182fb7451f. (The cp is necessary to ensure that new-giraffe paths (like git's "remotes") correctly point to the origin repo instead of to the giraffe folder as it would by default.)

This is faster than recloning from the internet because it only copies files locally on your disk (and on many systems, hard-links them to save even more time and space), but can still be really time-consuming if your repository is large.

hg strip

If you want to do more complicated things with modifying the commit history (which is somewhat frowned on in the hg world, by the way), first enable the Mercurial Queues extension by adding the following lines to your .hgrc (there's no need to specify a path after the equals sign):

[extensions]                                                                    
mq =

This gives you (among other useful things) the hg strip command to completely remove a changeset and all of its descendants from a repository. Thus you can use a command like:

hg strip 1cc72d33ea76

if 1cc72d33ea76 is the first "bad" changeset in your repository that you want to remove.

Unfortunately, it's often hard to remove exactly the right changesets using this method and it's all too easy to end up with multiple heads (which you can view using hg heads), requiring tedious repeated application of hg strip before you can get to where you want to be with no extra heads.

hg strip using revsets

Using hg revsets you can delete all the ancestors of . (the current revision) which are not ancestors of the revision you want to revert to, using a command like:

hg strip "ancestors(.) and not ancestors(77182fb7451f)"

Make sure to first run:

hg log -r "ancestors(.) and not ancestors(77182fb7451f)"

which will show you all the changesets that hg strip would remove, so you can make sure you don't irreparably harm your commit history (because you have backups… right?).

like image 163
Sophie Alpert Avatar answered Oct 31 '22 12:10

Sophie Alpert