简体   繁体   中英

How to get rid of some changeset in Hg?

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.

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.

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 :)

请参阅mq扩展名中的hg strip

You've got some good answers already, but a couple additional notes:

  • If you've got uncommitted local changes, shelve will set them aside for you for later retrieval
  • If your changeset has been pushed to another repository, then short of editing both repositories, a backout is your only option
  • A backout allows you to make a new changeset which is the inverse of the original changeset, getting rid of the undesired changes without changing the history of the repository
  • A rollback is normally your best option if you haven't already pushed to a remote repo since it obliterates the changeset while leaving your working copy intact
  • Strip will get rid of a whole branch of changes, but like rollbacks it will only stay gone if you haven't pushed the changes anywhere else
  • The same goes for cloning a repository up to a prior revision - the other tools are easier anyway

Not certain about the git things, but if you haven't pushed, you can use hg rollback . If you have pushed, there's not really anything decent you can do about it.

As for the current revision, see hg id .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM