hgbook
diff fr/ch13-mq-collab.xml @ 987:f0110009e946
french translation : sync with original files (en/ch05 to en/ch14 and appD)
author | Frédéric Bouquet <youshe.jaalon@gmail.com> |
---|---|
date | Wed Sep 09 16:07:36 2009 +0200 (2009-09-09) |
parents | en/ch13-mq-collab.xml@5225ec140003 |
children | 6f8c48362758 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/fr/ch13-mq-collab.xml Wed Sep 09 16:07:36 2009 +0200 1.3 @@ -0,0 +1,525 @@ 1.4 +<!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : --> 1.5 + 1.6 +<chapter id="chap:mq-collab"> 1.7 + <?dbhtml filename="advanced-uses-of-mercurial-queues.html"?> 1.8 + <title>Advanced uses of Mercurial Queues</title> 1.9 + 1.10 + <para id="x_15d">While it's easy to pick up straightforward uses of Mercurial 1.11 + Queues, use of a little discipline and some of MQ's less 1.12 + frequently used capabilities makes it possible to work in 1.13 + complicated development environments.</para> 1.14 + 1.15 + <para id="x_15e">In this chapter, I will use as an example a technique I have 1.16 + used to manage the development of an Infiniband device driver for 1.17 + the Linux kernel. The driver in question is large (at least as 1.18 + drivers go), with 25,000 lines of code spread across 35 source 1.19 + files. It is maintained by a small team of developers.</para> 1.20 + 1.21 + <para id="x_15f">While much of the material in this chapter is specific to 1.22 + Linux, the same principles apply to any code base for which you're 1.23 + not the primary owner, and upon which you need to do a lot of 1.24 + development.</para> 1.25 + 1.26 + <sect1> 1.27 + <title>The problem of many targets</title> 1.28 + 1.29 + <para id="x_160">The Linux kernel changes rapidly, and has never been 1.30 + internally stable; developers frequently make drastic changes 1.31 + between releases. This means that a version of the driver that 1.32 + works well with a particular released version of the kernel will 1.33 + not even <emphasis>compile</emphasis> correctly against, 1.34 + typically, any other version.</para> 1.35 + 1.36 + <para id="x_161">To maintain a driver, we have to keep a number of distinct 1.37 + versions of Linux in mind.</para> 1.38 + <itemizedlist> 1.39 + <listitem><para id="x_162">One target is the main Linux kernel development 1.40 + tree. Maintenance of the code is in this case partly shared 1.41 + by other developers in the kernel community, who make 1.42 + <quote>drive-by</quote> modifications to the driver as they 1.43 + develop and refine kernel subsystems.</para> 1.44 + </listitem> 1.45 + <listitem><para id="x_163">We also maintain a number of 1.46 + <quote>backports</quote> to older versions of the Linux 1.47 + kernel, to support the needs of customers who are running 1.48 + older Linux distributions that do not incorporate our 1.49 + drivers. (To <emphasis>backport</emphasis> a piece of code 1.50 + is to modify it to work in an older version of its target 1.51 + environment than the version it was developed for.)</para> 1.52 + </listitem> 1.53 + <listitem><para id="x_164">Finally, we make software releases on a schedule 1.54 + that is necessarily not aligned with those used by Linux 1.55 + distributors and kernel developers, so that we can deliver 1.56 + new features to customers without forcing them to upgrade 1.57 + their entire kernels or distributions.</para> 1.58 + </listitem></itemizedlist> 1.59 + 1.60 + <sect2> 1.61 + <title>Tempting approaches that don't work well</title> 1.62 + 1.63 + <para id="x_165">There are two <quote>standard</quote> ways to maintain a 1.64 + piece of software that has to target many different 1.65 + environments.</para> 1.66 + 1.67 + <para id="x_166">The first is to maintain a number of branches, each 1.68 + intended for a single target. The trouble with this approach 1.69 + is that you must maintain iron discipline in the flow of 1.70 + changes between repositories. A new feature or bug fix must 1.71 + start life in a <quote>pristine</quote> repository, then 1.72 + percolate out to every backport repository. Backport changes 1.73 + are more limited in the branches they should propagate to; a 1.74 + backport change that is applied to a branch where it doesn't 1.75 + belong will probably stop the driver from compiling.</para> 1.76 + 1.77 + <para id="x_167">The second is to maintain a single source tree filled with 1.78 + conditional statements that turn chunks of code on or off 1.79 + depending on the intended target. Because these 1.80 + <quote>ifdefs</quote> are not allowed in the Linux kernel 1.81 + tree, a manual or automatic process must be followed to strip 1.82 + them out and yield a clean tree. A code base maintained in 1.83 + this fashion rapidly becomes a rat's nest of conditional 1.84 + blocks that are difficult to understand and maintain.</para> 1.85 + 1.86 + <para id="x_168">Neither of these approaches is well suited to a situation 1.87 + where you don't <quote>own</quote> the canonical copy of a 1.88 + source tree. In the case of a Linux driver that is 1.89 + distributed with the standard kernel, Linus's tree contains 1.90 + the copy of the code that will be treated by the world as 1.91 + canonical. The upstream version of <quote>my</quote> driver 1.92 + can be modified by people I don't know, without me even 1.93 + finding out about it until after the changes show up in 1.94 + Linus's tree.</para> 1.95 + 1.96 + <para id="x_169">These approaches have the added weakness of making it 1.97 + difficult to generate well-formed patches to submit 1.98 + upstream.</para> 1.99 + 1.100 + <para id="x_16a">In principle, Mercurial Queues seems like a good candidate 1.101 + to manage a development scenario such as the above. While 1.102 + this is indeed the case, MQ contains a few added features that 1.103 + make the job more pleasant.</para> 1.104 + 1.105 + </sect2> 1.106 + </sect1> 1.107 + <sect1> 1.108 + <title>Conditionally applying patches with guards</title> 1.109 + 1.110 + <para id="x_16b">Perhaps the best way to maintain sanity with so many targets 1.111 + is to be able to choose specific patches to apply for a given 1.112 + situation. MQ provides a feature called <quote>guards</quote> 1.113 + (which originates with quilt's <literal>guards</literal> 1.114 + command) that does just this. To start off, let's create a 1.115 + simple repository for experimenting in.</para> 1.116 + 1.117 + &interaction.mq.guards.init; 1.118 + 1.119 + <para id="x_16c">This gives us a tiny repository that contains two patches 1.120 + that don't have any dependencies on each other, because they 1.121 + touch different files.</para> 1.122 + 1.123 + <para id="x_16d">The idea behind conditional application is that you can 1.124 + <quote>tag</quote> a patch with a <emphasis>guard</emphasis>, 1.125 + which is simply a text string of your choosing, then tell MQ to 1.126 + select specific guards to use when applying patches. MQ will 1.127 + then either apply, or skip over, a guarded patch, depending on 1.128 + the guards that you have selected.</para> 1.129 + 1.130 + <para id="x_16e">A patch can have an arbitrary number of guards; each one is 1.131 + <emphasis>positive</emphasis> (<quote>apply this patch if this 1.132 + guard is selected</quote>) or <emphasis>negative</emphasis> 1.133 + (<quote>skip this patch if this guard is selected</quote>). A 1.134 + patch with no guards is always applied.</para> 1.135 + 1.136 + </sect1> 1.137 + <sect1> 1.138 + <title>Controlling the guards on a patch</title> 1.139 + 1.140 + <para id="x_16f">The <command role="hg-ext-mq">qguard</command> command lets 1.141 + you determine which guards should apply to a patch, or display 1.142 + the guards that are already in effect. Without any arguments, it 1.143 + displays the guards on the current topmost patch.</para> 1.144 + 1.145 + &interaction.mq.guards.qguard; 1.146 + 1.147 + <para id="x_170">To set a positive guard on a patch, prefix the name of the 1.148 + guard with a <quote><literal>+</literal></quote>.</para> 1.149 + 1.150 + &interaction.mq.guards.qguard.pos; 1.151 + 1.152 + <para id="x_171">To set a negative guard 1.153 + on a patch, prefix the name of the guard with a 1.154 + <quote><literal>-</literal></quote>.</para> 1.155 + 1.156 + &interaction.mq.guards.qguard.neg; 1.157 + 1.158 + <para id="x_74a">Notice that we prefixed the arguments to the <command>hg 1.159 + qguard</command> command with a <literal>--</literal> here, so 1.160 + that Mercurial would not interpret the text 1.161 + <literal>-quux</literal> as an option.</para> 1.162 + 1.163 + <note> 1.164 + <title>Setting vs. modifying</title> 1.165 + 1.166 + <para id="x_172"> The <command role="hg-ext-mq">qguard</command> command 1.167 + <emphasis>sets</emphasis> the guards on a patch; it doesn't 1.168 + <emphasis>modify</emphasis> them. What this means is that if 1.169 + you run <command role="hg-cmd">hg qguard +a +b</command> on a 1.170 + patch, then <command role="hg-cmd">hg qguard +c</command> on 1.171 + the same patch, the <emphasis>only</emphasis> guard that will 1.172 + be set on it afterwards is <literal>+c</literal>.</para> 1.173 + </note> 1.174 + 1.175 + <para id="x_173">Mercurial stores guards in the <filename 1.176 + role="special">series</filename> file; the form in which they 1.177 + are stored is easy both to understand and to edit by hand. (In 1.178 + other words, you don't have to use the <command 1.179 + role="hg-ext-mq">qguard</command> command if you don't want 1.180 + to; it's okay to simply edit the <filename 1.181 + role="special">series</filename> file.)</para> 1.182 + 1.183 + &interaction.mq.guards.series; 1.184 + 1.185 + </sect1> 1.186 + <sect1> 1.187 + <title>Selecting the guards to use</title> 1.188 + 1.189 + <para id="x_174">The <command role="hg-ext-mq">qselect</command> command 1.190 + determines which guards are active at a given time. The effect 1.191 + of this is to determine which patches MQ will apply the next 1.192 + time you run <command role="hg-ext-mq">qpush</command>. It has 1.193 + no other effect; in particular, it doesn't do anything to 1.194 + patches that are already applied.</para> 1.195 + 1.196 + <para id="x_175">With no arguments, the <command 1.197 + role="hg-ext-mq">qselect</command> command lists the guards 1.198 + currently in effect, one per line of output. Each argument is 1.199 + treated as the name of a guard to apply.</para> 1.200 + 1.201 + &interaction.mq.guards.qselect.foo; 1.202 + 1.203 + <para id="x_176">In case you're interested, the currently selected guards are 1.204 + stored in the <filename role="special">guards</filename> file.</para> 1.205 + 1.206 + &interaction.mq.guards.qselect.cat; 1.207 + 1.208 + <para id="x_177">We can see the effect the selected guards have when we run 1.209 + <command role="hg-ext-mq">qpush</command>.</para> 1.210 + 1.211 + &interaction.mq.guards.qselect.qpush; 1.212 + 1.213 + <para id="x_178">A guard cannot start with a 1.214 + <quote><literal>+</literal></quote> or 1.215 + <quote><literal>-</literal></quote> character. The name of a 1.216 + guard must not contain white space, but most other characters 1.217 + are acceptable. If you try to use a guard with an invalid name, 1.218 + MQ will complain:</para> 1.219 + 1.220 + &interaction.mq.guards.qselect.error; 1.221 + 1.222 + <para id="x_179">Changing the selected guards changes the patches that are 1.223 + applied.</para> 1.224 + 1.225 + &interaction.mq.guards.qselect.quux; 1.226 + 1.227 + <para id="x_17a">You can see in the example below that negative guards take 1.228 + precedence over positive guards.</para> 1.229 + 1.230 + &interaction.mq.guards.qselect.foobar; 1.231 + 1.232 + </sect1> 1.233 + <sect1> 1.234 + <title>MQ's rules for applying patches</title> 1.235 + 1.236 + <para id="x_17b">The rules that MQ uses when deciding whether to apply a 1.237 + patch are as follows.</para> 1.238 + <itemizedlist> 1.239 + <listitem><para id="x_17c">A patch that has no guards is always 1.240 + applied.</para> 1.241 + </listitem> 1.242 + <listitem><para id="x_17d">If the patch has any negative guard that matches 1.243 + any currently selected guard, the patch is skipped.</para> 1.244 + </listitem> 1.245 + <listitem><para id="x_17e">If the patch has any positive guard that matches 1.246 + any currently selected guard, the patch is applied.</para> 1.247 + </listitem> 1.248 + <listitem><para id="x_17f">If the patch has positive or negative guards, 1.249 + but none matches any currently selected guard, the patch is 1.250 + skipped.</para> 1.251 + </listitem></itemizedlist> 1.252 + 1.253 + </sect1> 1.254 + <sect1> 1.255 + <title>Trimming the work environment</title> 1.256 + 1.257 + <para id="x_180">In working on the device driver I mentioned earlier, I don't 1.258 + apply the patches to a normal Linux kernel tree. Instead, I use 1.259 + a repository that contains only a snapshot of the source files 1.260 + and headers that are relevant to Infiniband development. This 1.261 + repository is 1% the size of a kernel repository, so it's easier 1.262 + to work with.</para> 1.263 + 1.264 + <para id="x_181">I then choose a <quote>base</quote> version on top of which 1.265 + the patches are applied. This is a snapshot of the Linux kernel 1.266 + tree as of a revision of my choosing. When I take the snapshot, 1.267 + I record the changeset ID from the kernel repository in the 1.268 + commit message. Since the snapshot preserves the 1.269 + <quote>shape</quote> and content of the relevant parts of the 1.270 + kernel tree, I can apply my patches on top of either my tiny 1.271 + repository or a normal kernel tree.</para> 1.272 + 1.273 + <para id="x_182">Normally, the base tree atop which the patches apply should 1.274 + be a snapshot of a very recent upstream tree. This best 1.275 + facilitates the development of patches that can easily be 1.276 + submitted upstream with few or no modifications.</para> 1.277 + 1.278 + </sect1> 1.279 + <sect1> 1.280 + <title>Dividing up the <filename role="special">series</filename> 1.281 + file</title> 1.282 + 1.283 + <para id="x_183">I categorise the patches in the <filename 1.284 + role="special">series</filename> file into a number of logical 1.285 + groups. Each section of like patches begins with a block of 1.286 + comments that describes the purpose of the patches that 1.287 + follow.</para> 1.288 + 1.289 + <para id="x_184">The sequence of patch groups that I maintain follows. The 1.290 + ordering of these groups is important; I'll describe why after I 1.291 + introduce the groups.</para> 1.292 + <itemizedlist> 1.293 + <listitem><para id="x_185">The <quote>accepted</quote> group. Patches that 1.294 + the development team has submitted to the maintainer of the 1.295 + Infiniband subsystem, and which he has accepted, but which 1.296 + are not present in the snapshot that the tiny repository is 1.297 + based on. These are <quote>read only</quote> patches, 1.298 + present only to transform the tree into a similar state as 1.299 + it is in the upstream maintainer's repository.</para> 1.300 + </listitem> 1.301 + <listitem><para id="x_186">The <quote>rework</quote> group. Patches that I 1.302 + have submitted, but that the upstream maintainer has 1.303 + requested modifications to before he will accept 1.304 + them.</para> 1.305 + </listitem> 1.306 + <listitem><para id="x_187">The <quote>pending</quote> group. Patches that 1.307 + I have not yet submitted to the upstream maintainer, but 1.308 + which we have finished working on. These will be <quote>read 1.309 + only</quote> for a while. If the upstream maintainer 1.310 + accepts them upon submission, I'll move them to the end of 1.311 + the <quote>accepted</quote> group. If he requests that I 1.312 + modify any, I'll move them to the beginning of the 1.313 + <quote>rework</quote> group.</para> 1.314 + </listitem> 1.315 + <listitem><para id="x_188">The <quote>in progress</quote> group. Patches 1.316 + that are actively being developed, and should not be 1.317 + submitted anywhere yet.</para> 1.318 + </listitem> 1.319 + <listitem><para id="x_189">The <quote>backport</quote> group. Patches that 1.320 + adapt the source tree to older versions of the kernel 1.321 + tree.</para> 1.322 + </listitem> 1.323 + <listitem><para id="x_18a">The <quote>do not ship</quote> group. Patches 1.324 + that for some reason should never be submitted upstream. 1.325 + For example, one such patch might change embedded driver 1.326 + identification strings to make it easier to distinguish, in 1.327 + the field, between an out-of-tree version of the driver and 1.328 + a version shipped by a distribution vendor.</para> 1.329 + </listitem></itemizedlist> 1.330 + 1.331 + <para id="x_18b">Now to return to the reasons for ordering groups of patches 1.332 + in this way. We would like the lowest patches in the stack to 1.333 + be as stable as possible, so that we will not need to rework 1.334 + higher patches due to changes in context. Putting patches that 1.335 + will never be changed first in the <filename 1.336 + role="special">series</filename> file serves this 1.337 + purpose.</para> 1.338 + 1.339 + <para id="x_18c">We would also like the patches that we know we'll need to 1.340 + modify to be applied on top of a source tree that resembles the 1.341 + upstream tree as closely as possible. This is why we keep 1.342 + accepted patches around for a while.</para> 1.343 + 1.344 + <para id="x_18d">The <quote>backport</quote> and <quote>do not ship</quote> 1.345 + patches float at the end of the <filename 1.346 + role="special">series</filename> file. The backport patches 1.347 + must be applied on top of all other patches, and the <quote>do 1.348 + not ship</quote> patches might as well stay out of harm's 1.349 + way.</para> 1.350 + 1.351 + </sect1> 1.352 + <sect1> 1.353 + <title>Maintaining the patch series</title> 1.354 + 1.355 + <para id="x_18e">In my work, I use a number of guards to control which 1.356 + patches are to be applied.</para> 1.357 + 1.358 + <itemizedlist> 1.359 + <listitem><para id="x_18f"><quote>Accepted</quote> patches are guarded with 1.360 + <literal>accepted</literal>. I enable this guard most of 1.361 + the time. When I'm applying the patches on top of a tree 1.362 + where the patches are already present, I can turn this patch 1.363 + off, and the patches that follow it will apply 1.364 + cleanly.</para> 1.365 + </listitem> 1.366 + <listitem><para id="x_190">Patches that are <quote>finished</quote>, but 1.367 + not yet submitted, have no guards. If I'm applying the 1.368 + patch stack to a copy of the upstream tree, I don't need to 1.369 + enable any guards in order to get a reasonably safe source 1.370 + tree.</para> 1.371 + </listitem> 1.372 + <listitem><para id="x_191">Those patches that need reworking before being 1.373 + resubmitted are guarded with 1.374 + <literal>rework</literal>.</para> 1.375 + </listitem> 1.376 + <listitem><para id="x_192">For those patches that are still under 1.377 + development, I use <literal>devel</literal>.</para> 1.378 + </listitem> 1.379 + <listitem><para id="x_193">A backport patch may have several guards, one 1.380 + for each version of the kernel to which it applies. For 1.381 + example, a patch that backports a piece of code to 2.6.9 1.382 + will have a <literal>2.6.9</literal> guard.</para> 1.383 + </listitem></itemizedlist> 1.384 + <para id="x_194">This variety of guards gives me considerable flexibility in 1.385 + determining what kind of source tree I want to end up with. For 1.386 + most situations, the selection of appropriate guards is 1.387 + automated during the build process, but I can manually tune the 1.388 + guards to use for less common circumstances.</para> 1.389 + 1.390 + <sect2> 1.391 + <title>The art of writing backport patches</title> 1.392 + 1.393 + <para id="x_195">Using MQ, writing a backport patch is a simple process. 1.394 + All such a patch has to do is modify a piece of code that uses 1.395 + a kernel feature not present in the older version of the 1.396 + kernel, so that the driver continues to work correctly under 1.397 + that older version.</para> 1.398 + 1.399 + <para id="x_196">A useful goal when writing a good backport patch is to 1.400 + make your code look as if it was written for the older version 1.401 + of the kernel you're targeting. The less obtrusive the patch, 1.402 + the easier it will be to understand and maintain. If you're 1.403 + writing a collection of backport patches to avoid the 1.404 + <quote>rat's nest</quote> effect of lots of 1.405 + <literal>#ifdef</literal>s (hunks of source code that are only 1.406 + used conditionally) in your code, don't introduce 1.407 + version-dependent <literal>#ifdef</literal>s into the patches. 1.408 + Instead, write several patches, each of which makes 1.409 + unconditional changes, and control their application using 1.410 + guards.</para> 1.411 + 1.412 + <para id="x_197">There are two reasons to divide backport patches into a 1.413 + distinct group, away from the <quote>regular</quote> patches 1.414 + whose effects they modify. The first is that intermingling the 1.415 + two makes it more difficult to use a tool like the <literal 1.416 + role="hg-ext">patchbomb</literal> extension to automate the 1.417 + process of submitting the patches to an upstream maintainer. 1.418 + The second is that a backport patch could perturb the context 1.419 + in which a subsequent regular patch is applied, making it 1.420 + impossible to apply the regular patch cleanly 1.421 + <emphasis>without</emphasis> the earlier backport patch 1.422 + already being applied.</para> 1.423 + 1.424 + </sect2> 1.425 + </sect1> 1.426 + <sect1> 1.427 + <title>Useful tips for developing with MQ</title> 1.428 + 1.429 + <sect2> 1.430 + <title>Organising patches in directories</title> 1.431 + 1.432 + <para id="x_198">If you're working on a substantial project with MQ, it's 1.433 + not difficult to accumulate a large number of patches. For 1.434 + example, I have one patch repository that contains over 250 1.435 + patches.</para> 1.436 + 1.437 + <para id="x_199">If you can group these patches into separate logical 1.438 + categories, you can if you like store them in different 1.439 + directories; MQ has no problems with patch names that contain 1.440 + path separators.</para> 1.441 + 1.442 + </sect2> 1.443 + <sect2 id="mq-collab:tips:interdiff"> 1.444 + <title>Viewing the history of a patch</title> 1.445 + 1.446 + <para id="x_19a">If you're developing a set of patches over a long time, 1.447 + it's a good idea to maintain them in a repository, as 1.448 + discussed in <xref linkend="sec:mq:repo"/>. If you do 1.449 + so, you'll quickly 1.450 + discover that using the <command role="hg-cmd">hg 1.451 + diff</command> command to look at the history of changes to 1.452 + a patch is unworkable. This is in part because you're looking 1.453 + at the second derivative of the real code (a diff of a diff), 1.454 + but also because MQ adds noise to the process by modifying 1.455 + time stamps and directory names when it updates a 1.456 + patch.</para> 1.457 + 1.458 + <para id="x_19b">However, you can use the <literal 1.459 + role="hg-ext">extdiff</literal> extension, which is bundled 1.460 + with Mercurial, to turn a diff of two versions of a patch into 1.461 + something readable. To do this, you will need a third-party 1.462 + package called <literal role="package">patchutils</literal> 1.463 + <citation>web:patchutils</citation>. This provides a command 1.464 + named <command>interdiff</command>, which shows the 1.465 + differences between two diffs as a diff. Used on two versions 1.466 + of the same diff, it generates a diff that represents the diff 1.467 + from the first to the second version.</para> 1.468 + 1.469 + <para id="x_19c">You can enable the <literal 1.470 + role="hg-ext">extdiff</literal> extension in the usual way, 1.471 + by adding a line to the <literal 1.472 + role="rc-extensions">extensions</literal> section of your 1.473 + <filename role="special">~/.hgrc</filename>.</para> 1.474 + <programlisting>[extensions] 1.475 +extdiff =</programlisting> 1.476 + <para id="x_19d">The <command>interdiff</command> command expects to be 1.477 + passed the names of two files, but the <literal 1.478 + role="hg-ext">extdiff</literal> extension passes the program 1.479 + it runs a pair of directories, each of which can contain an 1.480 + arbitrary number of files. We thus need a small program that 1.481 + will run <command>interdiff</command> on each pair of files in 1.482 + these two directories. This program is available as <filename 1.483 + role="special">hg-interdiff</filename> in the <filename 1.484 + class="directory">examples</filename> directory of the 1.485 + source code repository that accompanies this book. <!-- 1.486 + &example.hg-interdiff; --></para> 1.487 + 1.488 + <para id="x_19e">With the <filename role="special">hg-interdiff</filename> 1.489 + program in your shell's search path, you can run it as 1.490 + follows, from inside an MQ patch directory:</para> 1.491 + <programlisting>hg extdiff -p hg-interdiff -r A:B my-change.patch</programlisting> 1.492 + <para id="x_19f">Since you'll probably want to use this long-winded command 1.493 + a lot, you can get <literal role="hg-ext">hgext</literal> to 1.494 + make it available as a normal Mercurial command, again by 1.495 + editing your <filename 1.496 + role="special">~/.hgrc</filename>.</para> 1.497 + <programlisting>[extdiff] 1.498 +cmd.interdiff = hg-interdiff</programlisting> 1.499 + <para id="x_1a0">This directs <literal role="hg-ext">hgext</literal> to 1.500 + make an <literal>interdiff</literal> command available, so you 1.501 + can now shorten the previous invocation of <command 1.502 + role="hg-ext-extdiff">extdiff</command> to something a 1.503 + little more wieldy.</para> 1.504 + <programlisting>hg interdiff -r A:B my-change.patch</programlisting> 1.505 + 1.506 + <note> 1.507 + <para id="x_1a1"> The <command>interdiff</command> command works well 1.508 + only if the underlying files against which versions of a 1.509 + patch are generated remain the same. If you create a patch, 1.510 + modify the underlying files, and then regenerate the patch, 1.511 + <command>interdiff</command> may not produce useful 1.512 + output.</para> 1.513 + </note> 1.514 + 1.515 + <para id="x_1a2">The <literal role="hg-ext">extdiff</literal> extension is 1.516 + useful for more than merely improving the presentation of MQ 1.517 + patches. To read more about it, go to <xref 1.518 + linkend="sec:hgext:extdiff"/>.</para> 1.519 + 1.520 + </sect2> 1.521 + </sect1> 1.522 +</chapter> 1.523 + 1.524 +<!-- 1.525 +local variables: 1.526 +sgml-parent-document: ("00book.xml" "book" "chapter") 1.527 +end: 1.528 +-->