hgbook
annotate es/mq-collab.tex @ 519:a529952fce96
changed "un tag" to "una etiqueta". Same thing for
"unos tags"
"un tag"
"el tag"
"los tags"
"de tag"
"de tags"
"unos tags"
"un tag"
"el tag"
"los tags"
"de tag"
"de tags"
author | Javier Rojas <jerojasro@devnull.li> |
---|---|
date | Sun Jan 18 22:21:43 2009 -0500 (2009-01-18) |
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: |