¿Cómo aplastas los commits en un parche con git format-patch?


163

Tengo ocho confirmaciones en una rama que me gustaría enviar por correo electrónico a algunas personas que aún no están iluminadas. Hasta ahora, todo lo que hago me da 8 archivos de parche o comienza a darme archivos de parche para cada confirmación en la historia de la rama, desde el principio de los tiempos. Usé git rebase --interactive para aplastar los commits, pero ahora todo lo que intento me da millones de parches desde el principio de los tiempos. ¿Qué estoy haciendo mal?

git format-patch master HEAD # yields zillions of patches, even though there's 
                             # only one commit since master

Tengo curiosidad sobre qué método terminarás usando entre las siguientes proposiciones. Háganos saber;)
VonC

44
Usaré git diff como lo sugirió Rob Di Marco. Pero estuve fuera del trabajo por dos semanas, después de haber presenciado el nacimiento de mi segunda bebé anoche, ¡así que pasará un tiempo antes de que lo use! :)
skiphoppy

2
Me encantaría ver git format-patch --squash master HEAD
schoetbi

1
Pruebe master..HEAD para especificar un rango de revoluciones.
Konrad Kleine

Respuestas:


186

Recomiendo hacer esto en una rama desechable de la siguiente manera. Si sus confirmaciones están en la rama "líneas nuevas" y ya ha cambiado a su rama "maestra", esto debería ser el truco:

[adam@mbp2600 example (master)]$ git checkout -b tmpsquash
Switched to a new branch "tmpsquash"

[adam@mbp2600 example (tmpsquash)]$ git merge --squash newlines
Updating 4d2de39..b6768b2
Fast forward
Squash commit -- not updating HEAD
 test.txt |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

[adam@mbp2600 example (tmpsquash)]$ git commit -a -m "My squashed commits"
[tmpsquash]: created 75b0a89: "My squashed commits"
 1 files changed, 2 insertions(+), 0 deletions(-)

[adam@mbp2600 example (tmpsquash)]$ git format-patch master
0001-My-squashed-commits.patch

¡Espero que esto ayude!


2
Esto es lo que uso cuando quiero mantener el historial localmente (en caso de que necesite editar el parche). De lo contrario, solo uso rebase -i y aplastar los commits.
sebnow

55
para mí, funcionó de manera más confiable, de lo git comit -m "My squashed commits"contrario agregaría otros archivos sin seguimiento
Sebastian

Además, puede cambiar a un commit específico en lugar del master y hacer esto para crear un parche de commit a commit:git checkout 775ec2a && git checkout -b patch && git merge --squash branchname
Berry M.

131

Solo para agregar una solución más al bote: si usa esto en su lugar:

git format-patch master --stdout > my_new_patch.diff

Entonces todavía habrá 8 parches ... pero todos estarán en un solo archivo de parche y se aplicarán como uno con:

git am < my_new_patch.diff

13
Me gusta esta solución Vale la pena notar que a veces puede crear un parche mucho más grande que el método descrito por @Adam Alexander. Esto se debe a que algunos archivos pueden editarse más de una vez a través de confirmaciones. Este método trata cada confirmación por separado, incluso si se revierte algún archivo. Pero la mayoría de las veces esto no es un problema.
gumik

1
¡Esta opción es excelente si estás tratando de evitar la fusión! (por ejemplo, desea omitir algunas confirmaciones). Todavía puedes git rebase -i ...y aplastarlos a todos en uno.
Jorge Orpinel

21

Siempre uso git diff así que en tu ejemplo, algo como

git diff master > patch.txt

15
Excepto que pierde todos los mensajes de confirmación y metadatos. Lo bueno de git format-patch es que es posible reconstruir toda la rama a partir de un conjunto de parches.
mcepl

el método create-branch-and-squash tiene la ventaja de combinar todos los mensajes de confirmación en uno, pero este método es mucho más rápido si desea escribir su propio mensaje de confirmación
woojoo666

