Mercurial Queues Extension
This extension is currently being distributed along with Mercurial.
Author: Chris Mason
In a distributed development model, [:ChangeSet:changesets] are traditionally immutable. Once a [:Commit:commit] is done, it lives in the project history forever. This can make it difficult to develop a set of individual changes for submission to a project maintainer. Over time, the development [:Repository:repository] will contain a number of [:Merge:merges], and a long line of changes as the code matures. This history is important for the individual developer, but when the changes are sent upstream they will be very difficult to review.
Andrew Morton originally developed a set of scripts for maintaining kernel [:Patch:patches] outside of any [:SCM] tool. Others extended these into a suite called [http://savannah.nongnu.org/projects/quilt quilt]. The basic idea behind quilt is to maintain patches instead of maintaining source files. Patches can be added, removed or reordered, and they can be refreshed as you fix bugs or update to a new base revision. quilt is very powerful, but it is not integrated with the underlying SCM tools. This makes it difficult to visualize your changes.
The patch queue extension integrates quilt functionality into Mercurial. Changes are maintained as patches which are committed into Mercurial. Commits can be removed or reordered, and the underlying patch can be refreshed based on changes made in the [:WorkingDirectory:working directory]. The patch directory can also be placed under revision control, so you can have a separate history of changes made to your patches.
Enable the extension by adding following lines to your configuration file ([:.hgrc]):
[extensions] hgext.mq =
3. Using Mercurial Queues
After the extension is properly installed, hg help will include the mq commands. These all start with q, and try to mimic commands under quilt. The patch queue lives in a directory named .hg/patches. You can edit the patch files themselves to change the comments used in the Mercurial commit messages. .hg/patches/series lists the patches in the order they will be applied. You can change the patch order simply by moving them around in the series file. Make sure to only change entries in the series file for patches that are not currently applied.
4. Merging patches with new upstream revisions
[:MqMerge] describes this in detail.
Find out more about mq in [:MqTutorial].
6. Hook Examples
You will often not want to [:Push:push] or [:Pull:pull] changes from a repository which has patches applied to it. To prevent yourself from doing this accidentally, you can add these [:Hook:hooks] to your repository .hg/hgrc.
[hooks] # Prevent "hg pull" if MQ patches are applied. prechangegroup.mq-no-pull = ! hg qtop > /dev/null 2>&1 # Prevent "hg push" if MQ patches are applied. preoutgoing.mq-no-push = ! hg qtop > /dev/null 2>&1
7. Command Examples
cd some_existing_hg_repository # setup the patch queue directory hg qinit # create a new patch named firstpatch hg qnew firstpatch # edit some files vi filename # update the patch to contain your changes hg qrefresh # vi .hg/patches/firstpatch to see the result # print the current patch to the screen hg qdiff # make some more changes vi filename # see the differences not yet stored in the patch hg diff # update the patch hg qrefresh # create another patch hg qnew secondpatch # Make more changes, and update the new patch vi filename hg qrefresh # Look at the patches you have applied # Look at all the patches in the queue hg qapplied hg qseries # remove the top patch hg qpop # apply the patch again hg qpush # remove all patches hg qpop -a # apply all patches hg qpush -a
8.1. Email all applied patches
hg email qbase:qtip
8.2. Convert all applied patches into permanent changesets
hg qdelete -r qbase:qtip
8.3. Output all applied patches as a single patch
hg diff -r $(hg parents -r qbase --template '#rev#') -r qtip
8.4. Force all patches to always be in git format
Add this to your .hgrc
8.5. Prevent qrefresh from updating timestamps
If you're keeping your patch queue under revision control, it can be quite annoying when every qrefresh updates the timestamps in your patch. To prevent this you can add this to your .hgrc
8.6. How to add a qstatus command
Add this to your .hgrc (see AliasExtension):
[alias] qstatus = status --rev -2:.
Other useful aliases might be "status --rev qparent:." or "status --rev qparent:qtip"
8.7. Publishing patches
If you're tweaking a patch queue over time, it can get tedious to continually update a published repository with the latest changes. Hooks can make the process pretty automatic. You should have two repositories, one being the base repository and one being a repository of your patches, such as hg qinit -c would create.
In the patch repository, which should be in the root of your main repository, in .hg/patches, set up some changegroup hooks:
[hooks] # check out the latest version of the patches changegroup.1update = hg update # pop the old version from the base repo changegroup.2pop = hg -R ../.. qpop -a # push the versions that were just checked out changegroup.3push = hg -R ../.. qpush -a
If you're feeling really fancy, you could also publish the patch repository itself with another hook:
changegroup.publish = hg push ../../../patches/foo
The [:OverlayRepository:overlay patch queue] is published this way at http://hg.kublai.com/mercurial/overlay
The [:Strip:strip] command is also part of the mq extension, although it does not explicitly uses the patch queue.
10. See also
EditingHistory for a good use of Mercurial Queues.
RecordExtension for qrecord command.
Chapter 12: "Managing change with Mercurial Queues" at http://hgbook.red-bean.com/hgbookch12.html