hgbook

annotate es/mq-collab.tex @ 823:68e59fe2429e

Minor changes to Ch.1.
author Giulio@puck
date Sat Aug 15 22:07:42 2009 +0200 (2009-08-15)
parents a8cdb3cac133
children
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@491 126 %TODO tal vez no decir determinar, sino definir?
jerojasro@490 127 El comando \hgxcmd{mq}{qguard} le permite determinar qué guardias
jerojasro@490 128 deben aplicarse a un parche, o mostrar los guardias que están en
jerojasro@490 129 efecto. Sin ningún argumento, el comando muestra los guardias del
jerojasro@490 130 parche actual de la parte más alta de la pila.
jerojasro@336 131 \interaction{mq.guards.qguard}
jerojasro@490 132 Para poner un guardia positivo en un parche, prefije el nombre del
jerojasro@490 133 guardia con un ``\texttt{+}''.
jerojasro@336 134 \interaction{mq.guards.qguard.pos}
jerojasro@490 135 Para poner un guardia negativo en un parche, prefije el nombre del
jerojasro@490 136 guardia con un ``\texttt{-}''.
jerojasro@336 137 \interaction{mq.guards.qguard.neg}
jerojasro@336 138
jerojasro@336 139 \begin{note}
jerojasro@490 140 El comando \hgxcmd{mq}{qguard} \emph{pone} los guardias en un
jerojasro@490 141 parche; no los \emph{modifica}. Esto significa que si usted ejecuta
jerojasro@490 142 \hgcmdargs{qguard}{+a +b} sobre un parche, y luego
jerojasro@490 143 \hgcmdargs{qguard}{+c} en el mismo parche, el único guardia sobre el
jerojasro@490 144 parche después del comando será \texttt{+c}.
jerojasro@336 145 \end{note}
jerojasro@336 146
jerojasro@490 147 Mercurial almacena los guardias en el fichero \sfilename{series}; la
jerojasro@490 148 forma en que son almacenados es fácil tanto de entender como de editar
jerojasro@490 149 a mano. (En otras palabras, usted no tiene que usar el comando
jerojasro@490 150 \hgxcmd{mq}{qguard} si no lo desea; está bien simplemente editar el
jerojasro@490 151 fichero \sfilename{series})
jerojasro@336 152 \interaction{mq.guards.series}
jerojasro@336 153
jerojasro@491 154 \section{Selecccionar los guardias a usar}
jerojasro@491 155
jerojasro@491 156 %TODO tal vez no decir determinar, sino definir?
jerojasro@491 157 El comando \hgxcmd{mq}{qselect} determina qué guardias están activos
jerojasro@491 158 en cualquier momento. El efecto de esto es determinar qué parches
jerojasro@491 159 aplicará MQ la próxima vez que usted ejecute \hgxcmd{mq}{qpush}. No
jerojasro@491 160 tiene ningún otro efecto; en particular, no hace nada a los parches
jerojasro@491 161 que ya han sido aplicados.
jerojasro@491 162
jerojasro@491 163 Sin argumentos, el comando \hgxcmd{mq}{qselect} lista los guardias en
jerojasro@491 164 efecto actualmente, uno por cada línea de salida. Cada argumento es
jerojasro@491 165 tratado como el nombre de un guardia a aplicar.
jerojasro@336 166 \interaction{mq.guards.qselect.foo}
jerojasro@491 167 Si está interesado, los guardias seleccionados actualmente están
jerojasro@491 168 almacenados en el fichero \sfilename{guards}.
jerojasro@336 169 \interaction{mq.guards.qselect.cat}
jerojasro@491 170 Podemos ver el efecto que tienen los guardias seleccionados cuando
jerojasro@491 171 ejecutamos \hgxcmd{mq}{qpush}.
jerojasro@336 172 \interaction{mq.guards.qselect.qpush}
jerojasro@336 173
jerojasro@491 174 Un guardia no puede empezar con un caracter ``\texttt{+}'' o
jerojasro@491 175 ``\texttt{-}''. El nombre del guardia no debe contener espacios en
jerojasro@491 176 blanco, pero muchos otros caracteres son aceptables. Si usted trata de
jerojasro@491 177 usar un guardia con un nombre inválido, MQ se quejará:
jerojasro@336 178 \interaction{mq.guards.qselect.error}
jerojasro@491 179 Cambiar los guardias seleccionados cambia los parches que son
jerojasro@491 180 aplicados.
jerojasro@336 181 \interaction{mq.guards.qselect.quux}
jerojasro@491 182 Usted puede ver en el ejemplo de abajo que los guardias negativos
jerojasro@491 183 tienen precedencia sobre los guardias positivos.
jerojasro@336 184 \interaction{mq.guards.qselect.foobar}
jerojasro@336 185
jerojasro@494 186 \section{Reglas de MQ para aplicar parches}
jerojasro@494 187
jerojasro@494 188 Las reglas que MQ usa para decidir si debe aplicar un parche son las
jerojasro@494 189 siguientes.
jerojasro@336 190 \begin{itemize}
jerojasro@494 191 \item Un parche sin guardias es aplicado siempre.
jerojasro@494 192 \item Si el parche tiene algún guardia negativo que corresponda con
jerojasro@494 193 cualquiera de los guardias seleccionados, se salta el parche.
jerojasro@494 194 \item Si el parche tiene algún guardia positivo que corresponda con
jerojasro@494 195 cualquiera de los guardias seleccionados, se aplica el parche.
jerojasro@494 196 \item Si el parche tiene guardias positivos o negativos, pero ninguno
jerojasro@494 197 corresponde con cualquiera de los guardias seleccionados, se salta
jerojasro@494 198 el parche.
jerojasro@336 199 \end{itemize}
jerojasro@336 200
jerojasro@494 201 \section{Podar el entorno de trabajo}
jerojasro@494 202
jerojasro@494 203 En el trabajo del controlador de dispositivo que mencioné
jerojasro@494 204 anteriormente, yo no aplico los parches a un árbol normal del kernel
jerojasro@494 205 de Linux. En cambio, uso un repositorio que sólo contiene una
jerojasro@494 206 instantánea de los ficheros fuente y de cabecera que son relevantes
jerojasro@494 207 para el desarrollo de Infiniband. Este repositorio tiene un~1\% del
jerojasro@494 208 tamaño del repositorio del kernel, por lo que es más fácil trabajar
jerojasro@494 209 con él.
jerojasro@494 210
jerojasro@494 211 Luego escojo una versión ``base'' sobre la cual son aplicados los
jerojasro@494 212 parches. Es una instantánea del árbol del kernel de Linux en una
jerojasro@494 213 revisión de mi elección. Cuando tomo la instantánea, almaceno el ID de
jerojasro@494 214 conjunto de cambios en el mensaje de consignación. Ya que la
jerojasro@494 215 instantánea preserva la ``forma'' y el contenido de las partes
jerojasro@494 216 relevantes del árbol del kernel, puedo aplicar mis parches sobre mi
jerojasro@494 217 pequeño repositorio o sobre un árbol normal del kernel.
jerojasro@494 218
jerojasro@494 219 Normalmente, el árbol base sobre el que se aplican los parches debería
jerojasro@494 220 ser una instantánea de un árbol de desarrollo muy reciente. Esto
jerojasro@494 221 facilita mucho el desarrollo de parches que puedan ser enviados al
jerojasro@494 222 árbol oficial con pocas o ninguna modificación.
jerojasro@494 223
jerojasro@494 224 \section{Dividir el fichero \sfilename{series}}
jerojasro@494 225
jerojasro@494 226 Yo categorizo los parches en el fichero \sfilename{series} en una
jerojasro@494 227 serie de grupos lógicos. Cada sección de parches similares empieza con
jerojasro@494 228 un bloque de comentarios que describen el propósito de los parches que
jerojasro@494 229 le siguen.
jerojasro@494 230
jerojasro@494 231 La secuencia de grupos de parches que mantengo se muestra a
jerojasro@494 232 continuación. El orden de los grupos es importante; explicaré porqué
jerojasro@494 233 luego de que presente los grupos.
jerojasro@336 234 \begin{itemize}
jerojasro@494 235 \item El grupo ``aceptado''. Son parches que el equipo de desarrollo
jerojasro@494 236 ha enviado al mantenedor del subsistema Infiniband, y que él ha
jerojasro@494 237 aceptado, pero que no están presentes en la instantánea en la cual
jerojasro@494 238 está basada el repositorio pequeño. Estos son parches de
jerojasro@494 239 ``sólo lectura'', presentes únicamente para transformar el árbol en
jerojasro@494 240 un estado similar al del repositorio del mantenedor oficial.
jerojasro@494 241 \item El grupo ``revisar''. Parches que yo he enviado, pero sobre los
jerojasro@494 242 que que el mantenedor oficial ha solicitado modificaciones antes de
jerojasro@494 243 aceptarlos.
jerojasro@494 244 \item El grupo ``pendiente''. Parches que no he enviado al mantenedor
jerojasro@494 245 oficial, pero que ya están terminados. Estos parches serán de
jerojasro@494 246 ``sólo lectura'' por un buen tiempo. Si el mantenedor oficial los
jerojasro@494 247 acepta cuando los envíe, los moveré al final del grupo ``aceptado''.
jerojasro@494 248 Si él solicita que modificaciones en alguno de ellos, los moveré al
jerojasro@494 249 principio del grupo ``revisar''.
jerojasro@494 250 \item El grupo ``en proceso''. Parches que están siendo activamente
jerojasro@494 251 desarrollados, y no deberían ser enviados a ninguna parte aún.
jerojasro@494 252 \item El grupo ``backport''. Parches que adaptan el árbol de fuentes a
jerojasro@494 253 versiones antiguas del árbol del kernel.
jerojasro@494 254 \item El grupo ``no enviar''. Parches que por alguna razón nunca deben
jerojasro@494 255 ser enviados al mantenedor oficial del kernel. Por ejemplo, alguno
jerojasro@494 256 de esos parches podría cambiar las cadenas de identificación
jerojasro@494 257 embebidas del controlador para hacer más fácil la distinción, en
jerojasro@494 258 pruebas de campo, entre una versión del controlador de
jerojasro@494 259 salida-del-árbol y una versión entregada por un vendedor de alguna
jerojasro@494 260 distribución.
jerojasro@336 261 \end{itemize}
jerojasro@336 262
jerojasro@494 263 Ahora volvemos a las razones para ordenar los grupos de parches en
jerojasro@494 264 esta manera. Quisiéramos que los parches del fondo de la pila sean tan
jerojasro@494 265 estables como sea posible, para no tener que revisar parches más
jerojasro@494 266 arriba debido a cambios de contexto. Poner los parches que nunca
jerojasro@494 267 cambiarán en el primer lugar del fichero \sfilename{series} sirve a
jerojasro@494 268 este propósito.
jerojasro@494 269
jerojasro@494 270 También desearíamos que los parches que sabemos que debemos modificar
jerojasro@494 271 sean aplicados sobre un árbol de fuentes que se parezca al oficial
jerojasro@494 272 tanto como sea posible. Es por esto que mantenemos los parches
jerojasro@494 273 aceptados disponibles por una buena cantidad de tiempo.
jerojasro@494 274
jerojasro@494 275 Los parches ``backport'' y ``no enviar'' flotan al final del fichero
jerojasro@494 276 \sfilename{series}. Los parches de backport deben ser aplicados encima
jerojasro@494 277 de todos los otros parches, y los parches ``no enviar'' pueden
jerojasro@494 278 perfectamente quedarse fuera del camino.
jerojasro@336 279
jerojasro@495 280 \section{Mantener la serie de parches}
jerojasro@495 281
jerojasro@495 282 En mi trabajo, uso varios guardias para controlar qué parches deben
jerojasro@495 283 ser aplicados.
jerojasro@336 284
jerojasro@336 285 \begin{itemize}
jerojasro@495 286 \item Los parches ``aceptados'' son vigilados con
jerojasro@495 287 \texttt{accepted}. Yo habilito este guardia la mayoría de las veces.
jerojasro@495 288 Cuando aplico los parches sobre un árbol donde los parches ya están
jerojasro@495 289 %TODO no será ``desactivar este guardia''? si sí, corregir versión
jerojasro@495 290 %en inglés también
jerojasro@495 291 presentes, puedo desactivar este parche, y los parches que lo siguen
jerojasro@495 292 se aplicarán sin problemas.
jerojasro@495 293 \item Los parches que están ``terminados'', pero no han sido enviados,
jerojasro@495 294 no tienen guardias. Si estoy aplicando la pila de parches a una
jerojasro@495 295 copia del árbol oficial, no necesito habilitar ningún guardia para
jerojasro@495 296 obtener un árbol de fuentes razonablemente seguro.
jerojasro@495 297 \item Los parches que necesitan revisión antes de ser reenviados
jerojasro@495 298 tienen el guardia \texttt{rework}.
jerojasro@495 299 \item Para aquellos parches que aún están bajo desarrollo, uso
jerojasro@336 300 \texttt{devel}.
jerojasro@495 301 \item Un parche de backport puede tener varios guardias, uno para cada
jerojasro@495 302 versión del kernel a la que aplica. Por ejemplo, un parche que hace
jerojasro@495 303 backport de un segmento de código a~2.6.9 tendrá un guardia~\texttt{2.6.9}.
jerojasro@336 304 \end{itemize}
jerojasro@495 305 La variedad de guardias me brinda una flexibilidad considerable para
jerojasro@495 306 determinar qué tipo de árbol de fuentes acabaré por obtener. En la
jerojasro@495 307 mayoría de las situaciones, la selección de guardias apropiados es
jerojasro@495 308 automatizada durante el proceso de compilación, pero puedo ajustar
jerojasro@495 309 manualmente los guardias a usar para circunstancias poco comunes.
jerojasro@336 310
jerojasro@497 311 \subsection{El arte de escribir parches de backport}
jerojasro@497 312
jerojasro@497 313 Al usar MQ, escribir un parche de backport es un proceso simple. Todo
jerojasro@497 314 lo que dicho parche debe hacer es modificar una sección de código que
jerojasro@497 315 usa una característica del kernel que no está presente en la versión
jerojasro@497 316 anterior del kernel, para que el controlador siga funcionando
jerojasro@497 317 correctamente en esa versión anterior.
jerojasro@497 318
jerojasro@497 319 Una meta útil al escribir un buen parche de backport es hacer parecer
jerojasro@497 320 que el código hubiera sido escrito para la versión vieja del kernel
jerojasro@497 321 que usted tiene como objetivo. Entre menos intrusivo el parche, más
jerojasro@497 322 fácil será entenderlo y mantenerlo. Si usted está escribiendo una
jerojasro@497 323 colección de parches de backport para evitar el efecto de ``nido de
jerojasro@497 324 ratas'' de tener muchos \texttt{\#ifdef}s (secciones de código fuente
jerojasro@497 325 que sólo son usados condicionalmente) en su código, no introduzca
jerojasro@497 326 \texttt{\#ifdef}s dependientes de versiones específicas en los
jerojasro@497 327 parches. En vez de eso, escriba varios parches, cada uno de ellos
jerojasro@497 328 haciendo cambios incondicionales, y controle su aplicación usando
jerojasro@497 329 guardias.
jerojasro@497 330
jerojasro@497 331 Hay dos razones para ubicar los parches de backport en un grupo
jerojasro@497 332 diferente, aparte de los parches ``regulares'' cuyos efectos son
jerojasro@497 333 modificados por ellos. La primera es que mezclar los dos hace más
jerojasro@497 334 difícil usar herramientas como la extensión \hgext{patchbomb} para
jerojasro@497 335 automatizar el proceso de enviar los parches a un mantenedor oficial.
jerojasro@497 336 La segunda es que un parche de backport puede perturbar el contexto en
jerojasro@497 337 el que se aplica un parche regular subsecuente, haciendo imposible
jerojasro@497 338 aplicar el parche normal limpiamente \emph{sin} que el parche de
jerojasro@497 339 backport sea aplicado antes.
jerojasro@336 340
jerojasro@498 341 \section{Consejos útiles para hacer desarrollo con MQ}
jerojasro@498 342
jerojasro@498 343 \subsection{Organizar parches en directorios}
jerojasro@498 344
jerojasro@498 345 Si está trabajando en un proyecto grande con MQ, no es difícil
jerojasro@498 346 acumular un gran número de parches. Por ejemplo, tengo un repositorio
jerojasro@498 347 de parches que contiene más de 250 parches.
jerojasro@498 348
jerojasro@498 349 Si usted puede agrupar estos parches en categorías lógicas separadas,
jerojasro@498 350 usted puede almacenarlos en diferentes directorios si lo desea; MQ no
jerojasro@498 351 tiene problemas manejando nombres de parches que contienen separadores
jerojasro@498 352 de ruta.
jerojasro@498 353
jerojasro@516 354 \subsection{Ver el historial de un parche}
jerojasro@336 355 \label{mq-collab:tips:interdiff}
jerojasro@336 356
jerojasro@498 357 Si usted está desarrollando un conjunto de parches en un período de
jerojasro@498 358 tiempo grande, es una buena idea mantenerlos en un repositorio, como
jerojasro@498 359 se discutió en la sección~\ref{sec:mq:repo}. Si lo hace, notará
jerojasro@516 360 rápidamente que usar el comando \hgcmd{diff} para mirar el historial
jerojasro@498 361 del repositorio no es viable. Esto es debido en parte a que usted está
jerojasro@498 362 mirando la segunda derivada del código real (el diff de un diff), pero
jerojasro@498 363 también porque MQ añade ruido al proceso al modificar las marcas de
jerojasro@498 364 tiempo y los nombres de directorio cuando actualiza un parche.
jerojasro@498 365
jerojasro@498 366 Sin embargo, usted puede usar la extensión \hgext{extdiff}, que es
jerojasro@498 367 provisto junto con Mercurial, para convertir un diff de dos versiones
jerojasro@498 368 de un parche en algo legible. Para hacer esto, usted necesitará un
jerojasro@498 369 paquete de un tercero llamado
jerojasro@498 370 \package{patchutils}~\cite{web:patchutils}. Éste paquete provee un
jerojasro@498 371 comando llamado \command{interdiff}, que muestra las diferencias entre
jerojasro@498 372 dos diffs como un diff. Al usarlo en dos versiones del mismo diff,
jerojasro@498 373 genera un diff que representa el diff de la primera a la segunda
jerojasro@498 374 versión.
jerojasro@498 375
jerojasro@498 376 Usted puede habilitar la extensión \hgext{extdiff} de la manera usual,
jerojasro@498 377 añadiendo una línea a la sección \rcsection{extensions} de su \hgrc.
jerojasro@336 378 \begin{codesample2}
jerojasro@336 379 [extensions]
jerojasro@336 380 extdiff =
jerojasro@336 381 \end{codesample2}
jerojasro@498 382 El comando \command{interdiff} espera recibir los nombres de dos
jerojasro@498 383 ficheros, pero la extensión \hgext{extdiff} le pasa un par de
jerojasro@498 384 directorios al programa que ejecuta, cada uno de los cuales puede
jerojasro@498 385 contener una cantidad arbitraria de ficheros. Por esto necesitamos un
jerojasro@498 386 programa pequeño que ejecute \command{interdiff} en cada par de
jerojasro@498 387 ficheros de estos dos directorios. Este programa está disponible como
jerojasro@498 388 \sfilename{hg-interdiff} en el directorio \dirname{examples} del
jerojasro@498 389 repositorio de código fuente que acompaña a este libro.
jerojasro@336 390 \excode{hg-interdiff}
jerojasro@336 391
jerojasro@498 392 Con el programa \sfilename{hg-interdiff} en la ruta de búsqueda de su
jerojasro@498 393 intérprete de comandos, puede ejecutarlo como sigue, desde dentro de
jerojasro@498 394 un directorio de parches MQ:
jerojasro@336 395 \begin{codesample2}
jerojasro@336 396 hg extdiff -p hg-interdiff -r A:B my-change.patch
jerojasro@336 397 \end{codesample2}
jerojasro@498 398 Ya que usted seguramente querrá usar este comando tan largo a menudo,
jerojasro@498 399 puede hacer que \hgext{hgext} lo haga disponible como un comando
jerojasro@498 400 normal de Mercurial, editando de nuevo su \hgrc.
jerojasro@336 401 \begin{codesample2}
jerojasro@336 402 [extdiff]
jerojasro@336 403 cmd.interdiff = hg-interdiff
jerojasro@336 404 \end{codesample2}
jerojasro@498 405 Esto le indica a \hgext{hgext} que ponga a disposición un comando
jerojasro@498 406 \texttt{interdiff}, con lo que usted puede abreviar la invocación
jerojasro@498 407 anterior de \hgxcmd{extdiff}{extdiff} a algo un poco más manejable.
jerojasro@336 408 \begin{codesample2}
jerojasro@336 409 hg interdiff -r A:B my-change.patch
jerojasro@336 410 \end{codesample2}
jerojasro@336 411
jerojasro@336 412 \begin{note}
jerojasro@498 413 %TODO revisar redacción
jerojasro@498 414 El comando \command{interdiff} trabaja bien sólo si los ficheros
jerojasro@498 415 contra los cuales son generadas las versiones de un parche se
jerojasro@498 416 mantienen iguales. Si usted crea un parche, modifica los ficheros
jerojasro@498 417 subyacentes, y luego regenera el parche, \command{interdiff} podría
jerojasro@498 418 no producir ningún resultado útil.
jerojasro@336 419 \end{note}
jerojasro@336 420
jerojasro@498 421 La extensión \hgext{extdiff} es útil para más que solamente mejorar la
jerojasro@498 422 presentación de los parches~MQ. Para leer más acerca de esto, vaya a
jerojasro@498 423 la sección~\ref{sec:hgext:extdiff}.
jerojasro@336 424
jerojasro@336 425 %%% Local Variables:
jerojasro@336 426 %%% mode: latex
jerojasro@336 427 %%% TeX-master: "00book"
jerojasro@336 428 %%% End: