Recientemente 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
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 modificar
¿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 😉
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!
Me gustaMe gusta
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
Me gustaMe gusta
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
Me gustaMe gusta
Perdona el retraso 😉 He estado liado estos días y no me ha dado tiempo a hacer el banner 😉
Se agradece que estes suscrito al rss, espero que te gusten los nuevos artículos que estoy haciendo para estos días.
La url del banner para copiarlo es:

Por mi parte me he tomado la libertad de añadirte también a mi blogroll.
Saludos
Me gustaMe gusta
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 😛
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 🙂
Me gustaMe gusta
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 ;))
Me gustaMe gusta
Gracias eso necesitaba saber 🙂
Me gustaMe gusta
Muy sencillo y entendible.
Gracias por compartirlo.
Me gustaMe gusta
Gracias por compartir!
Me gustaMe gusta
Muchas gracias 🙂
¿Sabes cómo hacer para añadir más de un fichero a la vez en el mismo parche? Se que se hace pero no lo consigo
Me gustaMe gusta
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
Me gustaMe gusta
Gracias por tan pronta respuesta, pero me refería a cómo usar diff para crear un .patch con más de un fichero parcheado a la vez
Gracias
Me gustaMe gusta
Eso me requeriría algo más de espacio que un comentario; puedes buscar en Internet pues seguro que ya hay información sobre el tema.
Si no es suficiente dímelo y te dedico el próximo artículo 😉
Me gustaMe gusta
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 🙂
Me gustaMe gusta
¿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
Me gustaMe gusta
Se puede con directorios, por lo mismo, en linux odo es un fichero.
Me gustaMe gusta
Gran verdad… hasta dispositivos como las tarjetas de sonido tienen asociado un fichero 😉
Me gustaMe gusta
Hola, al fin un pajarito me dijo cómo hacerlo. Se hace con cat
Ejemplo
cat parche1.patch parche2.patch > parcheunion.patch
Así de sencillo es 😉
Me gustaMe gusta
Muchas gracias por la información, me ha sido de gran utilidad la accesible descripción del uso de los comandos.
Me gustaMe gusta
Me alegra que te haya sido de utilidad.
Un placer poder ayudar
Me gustaMe gusta
La forma de hacer lo mismo con directorios es la siguiente:
diff -Pur carpeta_vieja carpeta_nueva > parche.patch
El parámetro -P es para que agregue al parche los archivos que solo existen en uno de los directorios y el -r es para comparar recursivamente ambos directorios.
En la man de diff también se puede encontrar otras opciones igual de útiles.
Me gustaMe gusta