Mercurial > hgbook
annotate es/mq-collab.tex @ 588:b1ae672fd92b
translated a section
author | Javier Rojas <jerojasro@devnull.li> |
---|---|
date | Wed, 07 Jan 2009 21:27:01 -0500 |
parents | 039ed6f5935b |
children | 254888ffaf0a |
rev | line source |
---|---|
580
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
1 \chapter{Usos avanzados de las Colas de Mercurial} |
435 | 2 \label{chap:mq-collab} |
3 | |
580
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
4 Auunque es fácil aprender los usos más directos de las Colas de |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
5 Mercurial, tener algo de disciplina junto con algunas de las |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
6 capacidadees menos usadas de MQ hace posible trabajar en entornos de |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
7 desarrollo complejos. |
435 | 8 |
580
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
9 En este capítulo, usaré como ejemplo una técnica que he usado para |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
10 administrar el desarrollo de un controlador de dispositivo Infiniband |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
11 para el kernel de Linux. El controlador en cuestión es grande |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
12 (al menos en lo que se refiere a controladores), con 25,000 líneas de |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
13 código esparcidas en 35 ficheros fuente. Es mantenido por un equipo |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
14 pequeño de desarrolladores. |
435 | 15 |
580
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
16 Aunque mucho del material en este capítulo es específico de Linux, los |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
17 mismos principios aplican a cualquier base de código de la que usted |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
18 no sea el propietario principal, y sobre la que usted necesita hacer |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
19 un montón de desarrollo. |
435 | 20 |
580
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
21 \section{El problema de múltiples objetivos} |
435 | 22 |
580
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
23 El kernel de Linux cambia con rapidez, y nunca ha sido estable |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
24 internamente; los desarrolladores hacen cambios drásticos entre |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
25 %TODO no encontré una traducción adecuada para "release". Por eso el |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
26 %cambio |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
27 versiones frecuentemente. Esto significa que una versión del |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
28 controlador que funciona bien con una versión particular del kernel ni |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
29 siquiera \emph{compilará} correctamente contra, típicamente, cualquier |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
30 otra versión. |
435 | 31 |
580
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
32 Para mantener un controlador, debemos tener en cuenta una buena |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
33 cantidad de versiones de Linux en mente. |
435 | 34 \begin{itemize} |
580
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
35 \item Un objetivo es el árbol de desarrollo principal del kernel de |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
36 Linux. En este caso el mantenimiento del código es compartido |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
37 parcialmente por otros desarrolladores en la comunidad del kernel, |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
38 %TODO drive-by. |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
39 quienes hacen modificaciones ``de-afán'' al controlador a medida que |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
40 desarrollan y refinan subsistemas en el kernel. |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
41 %TODO backport |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
42 \item También mantenemos algunos ``backports'' para versiones antiguas |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
43 del kernel de Linux, para dar soporte a las necesidades de los |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
44 clientes que están corriendo versiones antiguas de Linux que no |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
45 incorporan nuestros controladores. (Hacer el \emph{backport} de un |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
46 pedazo de código es modificarlo para que trabaje en una versión |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
47 de su entorno objetivo anterior a aquella para la cual fue escrito.) |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
48 \item Finalmente, nosotros liberamos nuestro software de acuerdo a un |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
49 cronograma que no necesariamente está alineado con el que usan los |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
50 distribuidores de Linux y los desarrolladores del kernel, así que |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
51 podemos entregar nuevas características a los clientes sin forzarlos |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
52 a actualizar kernels completos o distribuciones. |
435 | 53 \end{itemize} |
54 | |
580
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
55 \subsection{Aproximaciones tentadoras que no funcionan adecuadamente} |
435 | 56 |
580
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
57 Hay dos maneras estándar de mantener una porción de software que debe |
6cf30b3ed48f
translated some paragraphs
Javier Rojas <jerojasro@devnull.li>
parents:
435
diff
changeset
|
58 funcionar en muchos entornos diferentes. |
435 | 59 |
584 | 60 La primera es mantener varias ramas, cada una pensada para un único |
61 entorno. El problema de esta aproximación es que usted debe tener una | |
62 disciplina férrea con el flujo de cambios entre repositorios. Una | |
63 nueva característica o un arreglo de fallo deben empezar su vida en un | |
64 repositorio ``prístino'', y luego propagarse a cada repositorio de | |
65 backport. Los cambios para backports están más limitados respecto a | |
66 las ramas a las que deberían propagarse; un cambio para backport que | |
67 es aplicado a una rama en la que no corresponde probablemente hará que | |
68 el controlador no compile. | |
69 | |
70 La segunda es mantener un único árbol de código fuente lleno de | |
71 declaraciones que activen o desactiven secciones de código dependiendo | |
72 del entorno objetivo. Ya que estos ``ifdefs'' no están permitidos en | |
73 el árbol del kernel de Linux, debe seguirse algún proceso manual o | |
74 automático para eliminarlos y producir un árbol limpio. Una base de | |
75 código mantenida de esta manera se convierte rápidamente en un nido de | |
76 ratas de bloques condicionales que son difíciles de entender y | |
77 mantener. | |
435 | 78 |
584 | 79 %TODO canónica? |
80 Ninguno de estos enfoques es adecuado para situaciones en las que | |
81 usted no es ``dueño'' de la copia canónica de un árbol de fuentes. En | |
82 el caso de un controlador de Linux que es distribuido con el kernel | |
83 estándar, el árbol de Linux contiene la copia del código que será | |
84 considerada por el mundo como la canónica. La versión oficial de | |
85 ``mi'' controlador puede ser modificada por gente que no conozco, sin | |
86 que yo siquiera me entere de ello hasta después de que los cambios | |
87 aparecen en el árbol de Linus. | |
435 | 88 |
584 | 89 Estos enfoques tienen la debilidad adicional de dificultar la |
90 %TODO upstream. no no es río arriba | |
91 generación de parches bien formados para enviarlos a la versión | |
92 oficial. | |
435 | 93 |
584 | 94 En principio, las Colas de Mercurial parecen ser un buen candidato |
95 para administrar un escenario de desarrollo como el de arriba. Aunque | |
96 este es de hecho el caso, MQ tiene unas cuantas características | |
97 adicionales que hacen el trabajo más agradable. | |
435 | 98 |
588 | 99 \section{Aplicar parches condicionalmente mediante guardias} |
435 | 100 |
588 | 101 Tal vez la mejor manera de conservar la cordura con tantos entornos |
102 objetivo es poder escoger parches específicos para aplicar para cada | |
103 situación. MQ provee una característica llamada ``guardias'' | |
104 (que se origina del comando \texttt{guards} de Quilt) que hace | |
105 precisamente ésto. Para empezar, creemos un repositorio sencillo para | |
106 experimentar. | |
435 | 107 \interaction{mq.guards.init} |
588 | 108 Esto nos brinda un pequeño repositorio que contiene dos parches que no |
109 tienen ninguna dependencia respecto al otro, porque tocan ficheros | |
110 diferentes. | |
435 | 111 |
588 | 112 La idea detrás de la aplicación condicional es que usted puede |
113 ``etiquetar'' un parche con un \emph{guardia}, que simplemente es una | |
114 cadena de texto de su elección, y luego decirle a MQ que seleccione | |
115 guardias específicos para usar cuando aplique parches. MQ entonces | |
116 aplicará, u omitirá, un parche vigilado, dependiendo de los guardias | |
117 que usted haya seleccionado. | |
435 | 118 |
588 | 119 Un parche puede tener una cantidad arbitraria de guardias; cada uno es |
120 \emph{positivo} (``aplique el parche si este guardia es | |
121 seleccionado'') o \emph{negativo} (``omita este parche si este guardia | |
122 es seleccionado''). Un parche sin guardias siempre es aplicado. | |
435 | 123 |
124 \section{Controlling the guards on a patch} | |
125 | |
126 The \hgxcmd{mq}{qguard} command lets you determine which guards should | |
127 apply to a patch, or display the guards that are already in effect. | |
128 Without any arguments, it displays the guards on the current topmost | |
129 patch. | |
130 \interaction{mq.guards.qguard} | |
131 To set a positive guard on a patch, prefix the name of the guard with | |
132 a ``\texttt{+}''. | |
133 \interaction{mq.guards.qguard.pos} | |
134 To set a negative guard on a patch, prefix the name of the guard with | |
135 a ``\texttt{-}''. | |
136 \interaction{mq.guards.qguard.neg} | |
137 | |
138 \begin{note} | |
139 The \hgxcmd{mq}{qguard} command \emph{sets} the guards on a patch; it | |
140 doesn't \emph{modify} them. What this means is that if you run | |
141 \hgcmdargs{qguard}{+a +b} on a patch, then \hgcmdargs{qguard}{+c} on | |
142 the same patch, the \emph{only} guard that will be set on it | |
143 afterwards is \texttt{+c}. | |
144 \end{note} | |
145 | |
146 Mercurial stores guards in the \sfilename{series} file; the form in | |
147 which they are stored is easy both to understand and to edit by hand. | |
148 (In other words, you don't have to use the \hgxcmd{mq}{qguard} command if | |
149 you don't want to; it's okay to simply edit the \sfilename{series} | |
150 file.) | |
151 \interaction{mq.guards.series} | |
152 | |
153 \section{Selecting the guards to use} | |
154 | |
155 The \hgxcmd{mq}{qselect} command determines which guards are active at a | |
156 given time. The effect of this is to determine which patches MQ will | |
157 apply the next time you run \hgxcmd{mq}{qpush}. It has no other effect; in | |
158 particular, it doesn't do anything to patches that are already | |
159 applied. | |
160 | |
161 With no arguments, the \hgxcmd{mq}{qselect} command lists the guards | |
162 currently in effect, one per line of output. Each argument is treated | |
163 as the name of a guard to apply. | |
164 \interaction{mq.guards.qselect.foo} | |
165 In case you're interested, the currently selected guards are stored in | |
166 the \sfilename{guards} file. | |
167 \interaction{mq.guards.qselect.cat} | |
168 We can see the effect the selected guards have when we run | |
169 \hgxcmd{mq}{qpush}. | |
170 \interaction{mq.guards.qselect.qpush} | |
171 | |
172 A guard cannot start with a ``\texttt{+}'' or ``\texttt{-}'' | |
173 character. The name of a guard must not contain white space, but most | |
174 other characters are acceptable. If you try to use a guard with an | |
175 invalid name, MQ will complain: | |
176 \interaction{mq.guards.qselect.error} | |
177 Changing the selected guards changes the patches that are applied. | |
178 \interaction{mq.guards.qselect.quux} | |
179 You can see in the example below that negative guards take precedence | |
180 over positive guards. | |
181 \interaction{mq.guards.qselect.foobar} | |
182 | |
183 \section{MQ's rules for applying patches} | |
184 | |
185 The rules that MQ uses when deciding whether to apply a patch | |
186 are as follows. | |
187 \begin{itemize} | |
188 \item A patch that has no guards is always applied. | |
189 \item If the patch has any negative guard that matches any currently | |
190 selected guard, the patch is skipped. | |
191 \item If the patch has any positive guard that matches any currently | |
192 selected guard, the patch is applied. | |
193 \item If the patch has positive or negative guards, but none matches | |
194 any currently selected guard, the patch is skipped. | |
195 \end{itemize} | |
196 | |
197 \section{Trimming the work environment} | |
198 | |
199 In working on the device driver I mentioned earlier, I don't apply the | |
200 patches to a normal Linux kernel tree. Instead, I use a repository | |
201 that contains only a snapshot of the source files and headers that are | |
202 relevant to Infiniband development. This repository is~1\% the size | |
203 of a kernel repository, so it's easier to work with. | |
204 | |
205 I then choose a ``base'' version on top of which the patches are | |
206 applied. This is a snapshot of the Linux kernel tree as of a revision | |
207 of my choosing. When I take the snapshot, I record the changeset ID | |
208 from the kernel repository in the commit message. Since the snapshot | |
209 preserves the ``shape'' and content of the relevant parts of the | |
210 kernel tree, I can apply my patches on top of either my tiny | |
211 repository or a normal kernel tree. | |
212 | |
213 Normally, the base tree atop which the patches apply should be a | |
214 snapshot of a very recent upstream tree. This best facilitates the | |
215 development of patches that can easily be submitted upstream with few | |
216 or no modifications. | |
217 | |
218 \section{Dividing up the \sfilename{series} file} | |
219 | |
220 I categorise the patches in the \sfilename{series} file into a number | |
221 of logical groups. Each section of like patches begins with a block | |
222 of comments that describes the purpose of the patches that follow. | |
223 | |
224 The sequence of patch groups that I maintain follows. The ordering of | |
225 these groups is important; I'll describe why after I introduce the | |
226 groups. | |
227 \begin{itemize} | |
228 \item The ``accepted'' group. Patches that the development team has | |
229 submitted to the maintainer of the Infiniband subsystem, and which | |
230 he has accepted, but which are not present in the snapshot that the | |
231 tiny repository is based on. These are ``read only'' patches, | |
232 present only to transform the tree into a similar state as it is in | |
233 the upstream maintainer's repository. | |
234 \item The ``rework'' group. Patches that I have submitted, but that | |
235 the upstream maintainer has requested modifications to before he | |
236 will accept them. | |
237 \item The ``pending'' group. Patches that I have not yet submitted to | |
238 the upstream maintainer, but which we have finished working on. | |
239 These will be ``read only'' for a while. If the upstream maintainer | |
240 accepts them upon submission, I'll move them to the end of the | |
241 ``accepted'' group. If he requests that I modify any, I'll move | |
242 them to the beginning of the ``rework'' group. | |
243 \item The ``in progress'' group. Patches that are actively being | |
244 developed, and should not be submitted anywhere yet. | |
245 \item The ``backport'' group. Patches that adapt the source tree to | |
246 older versions of the kernel tree. | |
247 \item The ``do not ship'' group. Patches that for some reason should | |
248 never be submitted upstream. For example, one such patch might | |
249 change embedded driver identification strings to make it easier to | |
250 distinguish, in the field, between an out-of-tree version of the | |
251 driver and a version shipped by a distribution vendor. | |
252 \end{itemize} | |
253 | |
254 Now to return to the reasons for ordering groups of patches in this | |
255 way. We would like the lowest patches in the stack to be as stable as | |
256 possible, so that we will not need to rework higher patches due to | |
257 changes in context. Putting patches that will never be changed first | |
258 in the \sfilename{series} file serves this purpose. | |
259 | |
260 We would also like the patches that we know we'll need to modify to be | |
261 applied on top of a source tree that resembles the upstream tree as | |
262 closely as possible. This is why we keep accepted patches around for | |
263 a while. | |
264 | |
265 The ``backport'' and ``do not ship'' patches float at the end of the | |
266 \sfilename{series} file. The backport patches must be applied on top | |
267 of all other patches, and the ``do not ship'' patches might as well | |
268 stay out of harm's way. | |
269 | |
270 \section{Maintaining the patch series} | |
271 | |
272 In my work, I use a number of guards to control which patches are to | |
273 be applied. | |
274 | |
275 \begin{itemize} | |
276 \item ``Accepted'' patches are guarded with \texttt{accepted}. I | |
277 enable this guard most of the time. When I'm applying the patches | |
278 on top of a tree where the patches are already present, I can turn | |
279 this patch off, and the patches that follow it will apply cleanly. | |
280 \item Patches that are ``finished'', but not yet submitted, have no | |
281 guards. If I'm applying the patch stack to a copy of the upstream | |
282 tree, I don't need to enable any guards in order to get a reasonably | |
283 safe source tree. | |
284 \item Those patches that need reworking before being resubmitted are | |
285 guarded with \texttt{rework}. | |
286 \item For those patches that are still under development, I use | |
287 \texttt{devel}. | |
288 \item A backport patch may have several guards, one for each version | |
289 of the kernel to which it applies. For example, a patch that | |
290 backports a piece of code to~2.6.9 will have a~\texttt{2.6.9} guard. | |
291 \end{itemize} | |
292 This variety of guards gives me considerable flexibility in | |
293 qdetermining what kind of source tree I want to end up with. For most | |
294 situations, the selection of appropriate guards is automated during | |
295 the build process, but I can manually tune the guards to use for less | |
296 common circumstances. | |
297 | |
298 \subsection{The art of writing backport patches} | |
299 | |
300 Using MQ, writing a backport patch is a simple process. All such a | |
301 patch has to do is modify a piece of code that uses a kernel feature | |
302 not present in the older version of the kernel, so that the driver | |
303 continues to work correctly under that older version. | |
304 | |
305 A useful goal when writing a good backport patch is to make your code | |
306 look as if it was written for the older version of the kernel you're | |
307 targeting. The less obtrusive the patch, the easier it will be to | |
308 understand and maintain. If you're writing a collection of backport | |
309 patches to avoid the ``rat's nest'' effect of lots of | |
310 \texttt{\#ifdef}s (hunks of source code that are only used | |
311 conditionally) in your code, don't introduce version-dependent | |
312 \texttt{\#ifdef}s into the patches. Instead, write several patches, | |
313 each of which makes unconditional changes, and control their | |
314 application using guards. | |
315 | |
316 There are two reasons to divide backport patches into a distinct | |
317 group, away from the ``regular'' patches whose effects they modify. | |
318 The first is that intermingling the two makes it more difficult to use | |
319 a tool like the \hgext{patchbomb} extension to automate the process of | |
320 submitting the patches to an upstream maintainer. The second is that | |
321 a backport patch could perturb the context in which a subsequent | |
322 regular patch is applied, making it impossible to apply the regular | |
323 patch cleanly \emph{without} the earlier backport patch already being | |
324 applied. | |
325 | |
326 \section{Useful tips for developing with MQ} | |
327 | |
328 \subsection{Organising patches in directories} | |
329 | |
330 If you're working on a substantial project with MQ, it's not difficult | |
331 to accumulate a large number of patches. For example, I have one | |
332 patch repository that contains over 250 patches. | |
333 | |
334 If you can group these patches into separate logical categories, you | |
335 can if you like store them in different directories; MQ has no | |
336 problems with patch names that contain path separators. | |
337 | |
338 \subsection{Viewing the history of a patch} | |
339 \label{mq-collab:tips:interdiff} | |
340 | |
341 If you're developing a set of patches over a long time, it's a good | |
342 idea to maintain them in a repository, as discussed in | |
343 section~\ref{sec:mq:repo}. If you do so, you'll quickly discover that | |
344 using the \hgcmd{diff} command to look at the history of changes to a | |
345 patch is unworkable. This is in part because you're looking at the | |
346 second derivative of the real code (a diff of a diff), but also | |
347 because MQ adds noise to the process by modifying time stamps and | |
348 directory names when it updates a patch. | |
349 | |
350 However, you can use the \hgext{extdiff} extension, which is bundled | |
351 with Mercurial, to turn a diff of two versions of a patch into | |
352 something readable. To do this, you will need a third-party package | |
353 called \package{patchutils}~\cite{web:patchutils}. This provides a | |
354 command named \command{interdiff}, which shows the differences between | |
355 two diffs as a diff. Used on two versions of the same diff, it | |
356 generates a diff that represents the diff from the first to the second | |
357 version. | |
358 | |
359 You can enable the \hgext{extdiff} extension in the usual way, by | |
360 adding a line to the \rcsection{extensions} section of your \hgrc. | |
361 \begin{codesample2} | |
362 [extensions] | |
363 extdiff = | |
364 \end{codesample2} | |
365 The \command{interdiff} command expects to be passed the names of two | |
366 files, but the \hgext{extdiff} extension passes the program it runs a | |
367 pair of directories, each of which can contain an arbitrary number of | |
368 files. We thus need a small program that will run \command{interdiff} | |
369 on each pair of files in these two directories. This program is | |
370 available as \sfilename{hg-interdiff} in the \dirname{examples} | |
371 directory of the source code repository that accompanies this book. | |
372 \excode{hg-interdiff} | |
373 | |
374 With the \sfilename{hg-interdiff} program in your shell's search path, | |
375 you can run it as follows, from inside an MQ patch directory: | |
376 \begin{codesample2} | |
377 hg extdiff -p hg-interdiff -r A:B my-change.patch | |
378 \end{codesample2} | |
379 Since you'll probably want to use this long-winded command a lot, you | |
380 can get \hgext{hgext} to make it available as a normal Mercurial | |
381 command, again by editing your \hgrc. | |
382 \begin{codesample2} | |
383 [extdiff] | |
384 cmd.interdiff = hg-interdiff | |
385 \end{codesample2} | |
386 This directs \hgext{hgext} to make an \texttt{interdiff} command | |
387 available, so you can now shorten the previous invocation of | |
388 \hgxcmd{extdiff}{extdiff} to something a little more wieldy. | |
389 \begin{codesample2} | |
390 hg interdiff -r A:B my-change.patch | |
391 \end{codesample2} | |
392 | |
393 \begin{note} | |
394 The \command{interdiff} command works well only if the underlying | |
395 files against which versions of a patch are generated remain the | |
396 same. If you create a patch, modify the underlying files, and then | |
397 regenerate the patch, \command{interdiff} may not produce useful | |
398 output. | |
399 \end{note} | |
400 | |
401 The \hgext{extdiff} extension is useful for more than merely improving | |
402 the presentation of MQ~patches. To read more about it, go to | |
403 section~\ref{sec:hgext:extdiff}. | |
404 | |
405 %%% Local Variables: | |
406 %%% mode: latex | |
407 %%% TeX-master: "00book" | |
408 %%% End: |