Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get rid of some changeset in Hg?

Tags:

git

mercurial

Hey, I want to revert some changesets in Hg but I'm having a hard time doing so.

I commited some changes by accident, so I wanted to undo that. After trying a little bit, I was able to hg backout, but it created a new commit. Now, I wanted my repo to became to the initial state (without the last 2 commits and with my changes in the working dir). Apparently there's no way of doing that (something similar to git reset --soft). Is there?

Another thing I tried was to get rid of the latest commit (the one that reverted the original one). It would be something similar to git reset --hard, but again, there's no way to do that. I can hg update -C, but that is more like git checkout, since the commit is still out there.

And also, hg update -C -r X reverts me back to revision X, but when I check hg log there's no way for me to know in which revision I am right now. The only way is to check my bash history, is this right? There's gotta be a way to know this.

Anyway, I've been trying to sort this out for a while but couldn't find anything that would solve it. The references I found comparing git and hg commands are not accurate, since the commands don't have the exact same behavior.

I guess I just want to know what are the REAL equivalences in hg for git reset --hard and git reset --soft...

Thanks.

like image 969
Gaisorama Avatar asked Nov 13 '10 13:11

Gaisorama


People also ask

How do you strip in mercurial?

hg strip [-k] [-f] [-B bookmark] [-r] REV... The strip command removes the specified changesets and all their descendants. If the working directory has uncommitted changes, the operation is aborted unless the --force flag is supplied, in which case changes will be discarded.

How do you revert the last push in Heartgold?

hg rollback reverts the last transaction, so you'd be left with unfinished merge, which you have to use hg update -C to get out. If you don't want *b (you have it in another clone), then enable the built-in MQ extension and run hg strip -r <*b> . It will get rid of *b and *merge.


2 Answers

Mercurial intentionally doesn't make this easy. Mercurial's mindset is that code committed should continue to exist -- that the record of what didn't work out is almost as important as a record of what did. It's better to commit the negation of your work (which is what backout does) and still have the record than it is to actually discard it.

If, however, you just can't leave that change around (good reasons: it contains a password you can't change, bad reason: It just didn't work out) you have a few options:

  • strip: I don't like strip it modifies the repository and doesn't put the stuff back in the working dir. Strip is disabled by default for a reason.
  • clone: Just do a hg clone -r LASTCHANGESETYOULIKE oldrepo newrepo and now newrepo has everything up to and including LASTCHANGESETYOULIKE. Archive oldrepo and rename newrepo to oldrepo.
  • rollback: This is the one-level undo of the mercurial world. It would have undone your commit right after you did it, but it doesn't work if you've done any other pulls or commits, which you have.
like image 112
Ry4an Brase Avatar answered Sep 28 '22 08:09

Ry4an Brase


Here is how to do git reset --soft. Let us assume you have a graph like this:

... --- [A] --- [B] --- [X] --- [-X]

where X is the bad commit and -X is the backout you made. You now want to get rid of X and -X while leaving the working copy looking like it did when you committed X. You do

$ hg update B
$ hg revert --all --rev X # working copy now looks just like in X
$ hg strip --force X      # get rid of X and -X

If you want, you can make an alias for this with Mercurial 1.7:

[alias]
softreset = !hg update 'p1($1)' &&
             hg revert --all --rev $1 &&
             hg strip --force $1

The dirty working copy after hg revert makes it necessary to use hg strip --force. You use this new command as

$ hg softreset 10

which will remove 10 and any descendents while leaving the changes in 10 in the working copy. You can of course take this further and implement a hg reset command:

[alias]
reset = !test "$1" = "--hard" && hg strip $2 || hg softreset $2

The biggest problem with these aliases is the poor error handling. An extension written in Python would be much more robust and maintainable -- perhaps you could make such a "reset" extension and publish it on Bitbucket :)

like image 37
Martin Geisler Avatar answered Sep 28 '22 09:09

Martin Geisler