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