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
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')
$ 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