Mercurial Queues is the primary method used by many Thunderbird developers to create patches and work on multiple bugs without stumbling upon merge conflicts.
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 qrefresh is 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.
Version your patch queue to save changes. The mqext extension can make this much easier.
To enable MQ, put this in your
Mecurial.ini file for Windows or the
$HOME/.hgrc file for Linux and macOS:
[extensions]mq =[diff]git = 1unified = 8showfunc = 1
Don't forget the
git line. This allows changing binary files in your patches. The
unified line 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:
qnew is the command to initial a new patch.
-m is 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-name is, 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/patches directory under the repository.
Whenever you change something in your code, you need to trigger the
hg qrefresh command in order to update your current patch with the latest changes. Do a
hg diff before you issue
hg qefresh to 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 qseries to 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 diff and
hg qdiff take a
-w argument 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 pathes in order to prevent merge conflicts. Here's a standard workflow you should follow:
hg qpop -a to "pop" all your patches and revert the code base to its original status.
hg pull -u to pull all the recent changes from upstream.
hg qpush to apply once again your patch. Trigger this command as many times as you need in order to apply all the patches in sequence.
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
qrefresh command will only update the code to the patch at the top of you series.
hg qseries command 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 patcheshg 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 filehg qpush patch-name # Reapply patches -- watch out for rejects!
With MQ you can import a patch into your queue, e.g. from Bugzilla. It is unapplied by default and the
filename is 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-name to specify the patch name.
hg qimport https://bugzilla.mozilla.org/attachment.cgi?id=9086264 -n patch-namehg qimport ~/Your/Chosen/Directory/filename.patch -n patch-namehg qimport https://hg.mozilla.org/comm-central/rev/0e7bfdf1b900
If you have the
qimportbz extension 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 ...hg qrefresh... change some more files ...hg qrefresh -m "Bug 123456: A brief summary of the changes you have made."
hg export qtip > ~/bug-123456-fix.patch is not necessary since all the patches reside in the
.hg/patches directory 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 diff to see the latest changes which aren't in your patch yet. You can either add them to the patch using
hg qrefresh or remove them with
hg revert --all. Your best friend is the
hg out command, 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 import instead of
hg out will show changes that are not controlled by patches in a MQ. In this case you can strip all changeset
hg out shows using
hg strip -r with 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 qdelete or 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 0e7bfdf1b900hg qbackout -r 0e7bfdf1b900:0e7bfdf1b901 (multiple consequtive changesets)hg qbackout -r 0e7bfdf1b900 -r 0e7bfdf1b955 (non-consequtive)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).