Crear y aplicar parches (patches) en Linux

nullRecientemente he estado modificando un driver para la tarjeta GemPlus PC400 (acá GPR400) de modo que siga funcionando en Ubuntu Jaunty.

Como es de bien nacidos ser agradecidos, he querido enviar al autor de la versión original del driver los cambios necesarios para adaptarlo a la nueva versión del sistema operativo (la que tenía se quedaba en Ubuntu Hardy y han cambiado algunas cosas en el kernel que impedían que siguiese funcionando).

Para poder enviarle las modificaciones sobre el código fuente original he tenido que crear un patch y, a modo de recordatorio o chuleta, he optado por publicar el siguiente post (se que hay n-cientos artículos sobre el tema en Internet pero éste es el mio ;))

Crear un patch en Linux

Para ello utilizaremos el comando diff del siguiente modo

diff -u viejo.txt nuevo.txt > cambios.patch

donde

  • viejo.txt y nuevo.txt son el fichero original (viejo.txt) y la versión que resulta de realizar los cambios que resulten oportunos (nuevo.txt)
  • cambios.patch gracias a la redirección (>) es el fichero donde se almacenarán los cambios que deben realizarse sobre viejo.txt para obtener nuevo.txt (si no se utiliza la redirección, los cambios aparecerán única y exclusivamente en pantalla)
  • -u permite generar “información de contexto” que facilite (a un humano) entender los cambios que se han realizado sobre viejo.txt (opcional pero muy recomendable utilizarlo)

Aplicar un “remiendo” o patch

Lo más sencillo es ejecutar un

patch < cambios.patch

¿Sobre qué fichero realizará el cambio?

Si abres con un simple editor de textos el fichero cambios.txt (si has utilizado el parámetro -u que comentamos anteriormente) descubrirás que en él se indica el fichero a utilizar
null

En concreto nos interesa la primera línea donde se indica (con los signos ---) que el fichero a modificar es viejo.txt.

¿Qué ocurre si la ubicación del fichero no coincide?

Es posible que el directorio en el que el autor tiene almacenado el fichero no coincida con el tuyo (o incluso el nombre podría ser distinto).

En dicho caso el comando preguntará la ruta del fichero a modificarnull

¿Cómo adaptar la ruta al fichero?

Si no quieres tener que escribir nada en la terminal siempre puedes editar el fichero cambios.patch para que apunte al fichero (y directorio) adecuados.

Como dicha solución resulta algo “cutre” los padres del comando patch han optado por incluir (entre otros) el parámetro -p que permite indicar el número de subdirectorios (de la ruta al fichero) que deseamos eliminar.

Así lanzando patch con -p0

patch -p0 < cambios.patch

al eliminar 0 directorios utilizará la ruta completa al fichero (es equivalente a no utilizar el -p); en el ejemplo dicha ruta sería

/tmp/blogcrearpatchsyaplicarlosenlinux/viejo.txt

Utilizando -p1

patch -p1 < cambios.patch

eliminará el primer directorio (/tmp) quedando la ruta

blogcrearpatchsyaplicarlosenlinux/viejo.txt

Utilizando -p2

patch -p2 < cambios.patch

eliminaría los dos primeros directorios (/tmp/blogcrearpatchsyaplicarlosenlinux/) quedando como ruta única y exclusivamente el nombre del fichero (porque no hay más directorios que si no seguirían apareciendo ;))

viejo.txt

Conclusión

Una muy útil herramienta que permite generar un fichero con los cambios que se realizan sobre un archivo (sea binario o no).

Si alguien lo considera interesante que lo indique en los comentarios y publico un artículo explicando cómo interpretar el contenido del fichero cambios.patch.

Os puedo asegurar que una vez que se le coge el truco es realmente interesante el partido que se le puede llegar a sacar ;)

23 thoughts on “Crear y aplicar parches (patches) en Linux

  1. Pingback: Bitacoras.com
  2. Maanuel dijo:

    Waaa genial, siempre quise aprender algo sobre este comando… lo único que hacía era aplicar lo que leía en las guías, pero ahora sé lo que hace ;)

    Bueno, sería estupendo si puedes hacer ese artículo que mencionas…. como para enterarse de que va hacer el dichoso parche antes de aplicarlo.

    Saludos!

  3. Muy buen manual/chuleta. Yo le he utilizado un par de veces para mandar parches de traducción para la página de Wine. También es muy util utilizando bajo sistemas de control de versiones como Git.

    Realmente aprendiendote 10 o 15 comandos puedes hacer muy buenas cosas con git y patch.

    Saludos

    • Eres una auténtica caja de sorpresas @Shak [me alegra saber que colaboras activamente con proyectos open-source aunque se trate de Wine :P]

      Por cierto, hacia tiempo que no pasaba por tu blog y me ha sorprendido gratamente tanto la estética como el contenido (enhorabuena).

      Para que no vuelva a ocurrirme te incluyo en mi lector de RSS [ y si me envías una imagen "chula" de dimensiones similares a las de mi blogroll te meto en él ;) ]

      Un saludo compañero

  4. zuargo dijo:

    Excelente, excelente entrada, yo suelo instalar versiones svn de los programas para tener lo último de lo último, y casi siempre aparecen parches para corregir algunos errores entes de que salga la nueva revisión del programa. Nunca supe acerca de ese comando “patch”. Siempre aplicaba los cambios (contenidos en el archivo .patch) de forma manual, es decir, copiar y pegar :P

    Una duda, si aplico un parche con el comando .patch a un archivo de una versión svn de un programa, al momento de hacer “svn up” ¿me dará algún error? lo que pasa es que cuando aplicaba los parches de forma manual siempre me decía que el fichero que había editado no era el mismo que estaba en los ¿repositorios svn? (¿se dice así o no?) y entonces me hacía unas preguntas el sistema que realmente no me di el tiempo de entender xD.

    Agradecería mucho que me pudieras responder.

    Gracias :)

    • Si he entendido bien andas buscando hacer un update con el repositorio SVN. ¿es así?

      En dicho caso, si has cambiado el contenido que tienes en local (aplicando un parche o editando su contenido) es normal que te indique que no coincide con la versión existente en el servidor. Está en tu mano seguir adelante (perdiendo lo que tienes en local) o sincronizar manualmente tu fichero (el local) con lo que hay en el servidor (para esto te sería muy útil entender el contenido de los ficheros patch que, como indicas, parece que controlas ;))

    • Crea un fichero con las rutas a los ficheros que quieres “parchear” (imaginemos que se llama misParches.patch) y utiliza el parámetro -i del siguiente modo

      patch -p0 -i misParches.patch

      Espero te sea de utilidad, un saludo @Cristobal

  5. Hola de nuevo, pues nada que no hay forma, he mirado ya muchos enlaces, la ayuda de diff pero no me sale. Es lo único que me queda por saber para aplicar parches cuando creo paquetes deb y rpm.
    Lo único que he conseguido es unir dos ficheros .patch en un uno con el comando merge pero me los une por columnas y no me sirve :-(

    Muchas gracias :-)

    • ¿has probado a utilizar la misma técnica que se indica en el artículo (diff -u) pero indicando dos directorios en lugar de los ficheros a comparar?

      Ten en cuenta que en linux TODO son archivos (incluido los dispositivos como teclados, tarjetas de sonido, …) ;)

      Mantenme informado, últimamente no ando con demasiado tiempo y, aunque me interesa, el tema no he podido hacerte la prueba personalmente :(

      Perdona y un saludo

Deja un comentario

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s