Mercurial Queues

  • Revision slug: Mercurial_Queues
  • Revision title: Mercurial Queues
  • Revision id: 33823
  • Created:
  • Creator: Sid0
  • Is current revision? No
  • Comment 8 words added

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 Mecurial.ini file (see mozilla-build in https://developer.mozilla.org/en/Windows_Build_Prerequisites)  or $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 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".  If you didn't use -f and get the message "abort: local changes found, refresh first", -f will make those local changes into the patch.

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.

This does NOT save your uncommitted work. Use qrefresh to put edits into patches and qcommit to save snapshots of those patches.

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 patch-name

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 qdelete patchname

Throw an unapplied patch away. This removes the patch from your .hg/patches directory (and from MQ's oversight generally).

This is surprisingly different than hg qdelete -r, described below.

hg qrefresh -e

qrefresh -e lets you set the commit message the way you want it. (You can use hg qrefresh -m "message" instead, if you like.)

hg qfinish or hg qdelete -r qbase

"Finish" the bottommost applied patch. It becomes a permanent changeset, suitable for pushing, using the commit message set with qrefresh.

You can only finish patches from the bottom (i.e. you can't finish a patch that's applied over unfinished patches). hg qfinish -a (or hg qdelete -r qbase:qtip) will finish all applied patches. See also #Reordering the queue below.

hg qimport filename

Import a patch into your queue. It is unapplied by default and the filename is the patchname. Useful for testing patches shared on Bugzilla.

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

hg diff
hg status
These show you only uncommitted edits—work that's neither committed nor in an MQ patch. After a qrefresh, they'll both be empty.

 

hg qdiff

Show what the topmost applied MQ patch looks like, including any uncommitted edits you've made.

Use hg qdiff -U 8 to produce patches for review. (Unfortunately qdiff doesn't support -p yet; you can put {{ mediawiki.external('diff') }} showfunc=True in your ~/.hgrc file to get that.)

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 qunapplied

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).

To see more advanced commands, use hg help.

Advanced Topics

Rebasing patches

Rebasing for dummies. When you write a patch, it's based on whatever version of the repo you had when you started working. Of course, changes are constantly being pushed to the central repository, so by the time you want to push, you'll be out of date. Your changes are based on an old revision.

       $ hg glog --template '{node|short} - {author} - {desc|firstline}\n' 
TIP -> o  cd9f8db8ee0f - Devin Naquin <dnaquin@example.com> - Bug 383223
       |
       o  103f04f54b14 - L. David Baron <dbaron@example.org> - Tests for z-ordering of text-decorations.
       |
       o  e3a4c136455b - Robert O'Callahan <robert@example.org> - Support system proxy settings on OS X, fixi
       |
       o  745e0f997344 - Robert O'Callahan <robert@example.org> - Support system proxy settings on OS X, fixi
       |
       o  9d80a1461309 - Robert O'Callahan <robert@example.org> - Support system proxy settings on OS X, fixi
       |
       o  4721deb1dd19 - Diane Trout <diane@example.org>, James Bunton <jamesbunton@example.fm> - Support syst
       |
       o  3e166c19d130 - Michael Ventnor <ventnor.bugzilla@example.com.au> - text-shadow tests (bug 10713)
       |
       o  c06307605f98 - Michael Ventnor <ventnor.bugzilla@example.com.au> - Implement text-shadow rendering.
       |
YOU ---->@  d243d3af29ed - Jason Orendorff <jorendorff@example.com> - [mq] Implement trebled fromps.
       |/
       o  1df6e4240511 - Shawn Wilsher <sdwilsh@example.com> - Bug 429987
       |
       .
       .
       . (the past)

You have two choices:

  • Go ahead and finish your patch now, then hg merge with the tip; or
  • Rebase your patch before you finish and push it.

Rebasing is considered the polite thing. Merging leaves a merge changeset in the history.

It's best not to hg pull while you have patches applied. The most foolproof way to pull and update is:

$ hg qpop -a             # Unapply all patches
$ hg pull
$ hg update
$ hg qpush patchname     # Reapply patches -- watch out for rejects!

Warning: Rebasing across changesets that touch the same files as your patches 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.

Rebasing for smarties. If you're used to Mercurial and MQ and you dislike .rej files, you might want to consider MqMerge. This technique lets you rebase using your merge program, but it's a bit complex.

"Rebasing for smarties" for dummies. hg pull --rebase will pull changesets from hg.mozilla.org and rebase your patches on top of them, allowing you to deal with conflicts with a merge program instead of .rej files. See RebaseExtension and RebaseProject for more.

As of Mercurial 1.1, rebasing using hg rebase or hg pull --rebase might lose rename data; this is a known bug.

Reordering the queue

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.

The easiest way to fix this is:

$ hg qpop -a                   # Unapply all patches
$ $EDITOR .hg/patches/series   # Rearrange the lines of the series file
$ hg qpush patchname           # Reapply patches -- watch out for rejects!

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.

Wanted

  • Using MQ to thaw/edit/refreeze history
  • Sharing patch repos
  • guards, maybe
  • multiple queues, maybe

 

Revision Source

<p><strong>Mercurial Queues</strong>, or <strong>MQ</strong>, is a <a href="/en/Mercurial" title="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><strong>You can destroy work with MQ.</strong> 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><strong><code>hg qrefresh</code> is destructive.</strong> It replaces your previous version of the current patch with what's in your working directory. The previous version is lost. So:</li> <li><strong>Use <code>hg qcommit -m backup</code> to keep versions of your patches.</strong></li> <li><strong>Avoid the <code>-f</code> option, except for <code>hg qnew -f</code>.</strong> 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><strong>Don't use MQ in a repository anyone might pull from.</strong> 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 Mecurial.ini file (see mozilla-build in https://developer.mozilla.org/en/Windows_Build_Prerequisites)  or <code>$HOME/.hgrc</code> file:</p>
<pre class="eval">[extensions]
hgext.mq =

[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 <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>
<p>Make a new empty patch and give it a name. The new patch is <em>applied</em> 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.</p>
<p>Most people use <strong><code>hg qnew -f <var>patch-name</var></code></strong>. The <code>-f</code> flag here means "take all these uncommitted changes in my working copy and make a new patch out of them".  If you didn't use -f and get the message "abort: local changes found, refresh first", -f will make those local changes into the patch.</p>
</dd> <dt><code>hg qrefresh</code> </dt> <dd>
<p>Update the current patch to include your latest uncommitted changes. You'll do this often.</p>
</dd> <dt><code>hg qcommit -m "backup"</code> </dt> <dd>
<p>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.</p>
<p>This does <em>NOT</em> save your uncommitted work. Use <code>qrefresh</code> to put edits into patches and <code>qcommit</code> to save snapshots of those patches.</p>
</dd> <dt><code>hg qpop</code> </dt> <dd>
<p><em>Unapply</em> 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.</p>
<p>If you have multiple patches applied, you can <code>hg qpop -a</code> to unapply them all.</p>
</dd> <dt><code>hg qpush <var>patch-name</var></code> </dt> <dd>
<p>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>.</p>
<p>With a patch name, this applies patches until the desired patch is on top.</p>
<p><code>hg qpush -a</code> applies them all.</p>
</dd> <dt><code>hg qdelete <var>patchname</var></code> </dt> <dd>
<p>Throw an unapplied patch away. This removes the patch from your <code>.hg/patches</code> directory (and from MQ's oversight generally).</p>
<p>This is surprisingly different than <code>hg qdelete -r</code>, described below.</p>
</dd> <dt><code>hg qrefresh -e</code></dt> <dd>
<p><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.)</p>
</dd> <dt><code>hg qfinish</code> or <code>hg qdelete -r qbase</code></dt> <dd>
<p>"Finish" the bottommost applied patch. It becomes a permanent changeset, suitable for pushing, using the commit message set with <code>qrefresh</code>.</p>
<p>You can only finish patches from the bottom (i.e. you can't finish a patch that's applied over unfinished patches). <code>hg qfinish -a</code> (or <code>hg qdelete -r qbase:qtip</code>) will finish all applied patches. See also <a href="#Reordering_the_queue">#Reordering the queue</a> below.</p>
</dd> <dt><strong>hg qimport </strong><em><strong>filename</strong></em></dt> <dd>
<p>Import a patch into your queue. It is unapplied by default and the <em>filename</em> is the <em>patchname</em>. Useful for testing patches shared on Bugzilla.</p>
</dd> </dl>
<p>Just as important are the commands that show you what's going on:</p>
<dl> <dt><code>hg diff</code></dt> <dt><code>hg status</code></dt> <dd>These show you only uncommitted edits—work that's neither committed nor in an MQ patch. After a <code>qrefresh</code>, they'll both be empty.
<p> </p>
</dd><dt><code>hg qdiff</code> </dt> <dd>
<p>Show what the topmost applied MQ patch looks like, <em>including</em> any uncommitted edits you've made.</p>
<p>Use <strong><code>hg qdiff -U 8</code></strong> to produce patches for review. (Unfortunately <code>qdiff</code> doesn't support <code>-p</code> yet; you can put <code>{{ mediawiki.external('diff') }} showfunc=True</code> in your <code>~/.hgrc</code> file to get that.)</p>
</dd> <dt><code>hg qseries -v</code> </dt> <dd>
<p>List all MQ patches. Applied patches are listed as <code>A</code>, and unapplied patches as <code>U</code>.</p>
</dd> <dt><code>hg qapplied</code> </dt> <dd>
<p>List all the MQ patches that are applied, in queue order (that is, the order they were applied).</p>
</dd> <dt><code>hg log -r qbase:qtip</code> </dt> <dd>
<p>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.)</p>
</dd> <dt><code>hg qunapplied</code> </dt> <dd>
<p>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>).</p>
</dd></dl>
<p>To see more advanced commands, use <strong><code>hg help</code></strong>.</p>
<h3 name="Advanced_Topics">Advanced Topics</h3>
<h4 name="Rebasing_patches">Rebasing patches</h4>
<p><strong>Rebasing for dummies.</strong> When you write a patch, it's based on whatever version of the repo you had when you started working. Of course, changes are constantly being pushed to the central repository, so by the time you want to push, you'll be out of date. Your changes are <em>based on</em> an old revision.</p>
<pre class="eval">       $ <strong>hg glog --template '{node|short} - {author} - {desc|firstline}\n' </strong>
<strong>TIP -&gt;</strong> o  cd9f8db8ee0f - Devin Naquin &lt;<a class=" link-mailto" href="mailto:dnaquin@example.com" rel="freelink">dnaquin@example.com</a>&gt; - Bug 383223
       |
       o  103f04f54b14 - L. David Baron &lt;<a class=" link-mailto" href="mailto:dbaron@example.org" rel="freelink">dbaron@example.org</a>&gt; - Tests for z-ordering of text-decorations.
       |
       o  e3a4c136455b - Robert O'Callahan &lt;<a class=" link-mailto" href="mailto:robert@example.org" rel="freelink">robert@example.org</a>&gt; - Support system proxy settings on OS X, fixi
       |
       o  745e0f997344 - Robert O'Callahan &lt;<a class=" link-mailto" href="mailto:robert@example.org" rel="freelink">robert@example.org</a>&gt; - Support system proxy settings on OS X, fixi
       |
       o  9d80a1461309 - Robert O'Callahan &lt;<a class=" link-mailto" href="mailto:robert@example.org" rel="freelink">robert@example.org</a>&gt; - Support system proxy settings on OS X, fixi
       |
       o  4721deb1dd19 - Diane Trout &lt;<a class=" link-mailto" href="mailto:diane@example.org" rel="freelink">diane@example.org</a>&gt;, James Bunton &lt;<a class=" link-mailto" href="mailto:jamesbunton@example.fm" rel="freelink">jamesbunton@example.fm</a>&gt; - Support syst
       |
       o  3e166c19d130 - Michael Ventnor &lt;<a class=" link-mailto" href="mailto:ventnor.bugzilla@example.com.au" rel="freelink">ventnor.bugzilla@example.com.au</a>&gt; - text-shadow tests (bug 10713)
       |
       o  c06307605f98 - Michael Ventnor &lt;<a class=" link-mailto" href="mailto:ventnor.bugzilla@example.com.au" rel="freelink">ventnor.bugzilla@example.com.au</a>&gt; - Implement text-shadow rendering.
       |
<strong>YOU ----&gt;</strong>@  d243d3af29ed - Jason Orendorff &lt;<a class=" link-mailto" href="mailto:jorendorff@example.com" rel="freelink">jorendorff@example.com</a>&gt; - [mq] Implement trebled fromps.
       |/
       o  1df6e4240511 - Shawn Wilsher &lt;<a class=" link-mailto" href="mailto:sdwilsh@example.com" rel="freelink">sdwilsh@example.com</a>&gt; - Bug 429987
       |
       .
       .
       . (the past)
</pre>
<p>You have two choices:</p>
<ul> <li>Go ahead and finish your patch now, then <code>hg merge</code> with the tip; or</li> <li><em>Rebase</em> your patch before you finish and push it.</li>
</ul>
<p>Rebasing is considered the polite thing. Merging leaves a merge changeset in the history.</p>
<p>It's best not to <code>hg pull</code> while you have patches applied. The most foolproof way to pull and update is:</p>
<pre class="eval">$ <strong>hg qpop -a</strong>             <em># Unapply all patches</em>
$ <strong>hg pull</strong>
$ <strong>hg update</strong>
$ <strong>hg qpush <var>patchname</var></strong>     <em># Reapply patches -- watch out for rejects!</em>
</pre>
<p>Warning: Rebasing across changesets that touch the same files as your patches can cause conflicts when you push! If this happens, <code>hg qpush</code> will tell you, and it will leave <code>.rej</code> files in your working directory. To avoid losing work, you must manually apply these rejected changes, then <code>hg qrefresh</code>.</p>
<p><strong>Rebasing for smarties.</strong> If you're used to Mercurial and MQ and you dislike <code>.rej</code> files, you might want to consider <a class="external" href="http://www.selenic.com/mercurial/wiki/index.cgi/MqMerge">MqMerge</a>. This technique lets you rebase using your merge program, but it's a bit complex.</p>
<p><strong>"Rebasing for smarties" for dummies.</strong> <code>hg pull --rebase</code> will pull changesets from hg.mozilla.org and rebase your patches on top of them, allowing you to deal with conflicts with a merge program instead of <code>.rej</code> files. See <a class="external" href="http://www.selenic.com/mercurial/wiki/index.cgi/RebaseExtension" title="http://www.selenic.com/mercurial/wiki/index.cgi/RebaseExtension">RebaseExtension</a> and <a class="external" href="http://www.selenic.com/mercurial/wiki/RebaseProject" title="http://www.selenic.com/mercurial/wiki/RebaseProject">RebaseProject</a> for more.</p>
<div class="note">As of Mercurial 1.1, rebasing using <code>hg rebase</code> or <code>hg pull --rebase </code>might lose rename data; this is a <a class="external" href="http://www.selenic.com/mercurial/bts/issue1423" rel="external
nofollow" target="_blank" title="http://www.selenic.com/mercurial/bts/issue1423">known bug</a>.</div><h4 name="Reordering_the_queue">Reordering the queue</h4>
<p>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.</p>
<p>The easiest way to fix this is:</p>
<pre class="eval">$ <strong>hg qpop -a</strong>                   <em># Unapply all patches</em>
$ <strong>$EDITOR .hg/patches/series</strong>   <em># Rearrange the lines of the series file</em>
$ <strong>hg qpush <var>patchname</var></strong>           <em># Reapply patches -- watch out for rejects!</em>
</pre>
<p>Warning: Reordering patches that touch the same file can cause conflicts when you push! If this happens, <code>hg qpush</code> will tell you, and it will leave <code>.rej</code> files in your working directory. To avoid losing work, you must manually apply these rejected changes, then <code>hg qrefresh</code>.</p>
<h4 name="Wanted">Wanted</h4>
<ul> <li>Using MQ to thaw/edit/refreeze history</li> <li>Sharing patch repos</li> <li>guards, maybe</li> <li>multiple queues, maybe</li>
</ul>
<p> </p>
Revert to this revision