¿Puedo obtener una salida compatible con parches de git-diff?

160

Estoy haciendo algo muy simple mal. Estoy tratando de preparar un archivo de revisión normal, para poder volver a aplicar algunos cambios:

$ git diff > before
$ git diff something_here > save.patch
$ git checkout . 
$ patch < save.patch
$ git diff > after
$ diff before after
$

Con el something_here espacio en blanco casi funciona, pero los nombres de los archivos no son correctos. Creo que solo me falta alguna opción.

En la vida real, voy a hacer una fusión después del pago, por lo que el parche puede fallar allí, pero ya ves a lo que me refiero.

Edite Mi culpa aquí por hacer la pregunta incorrecta. La pregunta real es, ¿quiero guardar mis cambios, hacer una fusión y luego volver a aplicar los cambios, si es posible? Lo pregunté de manera incorrecta porque estoy acostumbrado a usar parches para resolver este tipo de problemas y git diffparecía que eso era lo que quería que hiciera.

El comentario de Charles Bailey tuvo la respuesta correcta. Para mí, git-apply es lo correcto (git-stash parece más pesado de lo que necesito y el rebase y los paquetes definitivamente están más allá de mi nivel de habilidad actual). Voy a aceptar la respuesta que Charles dio (porque usted No puedo aceptar un comentario). Gracias por todas las sugerencias.

Editar, 6 años después Como sabe cualquier persona familiarizada con el tema, sobreestimé la dificultad de git stash. Casi todos los días más o menos, usaré la siguiente secuencia:

$ git stash
$ git merge
$ git stash pop
Malvolio
fuente
8
¿Hay alguna razón que específicamente quieras usar en patchlugar de git apply?
CB Bailey
3
E incluso entonces, ¿realmente necesitas parches en lugar de algo así como git stashotras herramientas de git?
CB Bailey
3
Después de la edición, creo que git stashes la solución más fácil para lo que está tratando de hacer, pero hay muchos enfoques que funcionan.
CB Bailey
1
@Malvolio: De hecho, ni siquiera tiene que pensar en un nombre de archivo temporal para almacenar su parche.
CB Bailey
44
@Charlse, a veces necesitas enviar un parche a alguien sin todo el repositorio de git. Por ejemplo si está usando git-svn.
Elazar Leibovich

Respuestas:

139

Si desea usar el parche, debe eliminar los a/ b/prefijos que usa git de forma predeterminada. Puede hacerlo con la --no-prefixopción (también puede hacerlo con la -popción de parche ):

git diff --no-prefix [<other git-diff arguments>]

Por lo general, sin embargo, es más fácil usarlo directamente git diffy luego usar la salida para alimentarlo git apply.

La mayoría de las veces trato de evitar el uso de parches textuales. Por lo general, una o más confirmaciones temporales combinadas con rebase git stashy paquetes son más fáciles de administrar.

Para su caso de uso, creo que stashes lo más apropiado.

# save uncommitted changes
git stash

# do a merge or some other operation
git merge some-branch

# re-apply changes, removing stash if successful
# (you may be asked to resolve conflicts).
git stash pop
CB Bailey
fuente
77
git diff --no-prefix master > diff.patchy luegogit checkout master patch -p0 < diff.patch
Natim
1
@Natim Para mayor seguridad, recomendaría usar patch --dry-run < diff.patchantes de emitir el último comando.
ᴠɪɴᴄᴇɴᴛ
1
@ ᴠɪɴᴄᴇɴᴛ ¿Cuál sería el beneficio de hacer eso? Dado que estamos usando git, es poco probable que perdamos algo, ¿no?
Natim
1
@Natim Como dije, solo por la máxima seguridad, no es necesario deshacer nada en caso de error. También estaba pensando en las personas que leen esto y quieren usar patchfuera de git (tal vez usando un archivo de parche generado por diff) en un caso de uso más general.
ᴠɪɴᴄᴇɴᴛ
Con el fin de incluir nuevos archivos en el parche que necesita también incluye "git diff --no-prefijo --cached" en el parche. Tal vez hay una mejor manera?
jamshid
219

Solo use -p1: de todos modos, deberá usar -p0el --no-prefixestuche, por lo que puede omitir --no-prefixy usar -p1:

$ git diff > save.patch
$ patch -p1 < save.patch

$ git diff --no-prefix > save.patch
$ patch -p0 < save.patch
ndim
fuente
1
Si te estás preguntando por qué, el hombre documenta lo resume muy bien - fuente .
tutuDajuju
3
Esto no funcionará con cambios de nombre; git diffgenera una línea que patchignora. git applyEs el camino a seguir.
hraban
17

Los git diffs tienen un segmento de ruta adicional antepuesto a las rutas de archivo. Puede quitar esta entrada en la ruta especificando -p1 con parche, así:

patch -p1 < save.patch
Henrik Gustafsson
fuente
10
  1. Guardo el diff del directorio actual (incluidos los archivos no confirmados) contra el HEAD actual.
  2. Luego puede transportar el save.patcharchivo a cualquier lugar (incluidos los archivos binarios).
  3. En su máquina de destino, aplique el parche usando git apply <file>

Nota: también son los archivos almacenados actualmente.

$ git diff --binary --staged HEAD > save.patch
$ git reset --hard
$ <transport it>
$ git apply save.patch
Matej
fuente
Jajaja. Eso es gracioso. Hice esta pregunta hace casi cuatro años y la forma en que lo he hecho ha evolucionado, pero si me hubieras preguntado ayer cómo hacerlo, te habría dado tu respuesta y te habría dicho que la obtuve de las respuestas a esta pregunta. (En realidad, probablemente usaría un simple git diff > save.patchy en git checkout .lugar de un reinicio, pero sí ...
Malvolio
Oh, no noté que tenía 4 años: P. Por cierto, el restablecimiento es solo para demostrar que funciona. Tampoco veo a nadie usando git applyo haciendo que el diff sea relevante para su estado y el puntero a la última confirmación disponible. Hacer simplemente git diffno ha hecho nada en absoluto
Matej
Sí, ahora me pregunto cómo me enteré git apply. Lo que pasa git diffes (creo) el uso git reset: las relaciones entre el repositorio, el índice y el área de trabajo son el problema.
Malvolio
8

Un truco útil para evitar crear archivos de parches temporales:

git diff | patch -p1 -d [dst-dir]
comienzo lento
fuente
Exactamente lo que quería. ¡También funciona perfectamente con escondites! git stash show -p stash@{3} | patch -p1 -d [dst-dir]
dtmland