Saltar al contenido principal

Git Squash Commits: Una guía con ejemplos

Aprende a aplastar confirmaciones en una rama utilizando el rebase interactivo, que ayuda a mantener un historial de confirmaciones limpio y organizado.
Actualizado 5 nov 2024  · 7 min de lectura

"Commit early, commit often" es un mantra popular en el desarrollo de software cuando se utiliza Git. Hacerlo garantiza que cada cambio esté bien documentado, mejora la colaboración y facilita el seguimiento de la evolución del proyecto. Sin embargo, esto también puede llevar a una sobreabundancia de commits.

Aquí es donde entra en juego la importancia de aplastar los commits. Aplastar confirmaciones es el proceso de combinar varias entradas de confirmación en una única confirmación cohesionada.

Conviértete en Ingeniero de Datos

Conviértete en un ingeniero de datos mediante el aprendizaje avanzado de Python
Empieza a Aprender Gratis

Por ejemplo, supongamos que trabajamos en una función que implementa un formulario de inicio de sesión, y creamos los cuatro commits siguientes:

Ejemplo de historial de confirmaciones Git

Una vez completada la función, para el proyecto en general, estos commits son demasiado detallados. No necesitamos saber en el futuro que nos encontramos con un error que se solucionó durante el desarrollo. Para garantizar un historial limpio en la rama principal, aplastamos estos commits en un único commit:

Ejemplo de aplastar commits Git

Cómo aplastar commits en Git: Rebase interactivo

El método más común para aplastar confirmaciones es utilizar un rebase interactivo. Lo iniciamos utilizando el comando

git rebase -i HEAD~<number_of_commits>

Sustituye por el número de commits que queremos aplastar.

En nuestro caso, tenemos cuatro commits, por lo que el comando es:

git rebase -i HEAD~4

Al ejecutar este comando se abrirá un editor interactivo de la línea de comandos:

Editor CLI después de git rebase -i

La sección superior muestra los commits, mientras que la inferior contiene comentarios sobre cómo aplastar los commits.

Vemos cuatro compromisos. Para cada una, debemos decidir qué orden ejecutar. Nos interesan los comandos pick (p) y squash (s). Para aplastar estas cuatro confirmaciones en una sola, podemos elegir la primera y aplastar las tres restantes.

Aplicamos los comandos modificando el texto que precede a cada confirmación, concretamente cambiando pick por s o squash para la segunda, tercera y cuarta confirmaciones. Para hacer estas modificaciones, tenemos que entrar en el modo "INSERTAR" en el editor de texto de la línea de comandos pulsando la tecla i del teclado:

Entra en el modo de inserción en el editor CLI

Tras pulsar i, aparecerá el texto -- INSERT -- en la parte inferior, indicando que hemos entrado en el modo de inserción. Ahora podemos mover el cursor con las teclas de flecha, borrar caracteres y escribir como lo haríamos en un editor de texto estándar:

Interactúa con el editor de texto CLI

Cuando estemos satisfechos con los cambios, debemos salir del modo de inserción pulsando la tecla Esc del teclado. El siguiente paso es guardar nuestros cambios y salir del editor. Para ello, primero pulsamos la tecla : para indicar al editor que pretendemos ejecutar un comando:

Introduce un comando en el editor de texto CLI

En la parte inferior del editor, ahora vemos un punto y coma : que nos pide que insertemos un comando. Para guardar los cambios, utilizamos el comando w, que significa "escribir". Para cerrar el editor, utiliza q, que significa "salir". Estos comandos pueden combinarse y escribirse juntos wq:

Cómo guardar y salir del editor de texto CLI

Para ejecutar la orden, pulsamos la tecla Enter. Esta acción cerrará el editor actual y abrirá uno nuevo, permitiéndonos introducir el mensaje de confirmación para la nueva confirmación aplastada. El editor mostrará un mensaje por defecto con los mensajes de los cuatro commits que estamos aplastando:

