Mercurial Queues

  • Revision slug: Mercurial_Queues
  • Revision title: Mercurial Queues
  • Revision id: 33804
  • Created:
  • Creator: Benjamin Smedberg
  • Is current revision? No
  • Comment Some cleanup... remove the second-person a bit, add a bigger-badder warning.

Revision Content

Mercurial Queues, or MQ, is a Mercurial extension that lets you keep work in progress as mutable patches, instead of as immutable changesets.

Read this first! It'll save you some lost work.

  • You can 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.
  • 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. So:
  • Use hg qcommit -m backup to keep versions of your patches.
  • Avoid the -f option, except for hg qnew -f. Normally -f is dangerous because it's sharp. Here it's more like, -f makes assumptions, and if the assumptions are wrong you get implementation-defined, undocumented behavior.
  • 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.

Introduction

The output of a developer (on a good day, anyway) is patches. The MQ extension lets you treat a stack of patches as works-in-progress. You can apply them as Mercurial changesets, unapply them, edit them, and when they're done, turn them into permanent changesets and push them.

Each repository has its own queue of patches managed by MQ. They're just stored as files in a special directory, repository/.hg/patches.

To enable MQ, put this in your $HOME/.hgrc file:

[extensions]
hgext.mq =
[diff]
git = 1

Then, in the repository where you want to use MQ, type

hg qinit -c

