¿Qué significa aplastar confirmaciones en git?

117

¿Qué significa Squashing commits en git? ¿Cómo aplazo las confirmaciones en Github?

Soy nuevo en Git y solicité que me asignaran un error nuevo en coala-analyzer. Arreglé el error y ahora se me pidió que aplastara mis confirmaciones. ¿Cómo lo hago?

Lakshmanan Meiyappan
fuente
Hola @Lakshman, siéntete libre de aceptar la respuesta más votada. Responde adecuadamente a su pregunta.
Mostafiz Rahman

Respuestas:

180

Puede pensar en Git como una base de datos avanzada de instantáneas de su directorio (s) de trabajo.

Una característica muy buena de Git es la capacidad de reescribir el historial de confirmaciones.
La razón principal para hacer esto es que gran parte de ese historial es relevante solo para el desarrollador que lo generó, por lo que debe simplificarse o hacerse más agradable antes de enviarlo a un repositorio compartido.

Aplastar una confirmación significa, desde un punto de vista idiomático, mover los cambios introducidos en dicha confirmación a su padre, de modo que termine con una confirmación en lugar de dos (o más).
Si repite este proceso varias veces, puede reducir n commit a uno solo.

Visualmente, si comenzó su trabajo en el compromiso etiquetado como Inicio , desea esto

Git comete aplastamiento

Puede notar que la nueva confirmación tiene un tono de azul ligeramente más oscuro. Esto es intencional.

En Git, el aplastamiento se logra con un Rebase , de una forma especial llamada Interactive Rebase .
Simplificando cuando reorganiza un conjunto de confirmaciones en una rama B , aplica todos los cambios introducidos por esas confirmaciones a medida que se hicieron, comenzando desde B en lugar de su antecesor original.

Una pista visual

ingrese la descripción de la imagen aquí

Note nuevamente los diferentes tonos de azul.

Una nueva base de datos interactiva le permite elegir cómo se deben cambiar las bases de datos. Si ejecuta este comando:

 git rebase -i branch

Terminaría con un archivo que enumera las confirmaciones que se volverán a basar

 pick ae3...
 pick ef6...
 pick 1e0...
 pick 341...

Yo no nombrar el confirmaciones, pero estos cuatro unos pretenden ser las confirmaciones de inicio a la cabeza

Lo bueno de esta lista es que se puede editar .
Puede omitir las confirmaciones o puede aplastarlas .
Todo lo que tienes que hacer es cambiar la primera palabra a aplastar .

 pick ae3...
 squash ef6...
 squash 1e0...
 squash 341...

Si cierra el editor y no se encuentran conflictos de combinación, terminará con este historial:

ingrese la descripción de la imagen aquí

En su caso, no desea cambiar la base a otra rama, sino a una confirmación anterior.
Para transformar el historial como se muestra en el primer ejemplo, debe ejecutar algo como

git rebase -i HEAD~4

cambie los "comandos" para aplastar todas las confirmaciones excepto la primera, y luego cierre su editor.


Nota sobre la alteración de la historia

En Git, las confirmaciones nunca se editan. Se pueden podar, hacer no accesibles, clonar pero no cambiar.
Cuando realizas un cambio de base, en realidad estás creando nuevas confirmaciones.
Los antiguos ya no son accesibles por ningún árbitro, por lo que no se muestran en el historial, ¡pero todavía están allí!

Esto es lo que realmente obtienes por una rebase:

ingrese la descripción de la imagen aquí

Si ya los ha enviado a algún lugar, ¡reescribir el historial realmente hará una rama!

Margaret Bloom
fuente
Bien, ¿qué sucede con los comentarios de confirmación originales? ¿Se combinan en un solo comentario de confirmación grande o se pierden?
Paul R
De man git rebase: El mensaje de confirmación sugerido para la confirmación plegada es la concatenación de los mensajes de confirmación de la primera confirmación y de aquellos con el comando "squash"
Margaret Bloom
1
Esta es la mejor explicación que he visto de rebase, gracias.
Kerry Jones
Acerca del aplastamiento en su primera imagen: ¿Puede hacer un ejemplo en el que HEAD tenga un directorio de trabajo diferente antes (azul claro) y después (azul oscuro) del aplastamiento? En todos los ejemplos que intenté aplastar, parecía que acababa de eliminar las tres confirmaciones entre START y HEAD.
actual_panda
@actual_panda No estoy seguro de seguir. HEAD es un árbitro para un compromiso. Confirma deltas de tienda. El directorio de trabajo es una propiedad del repositorio en su conjunto, depende de la confirmación que haya verificado. En general, dos referencias (como HEAD y START) siempre dan dos direcciones de trabajo diferentes cuando se revisan. Si rebasas squash en la misma rama, el efecto es "perder" las confirmaciones intermedias, pero en realidad, git hizo una nueva con todos los deltas. git diffpuede ayudarlo a mostrar lo que sucedió.
Margaret Bloom
22