Editar el mensaje de confirmación de squash

Recomiendo modificar el mensaje para que refleje con exactitud los cambios implementados por estos commits combinados; al fin y al cabo, el objetivo del squashing es mantener un historial limpio y fácil de leer. 

Para interactuar con el editor y editar el mensaje, volvemos a pulsar i para entrar en modo edición y editar el mensaje a nuestro gusto.

Ejemplo de mensaje de confirmación de Squash

En este caso, sustituimos el mensaje de confirmación por "Implementar formulario de inicio de sesión". Para salir del modo edición, pulsamos Esc. A continuación, guarda los cambios pulsando :, introduciendo el comando wq y pulsando Enter.

Cómo ver el historial de confirmaciones

En general, recordar todo el historial de confirmaciones puede ser un reto. Para ver el historial de confirmaciones, podemos utilizar el comando git log. En el ejemplo mencionado, antes de realizar el squash, al ejecutar el comando git log se mostraría:

Historial de confirmaciones del registro Git antes del aplastamiento

Para navegar por la lista de commits, utiliza las teclas de flecha arriba y abajo. Para salir, pulsa q.

Podemos utilizar git log para confirmar el éxito de la calabaza. Ejecutarlo después del squash mostrará una única confirmación con el nuevo mensaje:

Historial de confirmaciones del registro Git después del aplastamiento

Empujar el commit aplastado

El comando anterior actuará sobre el repositorio local. Para actualizar el repositorio remoto, tenemos que empujar nuestros cambios. Sin embargo, como hemos cambiado el historial de confirmaciones, tenemos que forzar el push utilizando la opción --force:

git push --force origin feature/login-form

Forzar el empuje sobrescribirá el historial de confirmaciones de la rama remota y podría perturbar a otros que trabajen en esa rama. Es una buena práctica comunicarse con el equipo antes de hacerlo

Una forma más segura de forzar el push, que reduce el riesgo de interrumpir a los colaboradores, es utilizar en su lugar la opción --force-with-lease:

git push --force-with-lease origin feature/login-form

Esta opción garantiza que sólo forzaremos el push si la rama remota no se ha actualizado desde nuestro último fetch o pull.

Aplastar confirmaciones específicas

Imagínate que tenemos 5 compromisarios:

Ejemplo de registro Git con cinco confirmaciones

Supongamos que queremos conservar los commits 1, 2 y 5 y eliminar los commits 3 y 4.

Anular cualquier confirmación

Al utilizar el rebase interactivo, las confirmaciones marcadas para ser aplastadas se combinarán con la confirmación directamente anterior. En este caso, significa que queremos aplastar Commit4 para que se fusione con Commit3.

Para ello, debemos iniciar un rebase interactivo que incluya estos dos commits. En este caso, tres confirmaciones son suficientes, así que utilizamos el comando

git rebase -i HEAD~3

A continuación, ajustamos Commit4 a s para que quede aplastada con Commit3:

Aplastar dos commit ejemplo

Tras ejecutar este comando y listar los commits, observamos que los commits 3 y 4 se han aplastado juntos, mientras que el resto permanece sin cambios.

Registro Git después de aplastar

Aplastar a partir de una confirmación específica

En el comando git rebase -i HEAD~3, la parte HEAD es una abreviatura de la confirmación más reciente. La sintaxis ~3 se utiliza para especificar un antepasado de una confirmación. Por ejemplo, HEAD~1 se refiere al padre de la confirmación HEAD.

Ilustración de la notación ~

En un rebase interactivo, las confirmaciones consideradas incluyen todas las confirmaciones antepasadas que conducen a la confirmación especificada en el comando. Ten en cuenta que no se incluye la confirmación especificada:

Cómo se incluyen los commits en un rebase interactivo

