Git Squash Commits

Azhar Bashir Khan 30 enero 2023
  1. Uso de la herramienta interactiva git rebase para aplastar los commits de Git
  2. Uso de git merge -squash para aplastar los commits de Git
Git Squash Commits

Aprenderemos a aplastar Git en este tutorial. La idea básica es tomar múltiples commits continuas y combinarlas en una.

La intención principal es condensar muchas commits en unas pocas commits relevantes. Por lo tanto, hacer esto hace que el historial de git se vea conciso y claro.

Otra forma de verlo es que hacemos múltiples commits relacionadas con alguna tarea. Después de un tiempo, cuando alcanzamos un estado satisfactorio, los muchos mensajes de commit saturan el historial de git.

En este punto, es posible que deseemos combinar las diferentes commits en una para que el historial de git se vea claro y refleje mejor la tarea realizada.

Otro caso de uso es aplastar mientras se fusionan ramas. Por lo general, creamos una rama de funciones a partir de la rama principal para el desarrollo de algunas funciones.

Después de completar la función, fusionamos la rama de la función con la rama principal. Aquí también, es posible que deseemos aplastar los diversos mensajes de commit realizados en la rama de funciones en uno cuando se fusionan con la rama principal.

Tenga en cuenta que no existe el comando git squash.

Hay dos formas de lograr el aplastamiento de Git:

  • git rebase -i como herramienta interactiva utilizada para aplastar commits
  • git merge -squash usando la opción -squash mientras se fusiona

Uso de la herramienta interactiva git rebase para aplastar los commits de Git

Considere el siguiente extracto de registro de git, que muestra las últimas cuatro commits de HEAD que estamos interesados ​​en aplastar.

25c38c4 remove .class files
da66e6a Delete version.ini
f4e3f09 Delete .log
b0e6655 Delete .lock
da66e6a github git notes

Podemos ver en el registro los primeros cuatro mensajes de commit que significan las operaciones de eliminación de diferentes archivos irrelevantes. Ahora, aplastaremos estos cuatro compromisos en uno.

A continuación se muestra la sintaxis del comando para aplastar las últimas X commits utilizando la herramienta interactiva de rebase.

git rebase -i HEAD~[X]

Por lo tanto, para aplastar las cuatro commits, haríamos lo siguiente.

$ git rebase -i HEAD~4

Después de emitir este comando, Git invocará el editor predeterminado con detalles de los commits para aplastar, como se muestra a continuación.

pick b0e6655 Delete .lock
pick f4e3f09 Delete .log 
pick da66e6a Delete version.ini
pick 25c38c4 remove .class files

# Rebase 652d2fe..25c38c4 onto 652d2fe (4 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

El editor muestra las distintas commits con el comando pick. También muestra información sobre los comandos disponibles. Usaremos el comando squash (o s).

Como se muestra a continuación, mantendremos la primera confirmación con el comando pick y cambiaremos de la orden pick a la de s (para aplastar) para las tres commits restantes.

pick b0e6655 Delete .lock
s f4e3f09 Delete .log 
s da66e6a Delete version.ini
s 25c38c4 remove .class files

# Rebase 652d2fe..25c38c4 onto 652d2fe (4 command(s))
#
...

los commits marcadas con squash (o s) se fusionarán con el commit principal, a saber. el marcado con pick.

Ahora, guardaremos los cambios en el editor y saldremos. Después de esto, la herramienta rebase -i abrirá otro editor para ingresar el mensaje de commit, como se muestra a continuación:

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

Delete .lock

# This is the 2nd commit message:

Delete .log 

# This is the 3rd commit message:

Delete version.ini

# This is the 4th commit message:

remove .class files

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Sun Jan 3 16:39:23 2021 +0530
#
# interactive rebase in progress; onto 652d2fe
# Last commands done (4 commands done):
#    pick b0e6655 Delete .lock
#    s f4e3f09 Delete .log 
#    s da66e6a Delete version.ini
#    s 25c38c4 remove .class files
# No commands remaining.
# You are currently editing a commit while rebasing branch 'master' on '652d2fe'.
#
# Changes to be committed:
#       new file:   github-git-notes.txt
#

Ahora, agregaremos el nuevo mensaje de commit en la parte superior del primer mensaje de commit.

Deleted irrelevant files

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

Delete .lock

# This is the 2nd commit message:

Delete .log
...

Después de guardar y salir del editor, la herramienta rebase -i imprimirá el siguiente mensaje.

HEAD~2
Rebasing (2/2)


[detached HEAD caab6e8] Deleted irrelevant files
 Date: Sun Jan 3 16:39:23 2021 +0530
 1 file changed, 54 insertions(+)
 create mode 100644 github-git-notes.txt
Successfully rebased and updated refs/heads/master.

Ahora, comprobaremos el git log y veremos el mensaje de commit aplastado (es decir) un solo mensaje de commit en lugar de los cuatro mensajes de commit.

$ git log --oneline
25c38c4 Deleted irrelevant files
da66e6a github git notes
...

Uso de git merge -squash para aplastar los commits de Git

A continuación se muestra la sintaxis del comando para fusionar una rama con la rama actual (normalmente main) y aplastar los commits de la rama fuente.

git merge --squash <source_branch_name_to_squash>

Ahora fusionaremos la rama de funciones a saber. feature1 con aplastamiento con la rama main.

Primero, realizaremos el checkout en la rama main.

$ git checkout main
Switched to branch 'main'

Luego, haremos un git merge con la opción squash de la siguiente manera.

$ git merge --squash feature1
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requested

Cuando hacemos una fusión con la opción --squash, Git no creará un commit de fusión en la rama de destino, como lo hace en una fusión normal. En cambio, Git toma todos los cambios en la rama de origen, a saber. feature1 y lo pone como cambios locales en la copia de trabajo de la rama de destino, es decir, main.

Por favor ver más abajo.

$ git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   config.ini

Aquí, el archivo config.ini tiene los cambios realizados en la rama feature1.

Ahora, todo lo que queda es confirmar los cambios en la rama main como se muestra a continuación.

$ git commit -am 'Merged and squashed the feature1 branch changes'
[main 573b923] Squashed and merged the feature1 branch
 1 file changed, 4 insertions(+)

Por lo tanto, ahora hemos fusionado los cambios en la rama feature1 en la rama main, junto con aplastar los mensajes de commit de la rama feature1. Ahora solo tenemos un único mensaje de commit en la rama main.

Artículo relacionado - Git Rebase

Artículo relacionado - Git Merge