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