description |
---|
Tutorial on how to activate and use Mercurial Queues. |
{% hint style="danger" %}
Mercurial Queues is not compatible with the moz-phab
code submission tool. This page is here for historical reference only.
{% endhint %}
{% hint style="info" %} 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 {% endhint %}
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 =
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.
{% hint style="info" %}
The commit message is optional and you can add it at a later time with a qrefresh
.
{% endhint %}
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 patches 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.
{% hint style="info" %}
Merge conflicts can happen when reapplying your patches after pulling updates from upstream. Simply fix the merging issues and qrefresh
your patches.
{% endhint %}
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.
Use the 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 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!
{% hint style="warning" %}
Reordering patches that touch the same file can cause conflicts when you push! If this happens, hg qpush
will tell you, and it will leave .rej
files in your working directory. To avoid losing work, you must manually apply these rejected changes, then hg qrefresh
.
{% endhint %}
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-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 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."
Note that 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 qimport
, 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 qser
, 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 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).