使用Mercurial Queues

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  =

Figure 12.2: Contents to add to ~/.hgrc to enable the MQ extension

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

Figure 12.3: How to verify that MQ is enabled

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

Figure 12.4: Preparing a repository for use with MQ


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

Figure 12.5: Creating a new patch

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.

Note: You may sometimes want to edit the series file by hand; for example, to change the sequence in which some patches are applied. However, manually editing the status file is almost always a bad idea, as it’s easy to corrupt MQ’s idea of what is happening.

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    

Figure 12.6: Refreshing a patch

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    

Figure 12.7: Refresh a patch many times to accumulate changes

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

Figure 12.8: Stacking a second patch on top of the first

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

Figure 12.9: Understanding the patch stack with “hg qseries” and “hg qapplied

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.


PIC

Figure 12.10: Applied and unapplied patches in the MQ patch stack

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

Figure 12.11: Modifying the stack of applied patches

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

Figure 12.12: Pushing all unapplied patches

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

Figure 12.13: Forcibly creating a patch

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.

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值