Skip to main content

Mercurial: async operations are safer too

Posted by fabriziogiudici on July 27, 2009 at 10:53 AM PDT

I've previously told you that I'm going to blog about why I've switched to Mercurial and how I'm using it.

A quick tip for today is to learn how the capability of working in async mode (that is, you first commit locally and later push to the primary repo) can be also a safer way to work.

Consider this: while still working on the default branch of jrawio and fixing bugs, I've created a 2.0 branch for developing new stuff. Today I decided to remove a file README.html that got very old and it's now misleading - it should be rewritten from scratch. Here we go:

[Mistral:Projects/jrawio/src] fritz% hg remove README.html 
[Mistral:Projects/jrawio/src] fritz% hg commit -m "Dropped obsolete README.html"

The commit is only local. Before pushing out stuff, I've got the habit of reviewing the latest local changes:

[Mistral:Projects/jrawio/src] fritz% hg outgoing
comparing with https://kenai.com/hg/jrawio~src
searching
for changes
changeset:   306:bbecb5d43e63
branch:      2.0                <--- EEEK! WRONG BRANCH!
tag:         tip
user:        fabriziogiudici
date:        Tue Jul 28 13:30:51 2009 +0200
summary:     Dropped obsolete README.html.

Good habit! In fact, I could verify that I worked in the wrong branch: 2.0 instead of default. If you do such a mistake, you can cancel local changes, even committed ones, in a few different ways; for instance, by using the hg strip command, which eradicates all the changed children of a given revision:

[Mistral:Projects/jrawio/src] fritz% hg strip 306
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
saving bundle to /Volumes/Projects/jrawio/src/.hg/strip-backup/bbecb5d43e63-backup
[Mistral:Projects/jrawio/src] fritz% hg outgoing
comparing with https://kenai.com/hg/jrawio~src
searching
for changes
no changes found

Be careful with this command: if I made other commits, depending on 306, they would be eradicated too.

After having restored the status prior my mistake, I could re-apply the change, this time in the correct branch:

[Mistral:Projects/jrawio/src] fritz% hg update -c default
3 files updated, 0 files merged, 11 files removed, 0 files unresolved
[Mistral:Projects/jrawio/src] fritz% hg remove README.html
[Mistral:Projects/jrawio/src] fritz% hg commit -m "Dropped obsolete README.html"
[Mistral:Projects/jrawio/src] fritz% hg outgoing
comparing with https://kenai.com/hg/jrawio~src
searching
for changes
changeset:   306:1c1d04392ce4
tag:         tip
parent:      303:8e179f7791d0
user:        fabriziogiudici
date:        Tue Jul 28 13:32:49 2009 +0200
summary:     Dropped obsolete README.html

[Mistral:Projects/jrawio/src] fritz% hg push
pushing to https://kenai.com/hg/jrawio~src
searching
for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 0 changes to 0 files

In case you didn't erroneously remove a file, but made other modifications, of course you can easily back up your changes into a tar file before stripping the local repository, and restore them after later when you've switched to the correct branch.

The command hg strip is not available by default; it's an extension that can be activated by putting these lines in your $HOME/.hgrc configuration file:

[extensions]
hgext.mq =

Comments

Actually, I've made the wrong example :-) as you're right it makes sense with multiple commits. Thanks for commenting about hg rollback, that's why blogs and comments are for! ;-)

No, you can only rollback once, but there was a single commit in the above example. For multiple consecutive erroneous commits (a scenario more familiar than I wish) strip does the right thing: thank you for pointing me to it.

Sure. But if I'm not wrong hg rollback cancels only the last commit. Indeed the idea for this post came while I was writing the previous post, and I found myself with two commits in the wrong branch. hg strip in this case works, since cancels both; I think hg rollback cancels only the last one. Or if I perform hg rollback multiple times can I cancel multiple commits one by one?

Maybe you could have used the rollback command, which undoes the last local commit.