El comando rebase tiene algunas opciones increíbles disponibles en su modo --interactive(o -i), y una de las más utilizadas es la capacidad de aplastar confirmaciones. Lo que hace esto es tomar confirmaciones más pequeñas y combinarlas en otras más grandes, lo que podría ser útil si está terminando el trabajo del día o si solo desea empaquetar sus cambios de manera diferente. Vamos a repasar cómo puede hacer esto fácilmente.

Una advertencia: solo haga esto en confirmaciones que no se hayan enviado a un repositorio externo. Si otros han basado el trabajo en las confirmaciones que va a eliminar, pueden ocurrir muchos conflictos. Simplemente no reescriba su historial si lo ha compartido con otros.

Entonces, digamos que acaba de realizar algunas confirmaciones pequeñas y desea hacer una confirmación más grande con ellas. El historial de nuestro repositorio actualmente se ve así:

ingrese la descripción de la imagen aquí

Las últimas 4 confirmaciones serían mucho más felices si estuvieran juntas, así que hagámoslo a través de un reajuste interactivo:

$ git rebase -i HEAD~4

pick 01d1124 Adding license
pick 6340aaa Moving license into its own file
pick ebfd367 Jekyll has become self-aware.
pick 30e0ccb Changed the tagline in the binary, too.

# Rebase 60709da..30e0ccb onto 60709da
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

Entonces, han sucedido algunas cosas aquí. En primer lugar, le dije a Git que quería rebasar usando las últimas cuatro confirmaciones desde donde está HEAD con HEAD ~ 4. Git ahora me ha puesto en un editor con el texto anterior y una pequeña explicación de lo que se puede hacer. Tienes muchas opciones disponibles en esta pantalla, pero ahora mismo vamos a juntar todo en una sola confirmación. Entonces, cambiar las primeras cuatro líneas del archivo a esto hará el truco:

pick 01d1124 Adding license
squash 6340aaa Moving license into its own file
squash ebfd367 Jekyll has become self-aware.
squash 30e0ccb Changed the tagline in the binary, too.

Básicamente, esto le dice a Git que combine las cuatro confirmaciones en la primera confirmación de la lista. Una vez hecho esto y guardado, aparece otro editor con lo siguiente:

# This is a combination of 4 commits.
# The first commit's message is:
Adding license

# This is the 2nd commit message:

Moving license into its own file

# This is the 3rd commit message:

Jekyll has become self-aware.

# This is the 4th commit message:

Changed the tagline in the binary, too.

    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    # Explicit paths specified without -i nor -o; assuming --only paths...
    # Not currently on any branch.
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #   new file:   LICENSE
    #   modified:   README.textile
    #   modified:   Rakefile
    #   modified:   bin/jekyll
    #

Dado que estamos combinando tantas confirmaciones, Git le permite modificar el mensaje de la nueva confirmación en función del resto de las confirmaciones involucradas en el proceso. Edite el mensaje como mejor le parezca, luego guárdelo y salga. Una vez hecho esto, ¡sus confirmaciones se han eliminado con éxito!

Created commit 0fc4eea: Creating license file, and making jekyll self-aware.
 4 files changed, 27 insertions(+), 30 deletions(-)
  create mode 100644 LICENSE
    Successfully rebased and updated refs/heads/master.

Y si volvemos a mirar la historia ... ingrese la descripción de la imagen aquí

Entonces, esto ha sido relativamente indoloro hasta ahora. Si se encuentra con conflictos durante el cambio de base, generalmente son bastante fáciles de resolver y Git lo guía en la mayor medida posible. Lo básico de esto es solucionar el conflicto en cuestión, git addel archivo y luego git rebase --continuereanudará el proceso. Por supuesto, hacer un git rebase --abortlo llevará de regreso a su estado anterior si lo desea. Si por alguna razón ha perdido una confirmación en el rebase, puede usar el reflog para recuperarlo.

Los detalles se pueden encontrar en este enlace .

0xAliHn
fuente
3
¡Gracias! En caso de que alguien se sienta tan incómodo con VIM como yo ... cuando llegues al punto en el que ingresas acciones para editar, presiona 'i' para ingresar al modo de edición. Cuando haya terminado con los cambios, presione escape y luego escriba ": wq" y lo hará avanzar. (Mac)
Farasi78
+1 para la precaución y el contexto de cuándo hacer esto. En mi experiencia personal, es bueno si está trabajando solo en una rama de características y tiene un montón de confirmaciones triviales como "léame actualizado", "hizo algo que a nadie le importa" y está listo para fusionar la rama, tal vez bueno, simplemente aplástalos todos en un solo compromiso. Nadie va a querer volver a tu "hice algo que a nadie le importa" y eso contamina el historial de confirmaciones
Adam Hughes