tags:

views:

1246

answers:

5

Bazaar has a wonderful uncommit command, which simply undoes the last commit. Is there any equivalent in Mercurial?

Edit: Bazaar's uncommit command does not modify files – it removes the last commit and associated data (useful, for example, when you notice too late that there is a typo in a commit message or a file wasn't added that should have been).

For example:

$ bzr ci -m "Fixed a proooblem" <-- problem is misspelt
$ bzr uncommit
...
$ bzr ci -m "Fixed a problem" <-- Exactly as if the first commit was correct.
A: 

Doesn't "hg revert" do that?

Ned Batchelder
You are correct. hg revert is the equivalent command.
Marc W
It will revert the files, but I'd like the entire commit (message and all) stricken from the history.
David Wolever
Or maybe there isn't something `hg help revert` isn't showing me...?
David Wolever
"hg revert" does not change the history. Instead "hg revert" changes the working copy -- you use it to revert uncommited changes back to some earlier revision (typically the working copy parent revision). To redo a commit you cannot use "hg revert", I suggest "hg rollback" instead.
Martin Geisler
+3  A: 

Maybe hg backout tip? I recommend http://hgbook.red-bean.com/read/finding-and-fixing-mistakes.html for all details about hg backout, how it differs from hg revert, and many related topics, but if I undestand what uncommit does, it does seem exactly equivalent to hg backout tip.

Edit: in a comment you've now clarified you want to "delete history" -- that's hard (unless you're VERY fast on the draw, maybe;-)... per the red-bean book again:

Since Mercurial treats history as accumulative—every change builds on top of all changes that preceded it—you generally can't just make disastrous changes disappear. The one exception is when you've just committed a change, and it hasn't been pushed or pulled into another repository. That's when you can safely use the hg rollback command

So if you just want to try to "make it disappear" (and you're lucky enough that it hasn't yet been pushed or pulled elsewhere), then hg rollback may be a better approach!

Alex Martelli
Close, but not quite.`bzr revert` will leave all the files in place, ready to be re-committed.
David Wolever
do you mean "bzr uncommit"?
Alex Martelli
err, yes, that's right... Thanks.
David Wolever
anyway, "hg rollback" seems more and more like what you want -- it rolls back the latest _transaction_ (commit or pull), though, per red-bean book again, "you can only rollback once" and "it's useless once you've pushed".
Alex Martelli
Ah, yes – I was just reading about rollback when I thought I'd come back here to see if there were any more comments.Rollback is *almost* what I want... But it doesn't put the files back for me (ie, a revert is required to put the files back where they were before the commit)... But I don't think I'll complain any more :)Thanks for the help Alex!
David Wolever
A: 

From reading the comments, it seems that you want a way to simply do away with the record of the commit without undoing the changes to the file. In Mercurial, there is no automated way of doing this. hg revert is as close as you're going to get.

However, you could do this with a couple manual steps. When you invoke hg revert, its default behavior is to take the files in the changeset you are reverting and rename them as filename.ext.orig, where ext is the original extension of the file. The reverted versions then take on the original filename. So what you could do is run hg revert, delete the files with the original names, and remove .orig from the backup files' names. Then re-commit with your corrected log message. Just don't do this with any revision other than the tip because you'll probably get a lot of changed files and forget which ones belonged in which changeset.

I also would not recommend doing this if you've already pushed your changesets out to a remote repo. Only do this if everything is still only local.

Let me know if you need further explanation. I've had to do this on occasion, so I'm familiar with the process.

Marc W
Thanks for the comment, but I think `hg rollback` is what I'm looking for.
David Wolever
From the hg command line help on rollback, "It will also restore the dirstate at the time of the last transaction." Isn't this what you're trying to avoid?
Marc W
@Marc: no, he wants the dirstate back too. That is what keeps track of added files, for example. So "hg add foo.c; hg commit; hg rollback" will leave foo.c added as per "hg status".
Martin Geisler
By the way, I agree that talking about "the dirstate" is poor style since users shouldn't have to be aware of this terminology.
Martin Geisler
+7  A: 

You want the hg rollback command. This command will remove the last transaction from your repository. A commit is a transaction, so you can use this as

% hg commit -m 'My elaburate bugfix.' foo.c foo.h
% hg rollback
% hg commit -m 'My elaborate bugfix.' foo.c foo.h

After the rollback the files will again be seen as modified, and this means that the second commit will store the same changes as the first, but with a better commit message.

Beware: hg rollback is more powerful than a simple "uncommit" function. If someone has pushed to your repository, then that change will be the last transaction, and so hg rolllback will remove their changesets. This means that you should only use hg rollback on private repositories where you are sure that nobody else will have created transactions in the mean time.

Also, if you have not given the commit message on the command line, then you cannot just press up-arrow twice to redo the commit after a rollback. However, Mercurial 1.5 and later will save your last commit message in .hg/last-message.txt so that you can always find it again after a rollback.

Martin Geisler
A: 

There is also the "hg strip" command from the "mq" extension. At least it used to be. It is almost exact equivalent of "bzr uncommit". Beware though, when you pushed your errant commit earlier to another repository, it will be recreated with the nearest pull from it.

m--s
Sorry, this is incorrect — `hg strip` will delete changesets from the repository while `bzr uncommit` will set the repository and working tree back to the state they were in immediately before the commit.
David Wolever
Well, that's exactly why i used the word 'almost' - the only difference seems to be the state of the working directory. I just thought that it is worth mentioning, as this is the only Mercurial equivalent for 'bzr uncommit' (and sadly, a non-obvious one, so it is hard to find), capable of removing multiple changesets NOT immediately after the commit. According to Bazaar docs, bzr uncommit can do that. If you know of another history-tampering Mercurial command capable of removing multiple changesets (like for example 'bzr uncommit -r 1'), then please let me know. I'd be happy to learn about it.
m--s