jasonwryan.com

Miscellaneous ephemera…

Sharing Mercurial Patchsets

In my last post, on Mercurial Queues, I outlined how you might use MQ to manage a dwm patchset. Mercurial makes this process ridiculously easy, and this functionality is more than enough to recommend it. However, where I think it really gets interesting is when you share that same patchset across multiple machines and are easily able to customize which patches in the queue are applied, based upon the particular machine you are building dwm on.

For example, in my case I use dwm on all three of my machines: my desktop at home, my laptop at work and my EeePC. Given the nature of each of these three machines, though, I want a slightly different stack of patches applied. These differences might extend only to particular rules applied in config.def.h based upon the number of tags I use, or the different applications that I run at home as opposed to at work.

In any event, what I want to be able to do is maintain a single patchset in a mercurial repository, clone it to all my machines and then, using MQ, filter which specific patches are applied. This is all possible using a killer feature of MQ called guards. Guards allow you to conditionally apply patches in a queue. Essentially, in a queue, you “tag” a patch with a guard and—depending on whether or not the guard is positive (to be applied), or negative (to be skipped)—when you hg qpush -a MQ takes care of applying the correct patches in the queue.

So, in the case of my work laptop, I begin by cloning dwm and intializing a patch queue:

1
2
3
cd Build/
hg clone http://hg.suckless.org/dwm
hg qinit -c

I setup my .hgrc within the patches directory so that it points at the correct mercurial repository:

.hg/patches/.hg/hgrc
1
2
3
4
5
6
 # Mercurial config file
[ui]
username = jasonwryan <jasonwryan@gmail.com>
ssh = ssh -i ~/.ssh/bb -C
[paths]
default = ssh://hg@bitbucket.com/jasonwryan/dwm-patchset

Then I pull down my dwm patchset from the mercurial repository with hg pull:

1
2
3
4
5
6
7
pulling from ssh://hg@bitbucket.com/jasonwryan/dwm-patchset
requesting all changes
adding changesets
adding manifests
adding file changes
added 6 changesets with 16 changes to 10 files
(run 'hg update' to get a working copy)

After I update my local repo,1 I can see the full patchset with hg qseries:

1
2
3
4
5
6
7
setup.makefile
base.config.customizations
statuscolours
cycle
push
bstack
centurion.config

Then, as I decribed in my previous post, I make the changes to config.def.h that are specific to this machine:

1
2
3
4
hg qnew veles.config
 # “hack, hack, hack…”
hg qrefresh
hg qcommit -m 'Adaptions for Veles'

My patchset now has an additional patch in it:

1
2
3
4
5
6
7
8
9
10
┌─[Veles ~/Build/dwm]
└─╼ hg qseries
setup.makefile
base.config.customizations
statuscolours
cycle
push
bstack
centurion.config
veles.config

This is where guards come in to play. If I wasn’t interested in sharing the patchset, it would just be a matter of deleting the patch for Centurion. However, what I want to do is direct MQ to ignore that specific patch when applying the queue. I do that by creating a negative guard and then activating it:

1
2
3
hg qguard centurion.config -- -block
hg qselect block
number of unguarded, unapplied patches has changed from 8 to 7

That’s it! Adding a verbose flag to hg qseries2 will print out the patchset and the accompanying guard status:

1
2
3
4
5
6
7
8
9
10
┌─[Veles ~/Build/dwm]
└─╼ hg qseries -v
0 U setup.makefile
1 U base.config.customizations
2 U statuscolours
3 U cycle
4 U push
5 U bstack
6 G centurion.config
7 U veles.config

The real test, of course, is pushing the patchset onto the fresh dwm code:

1
2
3
4
5
6
7
8
9
10
11
┌─[Veles ~/Build/dwm]
└─╼ hg qpush -a
applying setup.makefile
applying base.config.customizations
applying statuscolours
applying cycle
applying push
applying bstack
skipping centurion.config - guarded by '-block'
applying veles.config
now at: veles.config

How cool is that? One central patchset, applied conditionally depending upon the machine you are using at the time.

Notes

  1. Any guards applied on other machines will be present in the newly pulled series file: these conflicts will need to be manually merged…
  2. The options for all of the hg commands can be read with hg -v help $command. For those related to queues, just prepend a q to $command.

Creative Commons image on Flickr by Thorsten Becker

Comments