GliderJan Varho

Working With Multiple Mercurial Queues (hg mqs)

  • Mercurial
  • hg
  • Mercurial queues

I've recently been using mercurial for revision control. I still don't like it much as git, because it tries so hard to prevent me from modifying history (modifying local history is not a bad idea) and has so many tools that do almost the same thing.

However, the MQ extension is quite nice. Even though it requires you to learn a new set of commands (where in git you'd just use another local branch as a queue), it does make modifying and moving through patches somewhat easier than git rebase -i.

This is not a tutorial in using MQs, for that see e.g. here. Instead, I'm only looking at using multiple patch queues for which very little documentation can be found online.

Creating and Moving Between Queues

The main command for interacting with queues (as opposed to patches) is the hg qqueue command. Its help output gives a list of the options you use to manage queues:

-l --list list all available queues --active print name of active queue -c --create create new queue --rename rename active queue --delete delete reference to queue --purge delete queue, and remove patch dir

Each time you use hg qq --create $QNAME to create a new patch queue and put some patches in it, a new directory is created in .hg/patches-$QNAME/. Each such directory works just like the .hg/patches/ directory does for the default queue (called 'patches').

You move between queues using hg qq $QNAME, but must first ensure no patches are applied, e.g. using hg qpop --all.

To list queues and see which is active, hg qq without options or arguments suffices. So in practice you don't normally need the -l/--list or --active options. The rest should be self-explanatory.

Moving/Copying Patches Between Queues

Since each patch queue is treated independently and you can only apply patches from one at a time, you may find you need to move or copy patches between queues. There is no special command for that, but the generic patch import command hg qimport works quite well.

Say you have a patch called 'A' in the default 'patches' queue and you want to copy it to the current queue. You can import it using hg qimport .hg/patches/A from the project's base directory. The patch gets imported and added on top on the current patch, but not applied. Add the -P/--push option to apply it immediately. Using this command you create an independent copy of a patch in the second queue so any changes in one will not be reflected in the other.

Alternatively, you can let a single copy of a patch be part of several queues using hg qimport -e ../patches/A. This way both queues point to the same patch file from their series/status files. The path part ../patches/ is actually part of the patch name in the second queue, so this is kind of a hack.

Of course, using the same patch file only really works if the patch applies cleanly in both queues (e.g. if it's the first patch in both). Remember to use hg qdelete -k/--keep if you need to delete it from one queue – I use an alias qdelete = qdelete -k. You will also not want to use hg qqueue --purge in this case!

Problems or Pitfalls

Unfortunately, the patch queues' use of different directories means that each of them has a separate repo if you use versioning, and patches that are part of two queues are separately versioned. You could probably work around this somehow if you really wanted to.

Note that guards are defined per queue. Whichever method you use to include one patch in two queues, you need to define the guards for each patch in each queue. You will also have to use hg qselect separately in each queue you work with when you e.g. move between branches.