This creates the patches directory and makes a separate hg repository in there for tracking your patches. (Advice: Don't skip this step. The separate hg repo is kinda weird, but the good news is, you never really have to think about it or look at it... until it saves your life.)

The life of a patch

The simplest possible life story of an MQ patch goes something like:

  • Make some changes in your working directory.
  • Use hg qnew -f bug-155443 to turn those changes into a patch. This is kinda like committing, only the commit isn't permanent.
  • Continue editing. Use hg qrefresh periodically to put those new changes into the patch, and you use hg qcommit -m "backup" to make a permanent record of your work.
  • Use hg qdiff to review your changes so far.
  • When the patch is complete and reviewed, use hg qrefresh -e to give it a commit message, then hg qdelete -r bug-155443 to turn the patch into a permanent changeset.
  • Finally, hg push your patch to a public repository.

Commands

The basic MQ commands are:

hg qnew patch-name
Make a new empty patch and give it a name. The new patch is applied when it's created. That means it's a changeset. If you do hg log -r . you'll see it. All the other hg commands, like hg annotate and hg grep, see it as a regular changeset.
Most people use hg qnew -f patch-name. The -f flag here means "take all these uncommitted changes in my working copy and make a new patch out of them".
hg qrefresh
Update the current patch to include your latest uncommitted changes. You'll do this often.
hg qcommit -m "backup"
Save a snapshot of your .hg/patches directory as a Mercurial revision in the .hg/patches repository. Do this often, too.
hg qpop
Unapply a patch. This removes the changeset. The patch is set aside in your .hg/patches directory. You can do other work, then re-apply your patch later.
If you have multiple patches applied, you can hg qpop -a to unapply them all.
hg qpush {{mediawiki.external('<var>patch-name</var>')}}
Apply an unapplied patch. If the patch is out of date—that is, if you've done hg update since the last time you refreshed it—then you might get rejects! The only thing to do in that case is to apply the rejects manually and hg qrefresh.
With a patch name, this applies patches until the desired patch is on top.
hg qpush -a applies them all.
hg qrefresh -e
hg qdelete -r patchname
"Finish" the bottommost applied patch. It becomes a permanent changeset, suitable for pushing.
The qrefresh -e lets you set the commit message the way you want it. (You can use hg qrefresh -m "message" instead, if you like.)
The qdelete command removes the patch from your .hg/patches directory (and from MQ's oversight generally).

Just as important are the commands that show you what's going on:

hg qseries -v
List all MQ patches. Applied patches are listed as A, and unapplied patches as U.
hg qapplied
List all the MQ patches that are applied, in queue order (that is, the order they were applied).
hg log -r qbase:qtip
Same thing, but show the changesets. (qbase and qtip are tags provided by MQ. They always point to the bottommost and topmost applied patch.)
hg unapplied
List all the MQ patches that aren't applied, in queue order (that is, the order they would be applied, if you did hg qpush -a).

Revision Source

<p><b>Mercurial Queues</b>, or <b>MQ</b>, is a <a href="en/Mercurial">Mercurial</a> extension that lets you keep work in progress as mutable patches, instead of as immutable changesets.
</p>
<div class="warning">
<p>Read this first!  It'll save you some lost work.
</p>
<ul><li> <b>You can destroy work with MQ.</b> 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.
</li><li> <b><code>hg qrefresh</code> is destructive.</b>  It replaces your previous version of the current patch with what's in your working directory.  The previous version is lost.  So:
</li><li> <b>Use <code>hg qcommit -m backup</code> to keep versions of your patches.</b>
</li><li> <b>Avoid the <code>-f</code> option, except for <code>hg qnew -f</code>.</b>  Normally <code>-f</code> is dangerous because it's sharp.  Here it's more like, <code>-f</code> makes assumptions, and if the assumptions are wrong you get implementation-defined, undocumented behavior.
</li><li> <b>Don't use MQ in a repository anyone might pull from.</b>  MQ creates temporary changesets in your repo.  If someone pulls one of them, you'll never get rid of it.
</li></ul>
</div>
<h3 name="Introduction"> Introduction </h3>
<p>The output of a developer (on a good day, anyway) is patches.  The MQ extension lets you treat a stack of patches as works-in-progress.  You can apply them as Mercurial changesets, unapply them, edit them, and when they're done, turn them into permanent changesets and push them.
</p><p>Each repository has its own queue of patches managed by MQ.  They're just stored as files in a special directory, <code>repository/.hg/patches</code>.
</p><p>To enable MQ, put this in your <code>$HOME/.hgrc</code> file:
</p>
<pre class="eval">[extensions]
hgext.mq =
</pre>
<pre class="eval">[diff]
git = 1
</pre>
<p>Then, in the repository where you want to use MQ, type 
</p>
<pre class="eval"><code>hg qinit -c</code>
</pre>
<p>This creates the patches directory and makes a separate hg repository in there for tracking your patches.  (Advice:  Don't skip this step.  The separate hg repo is kinda weird, but the good news is, you never really have to think about it or look at it... until it saves your life.)
</p>
<h3 name="The_life_of_a_patch"> The life of a patch </h3>
<p>The simplest possible life story of an MQ patch goes something like:
</p>
<ul><li> Make some changes in your working directory.
</li><li> Use <code>hg qnew -f bug-155443</code> to turn those changes into a patch.  This is kinda like committing, only the commit isn't permanent.
</li><li> Continue editing.  Use <code>hg qrefresh</code> periodically to put those new changes into the patch, and you use <code>hg qcommit -m "backup"</code> to make a permanent record of your work.
</li><li> Use <code>hg qdiff</code> to review your changes so far.
</li><li> When the patch is complete and reviewed, use <code>hg qrefresh -e</code> to give it a commit message, then <code>hg qdelete -r bug-155443</code> to turn the patch into a permanent changeset.
</li><li> Finally, <code>hg push</code> your patch to a public repository.
</li></ul>
<h3 name="Commands"> Commands </h3>
<p>The basic MQ commands are:
</p>
<dl><dt><code>hg qnew <var>patch-name</var></code>
</dt><dd>Make a new empty patch and give it a name.  The new patch is <i>applied</i> when it's created.  That means it's a changeset.  If you do <code>hg log -r .</code> you'll see it.  All the other <code>hg</code> commands, like <code>hg annotate</code> and <code>hg grep</code>, see it as a regular changeset.
</dd><dd>Most people use <code>hg qnew <b>-f</b> <var>patch-name</var></code>.  The <code>-f</code> flag here means "take all these uncommitted changes in my working copy and make a new patch out of them".
</dd></dl>
<dl><dt><code>hg qrefresh</code>
</dt><dd>Update the current patch to include your latest uncommitted changes.  You'll do this often.
</dd></dl>
<dl><dt><code>hg qcommit -m "backup"</code>
</dt><dd>Save a snapshot of your <code>.hg/patches</code> directory as a Mercurial revision in the <code>.hg/patches</code> repository.  Do this often, too.
</dd></dl>
<dl><dt><code>hg qpop</code>
</dt><dd><i>Unapply</i> a patch.  This removes the changeset.  The patch is set aside in your <code>.hg/patches</code> directory.  You can do other work, then re-apply your patch later.
</dd><dd>If you have multiple patches applied, you can <code>hg qpop -a</code> to unapply them all.
</dd></dl>
<dl><dt><code>hg qpush {{mediawiki.external('&lt;var&gt;patch-name&lt;/var&gt;')}}</code>
</dt><dd>Apply an unapplied patch.  If the patch is out of date—that is, if you've done <code>hg update</code> since the last time you refreshed it—then you might get rejects!  The only thing to do in that case is to apply the rejects manually and <code>hg qrefresh</code>.
</dd><dd>With a patch name, this applies patches until the desired patch is on top.
</dd><dd><code>hg qpush -a</code> applies them all.
</dd></dl>
<dl><dt><code>hg qrefresh -e</code>
</dt><dt><code>hg qdelete -r <var>patchname</var></code>
</dt><dd>"Finish" the bottommost<i> applied patch.  It becomes a permanent changeset, suitable for pushing.</i>
</dd><dd>The <code>qrefresh -e</code> lets you set the commit message the way you want it.  (You can use <code>hg qrefresh -m "message"</code> instead, if you like.)
</dd><dd>The <code>qdelete</code> command removes the patch from your <code>.hg/patches</code> directory (and from MQ's oversight generally).
</dd></dl>
<p>Just as important are the commands that show you what's going on:
</p>
<dl><dt><code>hg qseries -v</code>
</dt><dd>List all MQ patches. Applied patches are listed as A, and unapplied patches as U.
</dd></dl>
<dl><dt><code>hg qapplied</code>
</dt><dd>List all the MQ patches that are applied, in queue order (that is, the order they were applied).
</dd></dl>
<dl><dt><code>hg log -r qbase:qtip</code>
</dt><dd>Same thing, but show the changesets.  (<code>qbase</code> and <code>qtip</code> are tags provided by MQ.  They always point to the bottommost and topmost applied patch.)
</dd></dl>
<dl><dt><code>hg unapplied</code>
</dt><dd>List all the MQ patches that aren't applied, in queue order (that is, the order they would be applied, if you did <code>hg qpush -a</code>).
</dd></dl>
Revert to this revision