hgbook

annotate en/ch13-mq-collab.xml @ 648:e0ac2341a861

Fix building error introduced by bos at rev 8366882f67f2
author Dongsheng Song <dongsheng.song@gmail.com>
date Wed Mar 18 21:50:57 2009 +0800 (2009-03-18)
parents cfdb601a3c8b 8366882f67f2
children
rev   line source
bos@559 1 <!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->
bos@559 2
dongsheng@625 3 <chapter id="chap.mq-collab">
bos@572 4 <?dbhtml filename="advanced-uses-of-mercurial-queues.html"?>
bos@559 5 <title>Advanced uses of Mercurial Queues</title>
bos@559 6
bos@559 7 <para>While it's easy to pick up straightforward uses of Mercurial
bos@559 8 Queues, use of a little discipline and some of MQ's less
bos@559 9 frequently used capabilities makes it possible to work in
bos@559 10 complicated development environments.</para>
bos@559 11
bos@559 12 <para>In this chapter, I will use as an example a technique I have
bos@559 13 used to manage the development of an Infiniband device driver for
bos@559 14 the Linux kernel. The driver in question is large (at least as
bos@559 15 drivers go), with 25,000 lines of code spread across 35 source
bos@559 16 files. It is maintained by a small team of developers.</para>
bos@559 17
bos@559 18 <para>While much of the material in this chapter is specific to
bos@559 19 Linux, the same principles apply to any code base for which you're
bos@559 20 not the primary owner, and upon which you need to do a lot of
bos@559 21 development.</para>
bos@559 22
bos@559 23 <sect1>
bos@559 24 <title>The problem of many targets</title>
bos@559 25
bos@559 26 <para>The Linux kernel changes rapidly, and has never been
bos@559 27 internally stable; developers frequently make drastic changes
bos@559 28 between releases. This means that a version of the driver that
bos@559 29 works well with a particular released version of the kernel will
bos@559 30 not even <emphasis>compile</emphasis> correctly against,
bos@559 31 typically, any other version.</para>
bos@559 32
bos@559 33 <para>To maintain a driver, we have to keep a number of distinct
bos@559 34 versions of Linux in mind.</para>
bos@559 35 <itemizedlist>
bos@559 36 <listitem><para>One target is the main Linux kernel development
bos@559 37 tree. Maintenance of the code is in this case partly shared
bos@559 38 by other developers in the kernel community, who make
bos@559 39 <quote>drive-by</quote> modifications to the driver as they
bos@559 40 develop and refine kernel subsystems.</para>
bos@559 41 </listitem>
bos@559 42 <listitem><para>We also maintain a number of
bos@559 43 <quote>backports</quote> to older versions of the Linux
bos@559 44 kernel, to support the needs of customers who are running
bos@559 45 older Linux distributions that do not incorporate our
bos@559 46 drivers. (To <emphasis>backport</emphasis> a piece of code
bos@559 47 is to modify it to work in an older version of its target
bos@559 48 environment than the version it was developed for.)</para>
bos@559 49 </listitem>
bos@559 50 <listitem><para>Finally, we make software releases on a schedule
bos@559 51 that is necessarily not aligned with those used by Linux
bos@559 52 distributors and kernel developers, so that we can deliver
bos@559 53 new features to customers without forcing them to upgrade
bos@559 54 their entire kernels or distributions.</para>
bos@559 55 </listitem></itemizedlist>
bos@559 56
bos@559 57 <sect2>
bos@559 58 <title>Tempting approaches that don't work well</title>
bos@559 59
bos@559 60 <para>There are two <quote>standard</quote> ways to maintain a
bos@559 61 piece of software that has to target many different
bos@559 62 environments.</para>
bos@559 63
bos@559 64 <para>The first is to maintain a number of branches, each
bos@559 65 intended for a single target. The trouble with this approach
bos@559 66 is that you must maintain iron discipline in the flow of
bos@559 67 changes between repositories. A new feature or bug fix must
bos@559 68 start life in a <quote>pristine</quote> repository, then
bos@559 69 percolate out to every backport repository. Backport changes
bos@559 70 are more limited in the branches they should propagate to; a
bos@559 71 backport change that is applied to a branch where it doesn't
bos@559 72 belong will probably stop the driver from compiling.</para>
bos@559 73
bos@559 74 <para>The second is to maintain a single source tree filled with
bos@559 75 conditional statements that turn chunks of code on or off
bos@559 76 depending on the intended target. Because these
bos@559 77 <quote>ifdefs</quote> are not allowed in the Linux kernel
bos@559 78 tree, a manual or automatic process must be followed to strip
bos@559 79 them out and yield a clean tree. A code base maintained in
bos@559 80 this fashion rapidly becomes a rat's nest of conditional
bos@559 81 blocks that are difficult to understand and maintain.</para>
bos@559 82
bos@559 83 <para>Neither of these approaches is well suited to a situation
bos@559 84 where you don't <quote>own</quote> the canonical copy of a
bos@559 85 source tree. In the case of a Linux driver that is
bos@559 86 distributed with the standard kernel, Linus's tree contains
bos@559 87 the copy of the code that will be treated by the world as
bos@559 88 canonical. The upstream version of <quote>my</quote> driver
bos@559 89 can be modified by people I don't know, without me even
bos@559 90 finding out about it until after the changes show up in
bos@559 91 Linus's tree.</para>
bos@559 92
bos@559 93 <para>These approaches have the added weakness of making it
bos@559 94 difficult to generate well-formed patches to submit
bos@559 95 upstream.</para>
bos@559 96
bos@559 97 <para>In principle, Mercurial Queues seems like a good candidate
bos@559 98 to manage a development scenario such as the above. While
bos@559 99 this is indeed the case, MQ contains a few added features that
bos@559 100 make the job more pleasant.</para>
bos@559 101
bos@559 102 </sect2>
bos@559 103 </sect1>
bos@559 104 <sect1>
bos@559 105 <title>Conditionally applying patches with guards</title>
bos@559 106
bos@559 107 <para>Perhaps the best way to maintain sanity with so many targets
bos@559 108 is to be able to choose specific patches to apply for a given
bos@559 109 situation. MQ provides a feature called <quote>guards</quote>
bos@559 110 (which originates with quilt's <literal>guards</literal>
bos@559 111 command) that does just this. To start off, let's create a
bos@567 112 simple repository for experimenting in.</para>
bos@567 113
bos@567 114 &interaction.mq.guards.init;
bos@567 115
bos@567 116 <para>This gives us a tiny repository that contains two patches
bos@567 117 that don't have any dependencies on each other, because they
bos@567 118 touch different files.</para>
bos@559 119
bos@559 120 <para>The idea behind conditional application is that you can
bos@559 121 <quote>tag</quote> a patch with a <emphasis>guard</emphasis>,
bos@559 122 which is simply a text string of your choosing, then tell MQ to
bos@559 123 select specific guards to use when applying patches. MQ will
bos@559 124 then either apply, or skip over, a guarded patch, depending on
bos@559 125 the guards that you have selected.</para>
bos@559 126
bos@559 127 <para>A patch can have an arbitrary number of guards; each one is
bos@559 128 <emphasis>positive</emphasis> (<quote>apply this patch if this
bos@559 129 guard is selected</quote>) or <emphasis>negative</emphasis>
bos@559 130 (<quote>skip this patch if this guard is selected</quote>). A
bos@559 131 patch with no guards is always applied.</para>
bos@559 132
bos@559 133 </sect1>
bos@559 134 <sect1>
bos@559 135 <title>Controlling the guards on a patch</title>
bos@559 136
bos@559 137 <para>The <command role="hg-ext-mq">qguard</command> command lets
bos@559 138 you determine which guards should apply to a patch, or display
bos@559 139 the guards that are already in effect. Without any arguments, it
bos@567 140 displays the guards on the current topmost patch.</para>
bos@567 141
bos@567 142 &interaction.mq.guards.qguard;
bos@567 143
bos@567 144 <para>To set a positive guard on a patch, prefix the name of the
bos@567 145 guard with a <quote><literal>+</literal></quote>.</para>
bos@567 146
bos@567 147 &interaction.mq.guards.qguard.pos;
bos@567 148
bos@567 149 <para>To set a negative guard
bos@559 150 on a patch, prefix the name of the guard with a
bos@567 151 <quote><literal>-</literal></quote>.</para>
bos@567 152
bos@567 153 &interaction.mq.guards.qguard.neg;
bos@559 154
bos@559 155 <note>
bos@559 156 <para> The <command role="hg-ext-mq">qguard</command> command
bos@559 157 <emphasis>sets</emphasis> the guards on a patch; it doesn't
bos@559 158 <emphasis>modify</emphasis> them. What this means is that if
bos@559 159 you run <command role="hg-cmd">hg qguard +a +b</command> on a
bos@559 160 patch, then <command role="hg-cmd">hg qguard +c</command> on
bos@559 161 the same patch, the <emphasis>only</emphasis> guard that will
bos@559 162 be set on it afterwards is <literal>+c</literal>.</para>
bos@559 163 </note>
bos@559 164
bos@559 165 <para>Mercurial stores guards in the <filename
bos@559 166 role="special">series</filename> file; the form in which they
bos@559 167 are stored is easy both to understand and to edit by hand. (In
bos@559 168 other words, you don't have to use the <command
bos@559 169 role="hg-ext-mq">qguard</command> command if you don't want
bos@559 170 to; it's okay to simply edit the <filename
bos@567 171 role="special">series</filename> file.)</para>
bos@567 172
bos@567 173 &interaction.mq.guards.series;
bos@559 174
bos@559 175 </sect1>
bos@559 176 <sect1>
bos@559 177 <title>Selecting the guards to use</title>
bos@559 178
bos@559 179 <para>The <command role="hg-ext-mq">qselect</command> command
bos@559 180 determines which guards are active at a given time. The effect
bos@559 181 of this is to determine which patches MQ will apply the next
bos@559 182 time you run <command role="hg-ext-mq">qpush</command>. It has
bos@559 183 no other effect; in particular, it doesn't do anything to
bos@559 184 patches that are already applied.</para>
bos@559 185
bos@559 186 <para>With no arguments, the <command
bos@559 187 role="hg-ext-mq">qselect</command> command lists the guards
bos@559 188 currently in effect, one per line of output. Each argument is
bos@567 189 treated as the name of a guard to apply.</para>
bos@567 190
bos@567 191 &interaction.mq.guards.qselect.foo;
bos@567 192
bos@567 193 <para>In case you're interested, the currently selected guards are
bos@567 194 stored in the <filename role="special">guards</filename> file.</para>
bos@567 195
bos@567 196 &interaction.mq.guards.qselect.cat;
bos@567 197
bos@567 198 <para>We can see the effect the selected guards have when we run
bos@567 199 <command role="hg-ext-mq">qpush</command>.</para>
bos@567 200
bos@567 201 &interaction.mq.guards.qselect.qpush;
bos@559 202
bos@559 203 <para>A guard cannot start with a
bos@559 204 <quote><literal>+</literal></quote> or
bos@559 205 <quote><literal>-</literal></quote> character. The name of a
bos@559 206 guard must not contain white space, but most other characters
bos@559 207 are acceptable. If you try to use a guard with an invalid name,
bos@567 208 MQ will complain:</para>
bos@567 209
bos@567 210 &interaction.mq.guards.qselect.error;
bos@567 211
bos@567 212 <para>Changing the selected guards changes the patches that are
bos@567 213 applied.</para>
bos@567 214
bos@567 215 &interaction.mq.guards.qselect.quux;
bos@567 216
bos@567 217 <para>You can see in the example below that negative guards take
bos@567 218 precedence over positive guards.</para>
bos@567 219
bos@567 220 &interaction.mq.guards.qselect.foobar;
bos@559 221
bos@559 222 </sect1>
bos@559 223 <sect1>
bos@559 224 <title>MQ's rules for applying patches</title>
bos@559 225
bos@559 226 <para>The rules that MQ uses when deciding whether to apply a
bos@559 227 patch are as follows.</para>
bos@559 228 <itemizedlist>
bos@559 229 <listitem><para>A patch that has no guards is always
bos@559 230 applied.</para>
bos@559 231 </listitem>
bos@559 232 <listitem><para>If the patch has any negative guard that matches
bos@559 233 any currently selected guard, the patch is skipped.</para>
bos@559 234 </listitem>
bos@559 235 <listitem><para>If the patch has any positive guard that matches
bos@559 236 any currently selected guard, the patch is applied.</para>
bos@559 237 </listitem>
bos@559 238 <listitem><para>If the patch has positive or negative guards,
bos@559 239 but none matches any currently selected guard, the patch is
bos@559 240 skipped.</para>
bos@559 241 </listitem></itemizedlist>
bos@559 242
bos@559 243 </sect1>
bos@559 244 <sect1>
bos@559 245 <title>Trimming the work environment</title>
bos@559 246
bos@559 247 <para>In working on the device driver I mentioned earlier, I don't
bos@559 248 apply the patches to a normal Linux kernel tree. Instead, I use
bos@559 249 a repository that contains only a snapshot of the source files
bos@559 250 and headers that are relevant to Infiniband development. This
bos@559 251 repository is 1% the size of a kernel repository, so it's easier
bos@559 252 to work with.</para>
bos@559 253
bos@559 254 <para>I then choose a <quote>base</quote> version on top of which
bos@559 255 the patches are applied. This is a snapshot of the Linux kernel
bos@559 256 tree as of a revision of my choosing. When I take the snapshot,
bos@559 257 I record the changeset ID from the kernel repository in the
bos@559 258 commit message. Since the snapshot preserves the
bos@559 259 <quote>shape</quote> and content of the relevant parts of the
bos@559 260 kernel tree, I can apply my patches on top of either my tiny
bos@559 261 repository or a normal kernel tree.</para>
bos@559 262
bos@559 263 <para>Normally, the base tree atop which the patches apply should
bos@559 264 be a snapshot of a very recent upstream tree. This best
bos@559 265 facilitates the development of patches that can easily be
bos@559 266 submitted upstream with few or no modifications.</para>
bos@559 267
bos@559 268 </sect1>
bos@559 269 <sect1>
bos@559 270 <title>Dividing up the <filename role="special">series</filename>
bos@559 271 file</title>
bos@559 272
bos@559 273 <para>I categorise the patches in the <filename
bos@559 274 role="special">series</filename> file into a number of logical
bos@559 275 groups. Each section of like patches begins with a block of
bos@559 276 comments that describes the purpose of the patches that
bos@559 277 follow.</para>
bos@559 278
bos@559 279 <para>The sequence of patch groups that I maintain follows. The
bos@559 280 ordering of these groups is important; I'll describe why after I
bos@559 281 introduce the groups.</para>
bos@559 282 <itemizedlist>
bos@559 283 <listitem><para>The <quote>accepted</quote> group. Patches that
bos@559 284 the development team has submitted to the maintainer of the
bos@559 285 Infiniband subsystem, and which he has accepted, but which
bos@559 286 are not present in the snapshot that the tiny repository is
bos@559 287 based on. These are <quote>read only</quote> patches,
bos@559 288 present only to transform the tree into a similar state as
bos@559 289 it is in the upstream maintainer's repository.</para>
bos@559 290 </listitem>
bos@559 291 <listitem><para>The <quote>rework</quote> group. Patches that I
bos@559 292 have submitted, but that the upstream maintainer has
bos@559 293 requested modifications to before he will accept
bos@559 294 them.</para>
bos@559 295 </listitem>
bos@559 296 <listitem><para>The <quote>pending</quote> group. Patches that
bos@559 297 I have not yet submitted to the upstream maintainer, but
bos@559 298 which we have finished working on. These will be <quote>read
bos@559 299 only</quote> for a while. If the upstream maintainer
bos@559 300 accepts them upon submission, I'll move them to the end of
bos@559 301 the <quote>accepted</quote> group. If he requests that I
bos@559 302 modify any, I'll move them to the beginning of the
bos@559 303 <quote>rework</quote> group.</para>
bos@559 304 </listitem>
bos@559 305 <listitem><para>The <quote>in progress</quote> group. Patches
bos@559 306 that are actively being developed, and should not be
bos@559 307 submitted anywhere yet.</para>
bos@559 308 </listitem>
bos@559 309 <listitem><para>The <quote>backport</quote> group. Patches that
bos@559 310 adapt the source tree to older versions of the kernel
bos@559 311 tree.</para>
bos@559 312 </listitem>
bos@559 313 <listitem><para>The <quote>do not ship</quote> group. Patches
bos@559 314 that for some reason should never be submitted upstream.
bos@559 315 For example, one such patch might change embedded driver
bos@559 316 identification strings to make it easier to distinguish, in
bos@559 317 the field, between an out-of-tree version of the driver and
bos@559 318 a version shipped by a distribution vendor.</para>
bos@559 319 </listitem></itemizedlist>
bos@559 320
bos@559 321 <para>Now to return to the reasons for ordering groups of patches
bos@559 322 in this way. We would like the lowest patches in the stack to
bos@559 323 be as stable as possible, so that we will not need to rework
bos@559 324 higher patches due to changes in context. Putting patches that
bos@559 325 will never be changed first in the <filename
bos@559 326 role="special">series</filename> file serves this
bos@559 327 purpose.</para>
bos@559 328
bos@559 329 <para>We would also like the patches that we know we'll need to
bos@559 330 modify to be applied on top of a source tree that resembles the
bos@559 331 upstream tree as closely as possible. This is why we keep
bos@559 332 accepted patches around for a while.</para>
bos@559 333
bos@559 334 <para>The <quote>backport</quote> and <quote>do not ship</quote>
bos@559 335 patches float at the end of the <filename
bos@559 336 role="special">series</filename> file. The backport patches
bos@559 337 must be applied on top of all other patches, and the <quote>do
bos@559 338 not ship</quote> patches might as well stay out of harm's
bos@559 339 way.</para>
bos@559 340
bos@559 341 </sect1>
bos@559 342 <sect1>
bos@559 343 <title>Maintaining the patch series</title>
bos@559 344
bos@559 345 <para>In my work, I use a number of guards to control which
bos@559 346 patches are to be applied.</para>
bos@559 347
bos@559 348 <itemizedlist>
bos@559 349 <listitem><para><quote>Accepted</quote> patches are guarded with
bos@559 350 <literal>accepted</literal>. I enable this guard most of
bos@559 351 the time. When I'm applying the patches on top of a tree
bos@559 352 where the patches are already present, I can turn this patch
bos@559 353 off, and the patches that follow it will apply
bos@559 354 cleanly.</para>
bos@559 355 </listitem>
bos@559 356 <listitem><para>Patches that are <quote>finished</quote>, but
bos@559 357 not yet submitted, have no guards. If I'm applying the
bos@559 358 patch stack to a copy of the upstream tree, I don't need to
bos@559 359 enable any guards in order to get a reasonably safe source
bos@559 360 tree.</para>
bos@559 361 </listitem>
bos@559 362 <listitem><para>Those patches that need reworking before being
bos@559 363 resubmitted are guarded with
bos@559 364 <literal>rework</literal>.</para>
bos@559 365 </listitem>
bos@559 366 <listitem><para>For those patches that are still under
bos@559 367 development, I use <literal>devel</literal>.</para>
bos@559 368 </listitem>
bos@559 369 <listitem><para>A backport patch may have several guards, one
bos@559 370 for each version of the kernel to which it applies. For
bos@559 371 example, a patch that backports a piece of code to 2.6.9
bos@559 372 will have a <literal>2.6.9</literal> guard.</para>
bos@559 373 </listitem></itemizedlist>
bos@559 374 <para>This variety of guards gives me considerable flexibility in
bos@559 375 determining what kind of source tree I want to end up with. For
bos@559 376 most situations, the selection of appropriate guards is
bos@559 377 automated during the build process, but I can manually tune the
bos@559 378 guards to use for less common circumstances.</para>
bos@559 379
bos@559 380 <sect2>
bos@559 381 <title>The art of writing backport patches</title>
bos@559 382
bos@559 383 <para>Using MQ, writing a backport patch is a simple process.
bos@559 384 All such a patch has to do is modify a piece of code that uses
bos@559 385 a kernel feature not present in the older version of the
bos@559 386 kernel, so that the driver continues to work correctly under
bos@559 387 that older version.</para>
bos@559 388
bos@559 389 <para>A useful goal when writing a good backport patch is to
bos@559 390 make your code look as if it was written for the older version
bos@559 391 of the kernel you're targeting. The less obtrusive the patch,
bos@559 392 the easier it will be to understand and maintain. If you're
bos@559 393 writing a collection of backport patches to avoid the
bos@559 394 <quote>rat's nest</quote> effect of lots of
bos@559 395 <literal>#ifdef</literal>s (hunks of source code that are only
bos@559 396 used conditionally) in your code, don't introduce
bos@559 397 version-dependent <literal>#ifdef</literal>s into the patches.
bos@559 398 Instead, write several patches, each of which makes
bos@559 399 unconditional changes, and control their application using
bos@559 400 guards.</para>
bos@559 401
bos@559 402 <para>There are two reasons to divide backport patches into a
bos@559 403 distinct group, away from the <quote>regular</quote> patches
bos@559 404 whose effects they modify. The first is that intermingling the
bos@559 405 two makes it more difficult to use a tool like the <literal
bos@559 406 role="hg-ext">patchbomb</literal> extension to automate the
bos@559 407 process of submitting the patches to an upstream maintainer.
bos@559 408 The second is that a backport patch could perturb the context
bos@559 409 in which a subsequent regular patch is applied, making it
bos@559 410 impossible to apply the regular patch cleanly
bos@559 411 <emphasis>without</emphasis> the earlier backport patch
bos@559 412 already being applied.</para>
bos@559 413
bos@559 414 </sect2>
bos@559 415 </sect1>
bos@559 416 <sect1>
bos@559 417 <title>Useful tips for developing with MQ</title>
bos@559 418
bos@559 419 <sect2>
bos@559 420 <title>Organising patches in directories</title>
bos@559 421
bos@559 422 <para>If you're working on a substantial project with MQ, it's
bos@559 423 not difficult to accumulate a large number of patches. For
bos@559 424 example, I have one patch repository that contains over 250
bos@559 425 patches.</para>
bos@559 426
bos@559 427 <para>If you can group these patches into separate logical
bos@559 428 categories, you can if you like store them in different
bos@559 429 directories; MQ has no problems with patch names that contain
bos@559 430 path separators.</para>
bos@559 431
bos@559 432 </sect2>
dongsheng@625 433 <sect2 id="mq-collab.tips.interdiff">
bos@559 434 <title>Viewing the history of a patch</title>
bos@559 435
bos@559 436 <para>If you're developing a set of patches over a long time,
bos@559 437 it's a good idea to maintain them in a repository, as
dongsheng@625 438 discussed in section <xref linkend="sec.mq.repo"/>. If you do
bos@559 439 so, you'll quickly
bos@559 440 discover that using the <command role="hg-cmd">hg
bos@559 441 diff</command> command to look at the history of changes to
bos@559 442 a patch is unworkable. This is in part because you're looking
bos@559 443 at the second derivative of the real code (a diff of a diff),
bos@559 444 but also because MQ adds noise to the process by modifying
bos@559 445 time stamps and directory names when it updates a
bos@559 446 patch.</para>
bos@559 447
bos@559 448 <para>However, you can use the <literal
bos@559 449 role="hg-ext">extdiff</literal> extension, which is bundled
bos@559 450 with Mercurial, to turn a diff of two versions of a patch into
bos@559 451 something readable. To do this, you will need a third-party
bos@559 452 package called <literal role="package">patchutils</literal>
bos@559 453 <citation>web:patchutils</citation>. This provides a command
bos@559 454 named <command>interdiff</command>, which shows the
bos@559 455 differences between two diffs as a diff. Used on two versions
bos@559 456 of the same diff, it generates a diff that represents the diff
bos@559 457 from the first to the second version.</para>
bos@559 458
bos@559 459 <para>You can enable the <literal
bos@559 460 role="hg-ext">extdiff</literal> extension in the usual way,
bos@559 461 by adding a line to the <literal
bos@559 462 role="rc-extensions">extensions</literal> section of your
bos@580 463 <filename role="special">~/.hgrc</filename>.</para>
bos@580 464 <programlisting>[extensions]
bos@580 465 extdiff =</programlisting>
bos@559 466 <para>The <command>interdiff</command> command expects to be
bos@559 467 passed the names of two files, but the <literal
bos@559 468 role="hg-ext">extdiff</literal> extension passes the program
bos@559 469 it runs a pair of directories, each of which can contain an
bos@559 470 arbitrary number of files. We thus need a small program that
bos@559 471 will run <command>interdiff</command> on each pair of files in
bos@559 472 these two directories. This program is available as <filename
bos@559 473 role="special">hg-interdiff</filename> in the <filename
bos@559 474 class="directory">examples</filename> directory of the
bos@559 475 source code repository that accompanies this book. <!--
bos@559 476 &example.hg-interdiff; --></para>
bos@559 477
bos@559 478 <para>With the <filename role="special">hg-interdiff</filename>
bos@559 479 program in your shell's search path, you can run it as
bos@559 480 follows, from inside an MQ patch directory:</para>
bos@580 481 <programlisting>hg extdiff -p hg-interdiff -r A:B my-change.patch</programlisting>
bos@559 482 <para>Since you'll probably want to use this long-winded command
bos@559 483 a lot, you can get <literal role="hg-ext">hgext</literal> to
bos@559 484 make it available as a normal Mercurial command, again by
bos@580 485 editing your <filename
bos@580 486 role="special">~/.hgrc</filename>.</para>
bos@580 487 <programlisting>[extdiff]
bos@580 488 cmd.interdiff = hg-interdiff</programlisting>
bos@559 489 <para>This directs <literal role="hg-ext">hgext</literal> to
bos@559 490 make an <literal>interdiff</literal> command available, so you
bos@559 491 can now shorten the previous invocation of <command
bos@559 492 role="hg-ext-extdiff">extdiff</command> to something a
bos@559 493 little more wieldy.</para>
bos@580 494 <programlisting>hg interdiff -r A:B my-change.patch</programlisting>
bos@559 495
bos@559 496 <note>
bos@559 497 <para> The <command>interdiff</command> command works well
bos@559 498 only if the underlying files against which versions of a
bos@559 499 patch are generated remain the same. If you create a patch,
bos@559 500 modify the underlying files, and then regenerate the patch,
bos@559 501 <command>interdiff</command> may not produce useful
bos@559 502 output.</para>
bos@559 503 </note>
bos@559 504
bos@559 505 <para>The <literal role="hg-ext">extdiff</literal> extension is
bos@559 506 useful for more than merely improving the presentation of MQ
bos@559 507 patches. To read more about it, go to section <xref
dongsheng@625 508 linkend="sec.hgext.extdiff"/>.</para>
bos@559 509
bos@559 510 </sect2>
bos@559 511 </sect1>
bos@559 512 </chapter>
bos@559 513
bos@559 514 <!--
bos@559 515 local variables:
bos@559 516 sgml-parent-document: ("00book.xml" "book" "chapter")
bos@559 517 end:
bos@559 518 -->