Código FuenteAhora que vamos avanzando en el proyecto Pascaline se ve la necesidad de mandar correcciones al código a la lista y formas más eficientes de enviarnos la información. Para aprender a manejarse con los parches he escrito un pequeño cursito.

Introducción

En los proyectos de software, es común la continua realización de cambios al código y la documentación para hacer mejoras o corregir fallos. El uso de parches es un método muy eficaz para transmitir y mostrar dichos cambios, y en este curso se explica cómo trabajar con ellos.

NOTA:
En las rutas de archivos y en la línea de comandos se utiliza la convención Unix, con “$” como símbolo de la línea de comandos y “/” como separador de directorios dentro de una ruta, que equivalen al símbolo “>” y “\” de Windows. (p.e. “$ dir” -> “> dir” y “programa/a.txt” -> “programa\a.txt”)

Qué es un parche y para qué sirve

Un parche es un archivo que recoge los cambios necesarios para pasar de un archivo “original” y un archivo “modificado”.

Por ejemplo:

original/a.txt (original):
linea 0
linea A
linea B

modificaciones/b.txt (modificado):
linea 0
linea B
linea C
linea D

el parche que recoge los cambios que convierten a.txt en b.txt es:

--- original/a.txt 2006-08-10 13:51:46.000000000 +0200
+++ modificaciones/b.txt 2006-08-10 13:51:55.000000000 +0200
@@ -1,3 +1,4 @@
linea 0
-linea A
linea B
+linea C
+linea D

Más adelante explicaremos qué significa cada una de las partes de este parche.

Con un poco de práctica, el uso de parches hace más sencillo el intercambio y la revisión de modificaciones, además de dar una idea más acertada que la simple inspección visual de la magnitud de los cambios que se producen entre las diferentes versiones de un archivo.

También facilita la separación de los cambios en conjuntos coherentes y “ortogonales”. Un parche puede corregir una errata, otro añadir una nueva funcionalidad, otro arreglar un fallo concreto, etc… de forma que se puede decidir aplicarlos todos (uno tras otro), aplicar solamente alguno de ellos, descartar alguno por incorrecto, etc. La utilización de parches “pequeños” que actúen sobre problemas específicos es una buena práctica que dificulta la introducción de errores de forma inadvertida.

Herramientas para generar y aplicar parches

Algunas herramientas, como ‘diff’ y ‘patch’, permiten generar y aplicar parches de forma automática, de manera que se evita el tedio de localizar manualmente los cambios y trasladarlos de una versión a otra.

La instalación de ‘diff’ y ‘patch’ es trivial en cualquier sistema GNU/Linux con las herramientas habituales (apt, rpm, synaptics…). Los paquetes relevantes son ‘diffutils’ y ‘patch’, aunque es probable que ya se encuentren instalados por defecto.

En Windows se pueden descargar binarios [1][2] compilados para esa plataforma, que se usan desde la línea de comandos. Es conveniente incluir la ruta de estos programas en la ruta por defecto del sistema (variable PATH) para evitar tener que escribir continuamente la ruta completa cada vez que se usan.

El proyecto Mingw [3] incluye muchas de estas aplicaciones empaquetadas conjuntamente con otras del entrono de desarrollo de GNU/Linux.

[1] http://gnuwin32.sourceforge.net/packages/patch.htm
[2] http://gnuwin32.sourceforge.net/packages/diffutils.htm
[3] http://www.mingw.org/

Ahora que hemos visto cómo instalar en nuestro sistema las herramientas necesarias, veremos cómo utilizarlas y para qué sirven.

diff

La aplicación ‘diff’ muestra las diferencias entre el archivo “original” y el “modificado”. Admite opciones que permiten hacer más legible el registro de cambios, por ejemplo, incorporando algo de contexto a los cambios (la opción más habitual es -u (formato unificado), pero depende de las políticas de cada proyecto).

Para generar el parche anterior se ejecutó en la línea de comandos:

$ diff -u a.txt b.txt

que produce la siguiente salida:

--- original/a.txt 2006-08-10 13:51:46.000000000 +0200
+++ modificaciones/b.txt 2006-08-10 13:51:55.000000000 +0200
@@ -1,3 +1,4 @@
linea 0
-linea A
linea B
+linea C
+linea D

Si redirigirmos la salida a un archivo ya tenemos un parche con los cambios (cambios.diff):

$ diff -u original/a.txt modificaciones/b.txt > cambios.diff

Información contenida en un parche

Hemos visto que la herramienta diff incluye algunos datos que no se encontraban en los archivos que compara:

