Mercurial_ The Definitive Guide - Bryan O'Sullivan [61]
Erasing Local History
The Accidental Commit
I have an occasional but persistent problem of typing rather more quickly than I can think, which sometimes results in me committing a changeset that is either incomplete or plain wrong. In my case, the usual kind of incomplete changeset is one in which I’ve created a new source file, but forgotten to hg add it. A “plain wrong” changeset is not as common, but no less annoying.
Rolling Back a Transaction
In Safe Operation, I mentioned that Mercurial treats each modification of a repository as a transaction. Every time you commit a changeset or pull changes from another repository, Mercurial remembers what you did. You can undo, or roll back, exactly one of these actions using the hg rollback command. (See Rolling Back Is Useless Once You’ve Pushed for an important caveat about the use of this command.)
Here’s a mistake that I often find myself making: committing a change in which I’ve created a new file, but forgotten to hg add it.
$ hg status
M a
$ echo b > b
$ hg commit -m 'Add file b'
Looking at the output of hg status after the commit immediately confirms the error.
$ hg status
? b
$ hg tip
changeset: 1:c6a8d372cddf
tag: tip
user: Bryan O'Sullivan date: Tue May 05 06:44:44 2009 +0000 summary: Add file b The commit captured the changes to the file a, but not the new file b. If I were to push this changeset to a repository that I shared with a colleague, the chances are high that something in a would refer to b, which would not be present in their repository when they pulled my changes. I would thus become the object of some indignation. However, luck is with me—I’ve caught my error before I pushed the changeset. I use the hg rollback command, and Mercurial makes that last changeset vanish. $ hg rollback rolling back last transaction $ hg tip changeset: 0:b80eb7d60f97 tag: tip user: Bryan O'Sullivan date: Tue May 05 06:44:44 2009 +0000 summary: First commit $ hg status M a ? b Notice that the changeset is no longer present in the repository’s history, and the working directory once again thinks that the file a is modified. The commit and rollback have left the working directory exactly as it was prior to the commit; the changeset has been completely erased. I can now safely hg add the file b, and rerun my commit. $ hg add b $ hg commit -m 'Add file b, this time for real' The Erroneous Pull It’s common practice with Mercurial to maintain separate development branches of a project in different repositories. Your development team might have one shared repository for your project’s “0.9” release, and another, containing different changes, for the “1.0” release. Given this, you can imagine that the consequences could be messy if you had a local “0.9” repository, and accidentally pulled changes from the shared “1.0” repository into it. At worst, you could be paying insufficient attention, and push those changes into the shared “0.9” tree, confusing your entire team (but don’t worry, we’ll return to this horror scenario later). However, it’s more likely that you’ll notice immediately, because Mercurial will display the URL it’s pulling from, or you will see it pull a suspiciously large number of changes into the repository. The hg rollback command will work nicely to expunge all of the changesets that you just pulled. Mercurial groups all changes from one hg pull into a single transaction, so one hg rollback is all you need to undo this mistake. Rolling Back Is Useless Once You’ve Pushed The value of the hg rollback command drops to zero once you’ve pushed your changes to another repository. Rolling back a change makes it disappear entirely, but only in the repository in which you performed the hg rollback. Because a rollback eliminates history,