Debug Command Tricks

posted by Friedrich Kastner-Masilko on April 23, 2010

If you tried hg help --debug, you may be familiar with the commands prefixed with ‘debug’. Most of them are used to inspect Mercurial’s internal storage, but some can come handy in certain situations. Two of these commands are hg debugsetparents and hg debugrebuildstate.

The first command forces Mercurial to forget the “real” parent revisions of a working-copy in favor of the specified revisions in ‘debugsetparents’. The second command is forcing Mercurial to rebuild its internal state.

So how can this be useful in normal conditions at all? Here are 3 scenarios where it comes handy to work with them:

1. Late-binding working-copy with repository.

Imagine an interesting project hosted with Mercurial. At first you only download a snapshot of the project to inspect the code and try something out. You didn’t clone it fully, because you wanted to avoid the overhead to just check the source.

Later in the process of playing with the code, you realize that this is going to be a longer-lasting relationship, so you decide to clone the repo and commit your changes. Since it is quite a big working-copy and you renamed/deleted/added some files, you don’t want to copy the whole thing over some checkout in order to not confuse the working-copy state. So how to commit this state at the proper location?

The solution is to copy the .hg folder into the snapshot’s root and issue:

$ hg debugsetparent tip
$ hg debugrebuildstate
$ hg commit -Am "my snapshot"

2. Creating alternate check-ins.

If you are anything like me, you don’t trust yourself. Therefore, you’d want to add alternative work BEFORE you delete one of the alternatives. So the usual workflow of using rollback to take back an ill-composed commit is not your thing.

Instead, it is possible to simply:

$ hg debugsetparent tip^^
$ hg debugrebuildstate

And you are back at the state you where before you commited, just with the “wrong” commit still there.

3. Simulate Git’s —no-ff merges with anonymous heads.

Most of the workflows for Git are easily reproducible with Mercurial, but some of them (gitflow) use so-called “non-fast-forward” merges. These merges can be done in Mercurial, too, but only with named-branches:

$ hg sl
$ echo x > x
$ hg ci -Am "base"
adding x
$ hg branch feature
marked working directory as branch feature
$ echo y > x
$ hg ci -m "feature"
$ hg up default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg merge feature
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg ci -m "merged"
$ hg glog
@    changeset:   2:e0502e1d12c6
|\   tag:         tip
| |  parent:      0:387ca709aeaf
| |  parent:      1:205ec0dce78f
| |  summary:     merged
| |
| o  changeset:   1:205ec0dce78f
|/   branch:      feature
|    summary:     feature
|
o  changeset:   0:387ca709aeaf
   summary:     base

As you can see in the above graphlog output, the merge contains no actual information besides indicating the merging of two named-branches (‘default’ and ‘feature’). As with Mercurial 1.5.1, you can’t do that with anonymous heads:

$ echo x > x
$ hg ci -Am "base"
adding x
$ echo y > x
$ hg ci -m "feature"
$ hg up 0
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg merge 1
abort: nothing to merge (use 'hg update' or check 'hg heads')

Why would you want to do that with anonymous heads, anyway? Well, one way of simulating Git branches is the bookmark extension. Unfortunately, using bookmarks (to name anonymous heads) is still using anonymous heads, so the above problem gets in your way:

$ hg bookmark master
$ hg bookmark feature -r 1
$ hg bookmark
 * master                    0:6965ee5bb884
   feature                   1:2061809a8e23
$ hg merge feature
abort: nothing to merge (use 'hg update' or check 'hg heads')

The solution:

$ hg debugsetparents master feature
$ hg revert -a -r feature
reverting x
$ hg ci -m "merged"
$ hg glog
@    changeset:   2:0dfae55684f6
|\   tag:         master
| |  tag:         tip
| |  parent:      0:6965ee5bb884
| |  parent:      1:2061809a8e23
| |  summary:     merged
| |
| o  changeset:   1:2061809a8e23
|/   tag:         feature
|    summary:     feature
|
o  changeset:   0:6965ee5bb884
   summary:     base

Mercurial has some “hidden” debug commands that can make your day in special situations.