--- original/a.txt 2006-08-10 13:51:46.000000000 +0200
+++ modificaciones/b.txt 2006-08-10 13:51:55.000000000 +0200
@@ -1,3 +1,4 @@
linea 0
-linea A
linea B
+linea C
+linea D

Esa información adicional aporta metadatos sobre los cambios, útiles para conocer el contexto, la procedencia de los datos y la localiza
Las primeras dos líneas de la salida que produce diff indican la ruta relativa (desde donde se hace el parche) y el nombre de los archivos que se comparan, y otros datos como la fecha de modificación, hora…

Ha de advertirse que, para las obtención de diferencias entre archivos, es significativo el órden. No es idéntica la diferencia entre a.txt y b.txt que la diferencia entre b.txt y a.txt.

La tercera línea encabeza un conjunto de cambios e informa acerca del fragmento (en a.txt y b.txt) en el que se han encontrado cambios, y se muestran a continuación en el parche. En nuestro ejemplo se indica que las líneas afectadas son las líneas 1 a 3 del archivo a.txt y las líneas 1 a 4 del archivo b.txt. Pueden aparecer varios de estos fragmentos en un mismo parche, con su encabezado correspondiente.

Dentro de cada uno de estos fragmentos, y a continuación del encabezado, se prefijan con un ‘-‘ las líneas eliminadas de a.txt (que no aparecen en b.txt) y se prefijan con un ‘+’ las líneas insertadas en b.txt (que no aparecen en a.txt).

-linea A < — se elimina (-) esta línea
+linea C < — se añade (+) esta línea
+linea D < — se añade (+) esta línea

Las líneas sin prefijo simplemente muestran parte del contexto de los cambios, para facilitar la lectura del parche. Estas líneas no representan cambios en los archivos, sino simplemente partes comunes que rodean las zonas de cambio.

Ya sabemos, pues, cómo se genera y qué significa el contenido de un parche.

Aplicación y reversión de cambios

Una vez guardada en un parche la información de los cambios parar transformar un archivo a.txt en otro b.txt, ¿qué hacemos con esa información?.

Puesto que en el parche se dispone de la información necesaria, es posible generar b.txt a partir de a.txt y el parche. Para ello se usa otra herramienta llamada ‘patch’ (es la que ha dado nombre a los parches=patches).

patch

La aplicación ‘patch’ aplica un conjunto de cambios generado por diff a un archivo para obtener el archivo modificado.

Simplemente se le debe enviar por la entrada estándar el archivo que contiene los cambios (el parche).

En nuestro ejemplo:

$ patch < cambios.diff

Con esta simple acción patch localiza a.txt (tiene en la cabecera la ruta) y aplica los cambios, dejando el archivo como b.txt. Hay que aclarar que el archivo a.txt no se renombra, sino que simplemente contiene lo mismo que contenía b.txt.

Hay que tener en cuenta que se debe aplicar el parche en el mismo nivel de directorio que se usó para generar el parche (es posible modificar esto con la opción -p, pero es más sencillo así). Normalmente se usa el directorio raíz del proyecto para generar y aplicar los parches y así no tener que consultar la posición del archivo y la ruta del parche.

Otra operación útil es la reversión de los cambios que produce un parche (es decir, volver de b.txt a a.txt deshaciendo los cambios indicados en el parche). Para ello simplemente se usa la opción -R de ‘patch’.

$ patch -R < cambios.diff

Trabajo con parches

En los proyectos de software libre es habitual la comunicación mediante listas de correo en las que se comenta y revisa el código entre las distintas personas que participan en el proyecto.

Se deben señalar algunas buenas prácticas para colaborar de esa manera:

  • El asunto del correo debe corresponder al contenido del mensaje
  • Cuando se quiera comentar el contenido de otro correo se debe responder al mismo en el cliente de correo (no crear un correo nuevo con el mismo tema) de forma que se pueda seguir el hilo en los clientes que soporten la visualización de conversaciones.
  • El código se comenta en línea (pegando el código) aunque se adjuntan parches para cada uno de las cuestiones tratadas que sean conceptualmente distintas. Así, si se deciden integrar dichos cambios, se puede elegir cuáles son relevantes, cuáles necesitan más trabajo, o dejar algunos sin aplicar.

Otros recursos en la red

http://www.gnu.org/software/diffutils/manual/html_mono/diff.html
http://www.infres.enst.fr/~blanch/howto/DiffPatch.html
http://www.linuxjournal.com/article/1237

Copyright ©, Rafael Villar Burke, agosto 2006
Se permite la distribución, copia y modificación del texto, siempre y cuando se conserve el copyright y esta nota.