Getting started with Mercurial Queues
Because MQ is implemented as an extension, you must explicitly enable before you can use it. (You don’t need to download anything; MQ ships with the standard Mercurial distribution.) To enable MQ, edit your ~/.hgrc file, and add the lines in figure 12.5 .
1
[extensions]
2 hgext.mq =
|
Once the extension is enabled, it will make a number of new commands available. To verify that the extension is working, you can use “hg help” to see if the “hg qinit” command is now available; see the example in figure 12.3 .
1
$
hg
help
qinit
2 hg qinit [-c] 3 4 init a new queue repository 5 6 The queue repository is unversioned by default. If -c is 7 specified, qinit will create a separate nested repository 8 for patches. Use qcommit to commit changes to this queue 9 repository. 10 11 options: 12 13 -c --create-repo create queue repository 14 15 use "hg -v help qinit" to show global options
|
You can use MQ with any Mercurial repository, and its commands only operate within that repository. To get started, simply prepare the repository using the “hg qinit” command (see figure 12.4 ). This command creates an empty directory called .hg/patches, where MQ will keep its metadata. As with many Mercurial commands, the “hg qinit” command prints nothing if it succeeds.
1
$
hg
init
mq-sandbox
2 $ cd mq-sandbox 3 $ echo 'line 1' > file1 4 $ echo 'another line 1' > file2 5 $ hg add file1 file2 6 $ hg commit -m'first change' 7 $ hg qinit
|
1
$
hg
tip
2 changeset: 0:93d314596e46 3 tag: tip 4 user: Bryan O'Sullivan <bos@serpentine.com> 5 date: Sun Jun 17 18:03:56 2007 +0000 6 summary: first change 7 8 $ hg qnew first.patch 9 $ hg tip 10 changeset: 1:42507102e3aa 11 tag: qtip 12 tag: first.patch 13 tag: tip 14 tag: qbase 15 user: Bryan O'Sullivan <bos@serpentine.com> 16 date: Sun Jun 17 18:03:56 2007 +0000 17 summary: New patch: first.patch 18 19 $ ls .hg/patches 20 first.patch series status
|
12.5.1 Creating a new patch
To begin work on a new patch, use the “hg qnew” command. This command takes one argument, the name of the patch to create. MQ will use this as the name of an actual file in the .hg/patches directory, as you can see in figure 12.5 .
Also newly present in the .hg/patches directory are two other files, series and status. The series file lists all of the patches that MQ knows about for this repository, with one patch per line. Mercurial uses the status file for internal book-keeping; it tracks all of the patches that MQ has applied in this repository.
Once you have created your new patch, you can edit files in the working directory as you usually would. All of the normal Mercurial commands, such as “hg diff” and “hg annotate”, work exactly as they did before.
12.5.2 Refreshing a patch
When you reach a point where you want to save your work, use the “hg qrefresh” command (figure 12.5 ) to update the patch you are working on. This command folds the changes you have made in the working directory into your patch, and updates its corresponding changeset to contain those changes.
1
$
echo
'line
2'
>>
file1
2 $ hg diff 3 diff -r 42507102e3aa file1 4 --- a/file1 Sun Jun 17 18:03:56 2007 +0000 5 +++ b/file1 Sun Jun 17 18:03:56 2007 +0000 6 @@ -1,1 +1,2 @@ line 1 7 line 1 8 +line 2 9 $ hg qrefresh 10 $ hg diff 11 $ hg tip --style=compact --patch 12 1[qtip,first.patch,tip,qbase] 78bfae8e7765 2007-06-17 18:03 +0000 bos 13 patch queue: first.patch 14 15 diff -r 93d314596e46 -r 78bfae8e7765 file1 16 --- a/file1 Sun Jun 17 18:03:56 2007 +0000 17 +++ b/file1 Sun Jun 17 18:03:57 2007 +0000 18 @@ -1,1 +1,2 @@ line 1 19 line 1 20 +line 2 21
|
You can run “hg qrefresh” as often as you like, so it’s a good way to “checkpoint” your work. Refresh your patch at an opportune time; try an experiment; and if the experiment doesn’t work out, “hg revert” your modifications back to the last time you refreshed.
1
$
echo
'line
3'
>>
file1
2 $ hg status 3 M file1 4 $ hg qrefresh 5 $ hg tip --style=compact --patch 6 1[qtip,first.patch,tip,qbase] 403df3ef5ecd 2007-06-17 18:03 +0000 bos 7 patch queue: first.patch 8 9 diff -r 93d314596e46 -r 403df3ef5ecd file1 10 --- a/file1 Sun Jun 17 18:03:56 2007 +0000 11 +++ b/file1 Sun Jun 17 18:03:57 2007 +0000 12 @@ -1,1 +1,3 @@ line 1 13 line 1 14 +line 2 15 +line 3 16
|
12.5.3 Stacking and tracking patches
Once you have finished working on a patch, or need to work on another, you can use the “hg qnew” command again to create a new patch. Mercurial will apply this patch on top of your existing patch. See figure 12.8 for an example. Notice that the patch contains the changes in our prior patch as part of its context (you can see this more clearly in the output of “hg annotate”).
1
$
hg
qnew
second.patch
2 $ hg log --style=compact --limit=2 3 2[qtip,second.patch,tip] 554fbb07f820 2007-06-17 18:03 +0000 bos 4 New patch: second.patch 5 6 1[first.patch,qbase] 403df3ef5ecd 2007-06-17 18:03 +0000 bos 7 patch queue: first.patch 8 9 $ echo 'line 4' >> file1 10 $ hg qrefresh 11 $ hg tip --style=compact --patch 12 2[qtip,second.patch,tip] 86100a6142b9 2007-06-17 18:03 +0000 bos 13 patch queue: second.patch 14 15 diff -r 403df3ef5ecd -r 86100a6142b9 file1 16 --- a/file1 Sun Jun 17 18:03:57 2007 +0000 17 +++ b/file1 Sun Jun 17 18:03:57 2007 +0000 18 @@ -1,3 +1,4 @@ line 1 19 line 1 20 line 2 21 line 3 22 +line 4 23 24 $ hg annotate file1 25 0: line 1 26 1: line 2 27 1: line 3 28 2: line 4
|
So far, with the exception of “hg qnew” and “hg qrefresh”, we’ve been careful to only use regular Mercurial commands. However, MQ provides many commands that are easier to use when you are thinking about patches, as illustrated in figure 12.9 :
- The “hg qseries” command lists every patch that MQ knows about in this repository, from oldest to newest (most recently created).
- The “hg qapplied” command lists every patch that MQ has applied in this repository, again from oldest to newest (most recently applied).
1
$
hg
qseries
2 first.patch 3 second.patch 4 $ hg qapplied 5 first.patch 6 second.patch
|
12.5.4 Manipulating the patch stack
The previous discussion implied that there must be a difference between “known” and “applied” patches, and there is. MQ can manage a patch without it being applied in the repository.
An applied patch has a corresponding changeset in the repository, and the effects of the patch and changeset are visible in the working directory. You can undo the application of a patch using the “hg qpop” command. MQ still knows about, or manages, a popped patch, but the patch no longer has a corresponding changeset in the repository, and the working directory does not contain the changes made by the patch. Figure 12.10 illustrates the difference between applied and tracked patches.
|
You can reapply an unapplied, or popped, patch using the “hg qpush” command. This creates a new changeset to correspond to the patch, and the patch’s changes once again become present in the working directory. See figure 12.11 for examples of “hg qpop” and “hg qpush” in action. Notice that once we have popped a patch or two patches, the output of “hg qseries” remains the same, while that of “hg qapplied” has changed.
1
$
hg
qapplied
2 first.patch 3 second.patch 4 $ hg qpop 5 Now at: first.patch 6 $ hg qseries 7 first.patch 8 second.patch 9 $ hg qapplied 10 first.patch 11 $ cat file1 12 line 1 13 line 2 14 line 3
|
12.5.5 Pushing and popping many patches
While “hg qpush” and “hg qpop” each operate on a single patch at a time by default, you can push and pop many patches in one go. The -a option to “hg qpush” causes it to push all unapplied patches, while the -a option to “hg qpop” causes it to pop all applied patches. (For some more ways to push and pop many patches, see section 12.7 below.)
1
$
hg
qpush
-a
2 applying second.patch 3 Now at: second.patch 4 $ cat file1 5 line 1 6 line 2 7 line 3 8 line 4
|
12.5.6 Safety checks, and overriding them
Several MQ commands check the working directory before they do anything, and fail if they find any modifications. They do this to ensure that you won’t lose any changes that you have made, but not yet incorporated into a patch. Figure 12.13 illustrates this; the “hg qnew” command will not create a new patch if there are outstanding changes, caused in this case by the “hg add” of file3.
1
$
echo
'file
3,
line
1'
>>
file3
2 $ hg qnew add-file3.patch 3 $ hg qnew -f add-file3.patch 4 abort: patch "add-file3.patch" already exists
|
Commands that check the working directory all take an “I know what I’m doing” option, which is always named -f. The exact meaning of -f depends on the command. For example, “hg qnew -f” will incorporate any outstanding changes into the new patch it creates, but “hg qpop -f” will revert modifications to any files affected by the patch that it is popping. Be sure to read the documentation for a command’s -f option before you use it!
12.5.7 Working on several patches at once
The “hg qrefresh” command always refreshes the topmost applied patch. This means that you can suspend work on one patch (by refreshing it), pop or push to make a different patch the top, and work on that patch for a while.
Here’s an example that illustrates how you can use this ability. Let’s say you’re developing a new feature as two patches. The first is a change to the core of your software, and the second—layered on top of the first—changes the user interface to use the code you just added to the core. If you notice a bug in the core while you’re working on the UI patch, it’s easy to fix the core. Simply “hg qrefresh” the UI patch to save your in-progress changes, and “hg qpop” down to the core patch. Fix the core bug, “hg qrefresh” the core patch, and “hg qpush” back to the UI patch to continue where you left off.