En lugar de utilizar HEAD, podemos especificar directamente un hash de confirmación. Por ejemplo, Commit2 tiene un hash de dbf3cc118d6d7c08ef9c4a326b26dbb1e3fe9ddf, por lo que el comando:

git rebase -i dbf3cc118d6d7c08ef9c4a326b26dbb1e3fe9ddf

iniciaría un rebase considerando todos los commits realizados después de Commit2. Por tanto, si queremos iniciar un rebase en una confirmación concreta e incluir esa confirmación, podemos utilizar el comando

git rebase -i <commit-hash>~1

Resolver conflictos al aplastar commits

Cuando aplastamos confirmaciones, combinamos los cambios de varias confirmaciones en una sola, lo que puede provocar conflictos si los cambios se solapan o divergen significativamente. He aquí algunas situaciones habituales en las que pueden surgir conflictos:

  1. Cambios superpuestos: Si dos o más confirmaciones que están siendo aplastadas han modificado las mismas líneas de un archivo o líneas estrechamente relacionadas, puede que Git no sea capaz de reconciliar automáticamente estos cambios. 
  2. Diferentes cambios de estado: Si un commit añade un determinado fragmento de código y otro commit modifica o elimina ese mismo fragmento de código, aplastar estos commits puede dar lugar a conflictos que hay que resolver.
  3. Renombrar y modificar: Si una confirmación cambia el nombre de un archivo y las siguientes hacen cambios en el nombre antiguo, aplastar estas confirmaciones puede confundir a Git, provocando un conflicto.
  4. Cambios en los archivos binarios: Los archivos binarios no se fusionan bien con las herramientas de diferencias basadas en texto. Si varios commits cambian el mismo archivo binario e intentamos aplastarlos, puede producirse un conflicto porque Git no puede conciliar automáticamente estos cambios.
  5. Historia compleja: Si los commits tienen una historia compleja con múltiples fusiones, ramificaciones o rebases entre ellos, aplastarlos puede provocar conflictos debido a la naturaleza no lineal de los cambios.

Al aplastar, Git intentará aplicar cada cambio de uno en uno. Si encuentra conflictos durante el proceso, hará una pausa y nos permitirá resolverlos. 

El conflicto se marcará con los marcadores de conflicto <<<<<< y >>>>>>. Para manejar los conflictos, tenemos que abrir los archivos y resolver manualmente cada uno seleccionando qué parte del código queremos conservar. 

Después de resolver los conflictos, tenemos que escenificar los archivos resueltos utilizando el comando git add. A continuación, podemos continuar el rebase utilizando el siguiente comando:

git rebase --continue

Para saber más sobre los conflictos en Git, consulta este tutorial sobre cómo resolver conflictos de fusión en Git.

Alternativas al Aplastamiento con Rebase

El comando git merge --squash es un método alternativo a git rebase -i para combinar varias confirmaciones en una sola. Este comando es especialmente útil cuando queremos fusionar los cambios de una rama en la rama principal aplastando todos los commits individuales en uno solo. Aquí tienes un resumen de cómo aplastar utilizando git merge:

  1. Navegamos hasta la rama de destino en la que queremos incorporar los cambios.
  2. Ejecutamos el comando git merge --squash sustituyendo por el nombre de la rama.
  3. Confirmamos los cambios con git commit para crear una única confirmación que represente todos los cambios de la rama de características.

Por ejemplo, supongamos que queremos incorporar los cambios de la rama feature/login-form en main como una única confirmación:

git checkout main
git merge --squash feature-branch
git commit -m "Implement login form"

Éstas son las limitaciones de este enfoque en comparación con git rebase -i:

  • Granularidad del control: Menos control sobre los commits individuales. Con rebase podemos elegir qué commits fusionar, mientras que fusionar obliga a combinar todos los cambios en un solo commit.
  • Historia intermedia: Al utilizar la fusión, el historial de confirmaciones individuales de la rama de características se pierde en la rama principal. Esto puede dificultar el seguimiento de los cambios incrementales realizados durante el desarrollo de la función.
  • Revisión previa al compromiso: Dado que escenifica todos los cambios como un único conjunto de cambios, no podemos revisar ni probar cada confirmación individualmente antes de aplastarla, a diferencia de lo que ocurre durante un rebase interactivo, en el que cada confirmación puede revisarse y probarse en secuencia.

