Cuando trabajamos con Git, a menudo nos encontramos con la necesidad de fusionar una rama de desarrollo con la rama principal, pero sin querer que el historial se llene de múltiples commits intermedios que pueden dificultar la lectura y el mantenimiento. Aquí es donde entra en juego la estrategia de merge con squash, una técnica que nos permite combinar todos esos commits en uno solo, manteniendo un historial más limpio y organizado.
Imaginemos que tenemos una rama llamada Bootstrap5 que contiene varios commits con cambios realizados recientemente, y queremos integrar esos cambios en la rama principal, que llamaremos Trunk. Si hacemos un merge tradicional, Git simplemente moverá el puntero de la rama principal hacia adelante, integrando todos los commits tal cual, lo que puede generar un historial con muchos pasos intermedios. Esto es lo que se conoce como un merge con fast-forward cuando no hay divergencias.
Sin embargo, si queremos que todos esos commits se conviertan en uno solo, podemos usar el merge con squash. Lo que hace Git en este caso es tomar el conjunto completo de diferencias entre Trunk y Bootstrap5 y aplicarlas como un único cambio. Es como si hiciéramos un git diff Trunk...Bootstrap5 para ver todas las modificaciones acumuladas y luego aplicáramos ese diff de golpe sobre Trunk.
Para llevar a cabo este proceso, primero nos situamos en la rama donde queremos integrar los cambios, en este caso Trunk. Luego ejecutamos el comando:
git merge --squash Bootstrap5
Al hacer esto, Git nos mostrará un resumen de todos los cambios que se van a aplicar, pero no realizará el commit automáticamente. Esto es importante: el merge con squash no actualiza el puntero HEAD ni crea un commit por sí solo. En su lugar, deja todos los cambios preparados en el área de staging, listos para que nosotros decidamos cuándo y cómo confirmar esos cambios.
Podemos comprobar el estado con:
git status
y veremos que todos los archivos modificados están listos para ser confirmados. Ahora solo queda hacer el commit manualmente con:
git commit
Esto abrirá el editor de texto configurado para Git, que en muchos casos es Vim. Git nos mostrará un mensaje predefinido que incluye todos los mensajes de los commits originales que hemos aplastado. Sin embargo, la gracia del squash es precisamente ocultar esos detalles y dejar un mensaje limpio y claro. Por eso, es recomendable borrar ese texto y escribir un mensaje que resuma el cambio de forma concisa.
Si usamos Vim, podemos hacerlo de forma eficiente sin tener que borrar línea por línea con la tecla de borrar. Para ello, pulsamos Shift + V para entrar en modo visual por líneas, seleccionamos todas las líneas que queremos eliminar desplazándonos con las flechas o con Ctrl + D para bajar página a página, y luego pulsamos d para borrarlas. Después, con la tecla o en mayúscula podemos insertar el nuevo mensaje de commit. Finalmente, guardamos y salimos con :w y Enter.
Una vez hecho esto, si consultamos el historial con:
git log --oneline --graph --all
veremos que todos los commits que antes estaban en la rama Bootstrap5 han quedado condensados en un único commit en la rama Trunk. La rama original sigue existiendo, pero podemos eliminarla si ya no la necesitamos.
Este método es especialmente útil cuando queremos mantener un historial limpio y evitar que se vean todos los commits intermedios que hicimos durante el desarrollo, algo que a menudo ocurre cuando usamos interfaces web para hacer squash merges. Al hacerlo desde la consola, tenemos un control total sobre el proceso y podemos entender mejor qué está pasando detrás de escena.
Así, el merge con squash nos permite integrar cambios de forma ordenada, combinando múltiples commits en uno solo y facilitando la lectura y mantenimiento del historial de nuestro repositorio.