Using Mercurial Queues
Tutorial on how to activate and use Mercurial Queues.
Mercurial Queues is the primary method used by many Thunderbird developers to create patches and work on multiple bugs without stumbling upon merge conflicts.
If you're already familiar with Mercurial Queues but you need a quick overview of all the available commands, take a look at the Mercurial Queues reference
You can accidentally destroy work with MQ. MQ puts you in a position where you're doing fairly complicated stuff to your uncommitted work. Certain operations make it easy to lose work. Watch your step.
For instance, unless you're running the mqext,
hg qrefreshis destructive. It replaces your previous version of the current patch with what's in your working directory. The previous version is lost.
Other things to keep in mind:
- Don't use MQ in a repository anyone might pull from. MQ creates temporary changesets in your repo. If someone pulls one of them, you'll never get rid of it.
- Avoid the -f option. It is sharp and can mess up your repository if used incorrectly.
- Ensure you use the latest stable release of Mercurial.
To enable MQ, put this in your
Mecurial.inifile for Windows or the
$HOME/.hgrcfile for Linux and macOS:
Don't forget the
gitline. This allows changing binary files in your patches. The
unifiedline give 8 lines patch.
Create a new patch with the command
hg qnew -m "Bug ###### - fixing something amazing" patch-name. Let's quickly analyze this command:
qnewis the command to initial a new patch.
-mis the command that allows you to write a commit message.
"Bug ###### - fixing something amazing"is the format we recommend using for the commit message, specifying the number of the Bug you're working on and a small description stating what you fixed.
patch-nameis, obviously, the name of your patch, and that can be anything.
Each repository has its own queue of patches managed by MQ. They're just stored as files in the
.hg/patchesdirectory under the repository.
The commit message is optional and you can add it at a later time with a
Whenever you change something in your code, you need to trigger the
hg qrefreshcommand in order to update your current patch with the latest changes. Do a
hg diffbefore you issue
hg qefreshto see which changes will be added to your patch. If you use multiple patches (see section below), it may be a good idea to do a
hg qseriesto make sure the right patch is on top. Otherwise the changes will be added to the wrong patch.
It's always good practice to check if the current changes have been properly saved in your patch by using the command
hg qdiff. All the diffs will be listed in your terminal.
Note that both
hg qdifftake a
-wargument to ignore white-space in case you reindented blocks and it's hard to see the net changes.
If you're working on a patch and you need to pull the updates from upstream, you need to "disconnect" your patches in order to prevent merge conflicts. Here's a standard workflow you should follow:
hg qpop -ato "pop" all your patches and revert the code base to its original status.
hg pull -uto pull all the recent changes from upstream.
hg qpushto apply once again your patch. Trigger this command as many times as you need in order to apply all the patches in sequence.
Merge conflicts can happen when reapplying your patches after pulling updates from upstream. Simply fix the merging issues and
MQ allows you to work on multiple patches at once and keeping the code separate. No matter how many patches you have applied in your queue, the
qrefreshcommand will only update the code to the patch at the top of you series.
hg qseriescommand to visualize a list of currently applied patches and their order.
Sometimes the queue ends up not being in the order you want. For example, maybe you've been working on two patches, and the second one (the topmost one in your queue) is ready to be pushed before the first one is.
If you have Mercurial 1.6 or newer, the best way to reorder your queue is
hg qpush --move. For example:
hg qpop -a # Unapply all patches
hg qpush --move patch-name # Apply only one patch, reordering as needed
With older Mercurial versions, you can do this:
hg qpop -a # Unapply all patches
$EDITOR .hg/patches/series # Manually rearrange the lines of the series file
hg qpush patch-name # Reapply patches -- watch out for rejects!
Reordering patches that touch the same file can cause conflicts when you push! If this happens,
hg qpushwill tell you, and it will leave
.rejfiles in your working directory. To avoid losing work, you must manually apply these rejected changes, then
With MQ you can import a patch into your queue, e.g. from Bugzilla. It is unapplied by default and the
filenameis used as the patch-name. You can directly import a Bugzilla patch by using the Bugzilla attachment URL as the argument. In that case you may also want to use
-n patch-nameto specify the patch name.
hg qimport https://bugzilla.mozilla.org/attachment.cgi?id=9086264 -n patch-name
hg qimport ~/Your/Chosen/Directory/filename.patch -n patch-name
hg qimport https://hg.mozilla.org/comm-central/rev/0e7bfdf1b900
If you have the
qimportbzextension installed, you can also import by specifying a bug number:
hg qimport bz:1574724
Here's a quick overview of a standard workflow you will be using with MQ.
hg qnew bug-123456-fix
... change some files ...
... change some more files ...
hg qrefresh -m "Bug 123456: A brief summary of the changes you have made."
hg export qtip > ~/bug-123456-fix.patchis not necessary since all the patches reside in the
.hg/patchesdirectory in your repository.
If you think that something has gone wrong, do this:
First check your patch queue:
hg qseries. If that looks right, do a
hg diffto see the latest changes which aren't in your patch yet. You can either add them to the patch using
hg qrefreshor remove them with
hg revert --all. Your best friend is the
hg outcommand, it shows all the changesets you have locally which aren't pushed to the repository yet. If for some reason you committed a patch to push it (using
hg qfinish), an action that only the sheriff does, or accidentally used
hg importinstead of
hg outwill show changes that are not controlled by patches in a MQ. In this case you can strip all changeset
hg outshows using
hg strip -rwith the lowest revision shown. After that, do
hg update -C default.
Commands mentioned so far can be abbreviated, so
hg qref, etc.
Of course you can delete patches from your queue using
hg qdeleteor rename them with
hg qrename. If you decide to combine patches, there is
hg qfold, that will merge the first unapplied patch into the patch at the tip of your apply queue. Use with care since the merged patch will be removed and the applied patch will be irreversibly changed.
Even if you're not the sheriff, it's sometimes handy to be able to backout one or more changesets. Use:
hg qbackout -r 0e7bfdf1b900
hg qbackout -r 0e7bfdf1b900:0e7bfdf1b901 (multiple consecutive changesets)
hg qbackout -r 0e7bfdf1b900 -r 0e7bfdf1b955 (non-consecutive)
hg qbackout -s -r 0e7bfdf1b900:0e7bfdf1b901 (merge into a single backout changeset)
There is also limited integration with Phabricator with
hg phabread. That needs a special setup. Ask the resident Thunderbird sheriff for details or read here (but there's more to it).
Last modified 1yr ago