en realidad, se puede hacer un mensaje combinado usando git log, vea mi respuesta para ver un ejemplo
woojoo666

2
Buena opción, pero considere que 'git diff' no puede incluir diferencias binarias (tal vez haya una opción para hacerlo).
Santiago Villafuerte

18

Esta es una adaptación de la respuesta de Adam Alexander, en caso de que sus cambios estén en la rama maestra. Esto hace lo siguiente:

  • Crea una nueva rama desechable "tmpsquash" desde el punto que queramos (busca la clave SHA que ejecuta "git --log" o con gitg. Selecciona el commit que quieres que sea tmpsquash head, los commits que están después de eso en master serán el aplastado comete).
  • Fusiona los cambios de maestro a tmpsquash.
  • Comete los cambios aplastados en tmpsquash.
  • Crea el parche con los commits aplastados.
  • Regresa a la rama maestra

laura@rune:~/example (master)$ git branch tmpsquash ba3c498878054e25afc5e22e207d62eb40ff1f38
laura@rune:~/example (master)$ git checkout tmpsquash
Switched to branch 'tmpsquash'
laura@rune:~/example (tmpsquash)$ git merge --squash master
Updating ba3c498..40386b8
Fast-forward
Squash commit -- not updating HEAD

[snip, changed files]

11 files changed, 212 insertions(+), 59 deletions(-)
laura@rune:~/example  (tmpsquash)$ git commit -a -m "My squashed commits"
[test2 6127e5c] My squashed commits
11 files changed, 212 insertions(+), 59 deletions(-)
laura@rune:~/example  (tmpsquash)$ git format-patch master
0001-My-squashed-commits.patch
laura@rune:~/example  (tmpsquash)$ git checkout master
Switched to branch 'master'
laura@rune:~/example  (master)$

Hacer cambios en master es un antipatrón si no los presionará para que los remotas. Y si lo desea, probablemente no necesite generar archivos de parche para ellos.
ivan_pozdeev

18

Como ya sabe, un git format-patch -8 HEADle dará ocho parches.

Si desea que sus 8 confirmaciones aparezcan como una sola, y no le importe volver a escribir el historial de su rama ( o-o-X-A-B-C-D-E-F-G-H), puede:

git rebase -i
// squash A, B, C, D, E ,F, G into H

o, y sería una mejor solución, reproducir todos tus 8 commits desde X(el commit antes de tus 8 commits) en una nueva rama

git branch delivery X
git checkout delivery
git merge --squash master
git format-patch HEAD

De esa manera, solo tiene una confirmación en la rama de "entrega", y representa todas sus últimas 8 confirmaciones


git merge mastersimplemente hace un avance rápido y no aplasta los commits en uno. Cambie a git merge --squash masterpara obtener todos los commits aplastados y visibles en el área organizada. Su flujo funcionará con este cambio. (Estoy usando git versión 2.1.0.)
Stunner

5

Parche de formato entre dos etiquetas:

git checkout <source-tag>
git checkout -b <tmpsquash>
git merge --squash <target-tag>
git commit -a -m "<message>"
git format-patch <source-tag>

5

La forma más fácil es usar git diffy agregar git logsi desea el mensaje de confirmación combinado que generaría el método de squash. Por ejemplo, para crear el parche entre commit abcdy 1234:

git diff abcd..1234 > patch.diff
git log abcd..1234 > patchmsg.txt

Luego, al aplicar el parche:

git apply patch.diff
git add -A
git reset patch.diff patchmsg.txt
git commit -F patchmsg.txt

No olvide el --binaryargumento de git diffcuando se trata de archivos que no son de texto, por ejemplo, imágenes o videos.


0

Basado en la respuesta de Adam Alexander:

git checkout newlines
## must be rebased to master
git checkout -b temporary
# squash the commits
git rebase -i master
git format-patch master
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.