Conclusión

Incorporar commits frecuentes y pequeños al flujo de trabajo de desarrollo fomenta la colaboración y una documentación clara, pero también puede desordenar el historial del proyecto. Aplastar commits consigue un equilibrio, preservando los hitos importantes y eliminando al mismo tiempo el ruido de los cambios iterativos menores.

Para saber más sobre Git, te recomiendo estos recursos:


Photo of François Aubry
Author
François Aubry
LinkedIn
Enseñar siempre ha sido mi pasión. Desde mis primeros días como estudiante, busqué con entusiasmo oportunidades para dar clases particulares y ayudar a otros estudiantes. Esta pasión me llevó a realizar un doctorado, en el que también trabajé como ayudante de profesor para apoyar mis esfuerzos académicos. Durante esos años, encontré una inmensa satisfacción en el entorno tradicional del aula, fomentando las conexiones y facilitando el aprendizaje. Sin embargo, con la llegada de las plataformas de aprendizaje en línea, reconocí el potencial transformador de la educación digital. De hecho, participé activamente en el desarrollo de una plataforma de este tipo en nuestra universidad. Estoy profundamente comprometida con la integración de los principios de la enseñanza tradicional con metodologías digitales innovadoras. Mi pasión es crear cursos que no sólo sean atractivos e informativos, sino también accesibles para los alumnos en esta era digital.
Temas

¡Aprende ingeniería de datos con estos cursos!

programa

Ingeniero de Datos Asociado

30 horas hr
Aprende los fundamentos de la ingeniería de datos: diseño de bases de datos y almacenamiento de datos, ¡trabajando con tecnologías como PostgreSQL y Snowflake!
Ver detallesRight Arrow
Comienza El Curso
Certificación disponible

curso

Comprender la ingeniería de datos

2 hr
246.8K
Descubre cómo los ingenieros de datos sientan las bases que hacen posible la ciencia de datos. ¡Sin codificación!
Ver másRight Arrow
Relacionado

tutorial

Tutorial de Git Revert y Git Reset para principiantes

Una guía tutorial para principiantes que muestra cómo utilizar los comandos Git Revert y Reset.
Zoumana Keita 's photo

Zoumana Keita

10 min

tutorial

Tutorial de GIT Push y Pull

Aprende a realizar solicitudes de Git PUSH y PULL con GitHub Desktop y la línea de comandos.

Olivia Smith

13 min

tutorial

Git pull force: Cómo sobrescribir una rama local con una remota

Aprende por qué git pull --force no es la mejor forma de sobrescribir una rama local con la versión remota, y descubre el método adecuado utilizando git fetch y git reset.
François Aubry's photo

François Aubry

tutorial

Git Prune: Qué es la poda Git y cómo usarla

La poda Git es un comando Git que elimina del repositorio los objetos que ya no son accesibles desde ninguna confirmación o rama, ayudando a liberar espacio en disco.
François Aubry's photo

François Aubry

5 min

tutorial

Tutorial de GitHub y Git para principiantes

Un tutorial para principiantes que muestra cómo funciona el control de versiones Git y por qué es crucial para los proyectos de ciencia de datos.
Abid Ali Awan's photo

Abid Ali Awan

17 min

tutorial

Git rename branch: Cómo cambiar el nombre de una rama local o remota

Aprende a renombrar ramas Git locales y remotas utilizando el terminal o la interfaz gráfica de usuario (GUI) de clientes populares como GitHub.
François Aubry's photo

François Aubry

See MoreSee More