"El buen diseño es obvio. El gran diseño es transparente"
- Joe Sparano

Fusionar commits

5 minutos de lectura
Fecha: 3/12/2020

¿Por qué fusionar commits?

Fusionar commits es una de las cosas mas chulas que podemos hacer, manipular la historia de nuestro proyecto hace que este sea mucho más legible y que podamos encontrar el cambio que queremos más rápido.

A quien no le ha pasado que aunque estaba trabajando en una tarea, ha acabado subiendo 4 o 5 commits porque se equivoco alguna vez, porque los requisitos no estaban tan bien definidos como nos gustaría o simplemente porque somos así y hacemos varias subidas por costumbre.

No voy a entrar en el porque se hace, si es mejor o peor, o si esta o no justificado. Pero el caso es que en el mundo real los programadores a veces metemos commits que funcionalmente no tienen ningun sentido. Y no queremos tenerlos así en git porque ni tienen sentido, y posiblemente porque los comentarios o sean recurrentes o no aporten gran cosa.

Por toda esta parrafada es necesario que sepas fusionar commits, y por eso hay un comando maravilloso que nos deja hacer esto y muchas otras cosas. Estamos hablando del rebase interactivo.

Como fusionar commits

Un rebase interactivo nos permite que escojamos una series de commits que esten en nuestro repositorio local (no puedes fusionar algo que llego al remoto, tenlo en cuenta porque como lo subas y luego quieras ya no vas a poder) y que hagamos cosas con ellos.

Entre estas cosas estan editar los comentarios, dividirlos, ordenarlos y por supuesto, lo que nos ocupa, fusionarlos.

Para mostraros como funciona voy a crearme un repositorio de git y le voy a subir 5 commits. Cada uno escribe una linea distinta dentro de un fichero de texto, más simple no puede ser.

Descripción de la imagen

Como vemos por un lado con git log sacamos nuestro historial de git, y por el otro vemos el fichero, como decia cada commit equivale a una linea del fichero.

Vamos a intentar combinar en un solo commit los 3 últimos que hemos subido, de manera que tendremos un único commit que creará la tercera, cuarta y quinta línea del documento.

Para ello ejecutamos el siguiente comando

git rebase -i HEAD~3

Esto nos va a abrir de forma automática el editor de texto por defecto que tengamos configurado en GIT que en mi caso es Visual Studio Code, y allí podremos editar lo que queremos hacer con nuestro rebase interactivo.

Descripción de la imagen

Lo importante son las 3 primeras lineas que como veis describen los 3 commits con los que vamos a trabajar. La primera palabra de cada linea es pick y es esta palabra la que define que va a pasar con ese commit en concreto.

Por defecto cuando hacemos un rebase interactivo todo van a ser pick, porque es la palabra que indica que queremos usar el commit sin hacer ningun cambio.

Os he dejado tambien en la captura los comentarios de ayuda que nos proporciona GIT donde podemos ver el resto de palabras que podemos usar y el resultado que producen.

En nuestro caso la que nos interesa es squash, que traducida del ingés sería aplastar y que es muy apropiado porque literalmente va a aplastar el commit al que se lo apliquemos contra el anterior.

Esto quiere decir que si yo le pongo el squash al quinto commit este me lo va a aplastar o fusionar con el anterior que es cuarto, de manera que, ahora el cuarto commit va a contener los cambios de ambos.

Como queremos fusionar los 3 ultimos tenemos que hacer esto…

Descripción de la imagen

Ahora solo guarda y cierra (ambas cosas) y automáticamente el rebase continuará al siguiente paso.

Puede que ahora el comentario del commit no sea el deseado porque su código ya hace más cosas o porque ya de entrada no estuviera bien. Por eso en el siguiente paso se te va a pedir que lo edites.

Por defecto lo que hace es concatenar en distintos párrafos los comentarios de los commits que estas fusionando, en mi caso como son 3 me pone esto:

Descripción de la imagen

No os asusteis por la parrafada, ya veis que casi todo son comentarios de GIT, mi consejo borra todo y escribe el comentario que quieras.

Porque lo normal suele ser que la concatenación no sirva, salvo que realmente los commits fueran todo tareas atómicas bien hechas y estés buscando fusionarlos para subir en un solo commit la historia de usuario que los engloba.

En mi caso voy a poner que es la fusion de los 3 últimos commits…

Descripción de la imagen

Y lo mismo de antes, lo guardas y cierras la pestaña o el editor. Con esto volverás a la ventana de comandos y se te indicará que el rebase se ha completado

Ahora podemos volver a hacer un git log para ver como ha quedado la historia.

Descripción de la imagen

Como veis ahora en vez de 5 tenemos 3 commits porque el último es la fusión que hemos hecho.

Tambien podeis observar que la hacer la fusión, realmente no es que se aplaste sencillamente un commit con el anterior sino que se crea un commit nuevo. Esto se puede comprobar mirando el hash (lo que identifica realmente el commit) de cada uno de ellos, mientras que los de los commits eran:


    7343ba952e9fbfe0c0aec4e5de7c365be9b57aba
    79cc5a151e09bec12990f8d77445a91144dcfb56
    e33dd897c950a4484a97e92ce6a4ee04d667d98b

Mientras que el de la fusion es ef6ec1206e2e7ce2512788f3fc503cd4fff8e916. De manera que la fusion no es que coja como base un commit y vaya aplastandole por encima los que le pones squash, sino que crea uno nuevo.

Con esto ya esta explicado todo el proceso. De todas formas alguien podria preguntarse como podria hacer si en vez de querer hacer la fusion del 3-5 la quisiera hacer del 2-4.

En ese caso lo más facil seria coger las 4 ultimas y tocar solo las que quieres, para marcar el punto puedes usar el hash, yo en este caso lo hago igual que antes.

git rebase -i HEAD~4

Quedaria algo así

pick b1b83c2 Segundo commit
squash e33dd89 Tercer commit
squash 79cc5a1 Cuarto commit
pick 7343ba9 Quinto commit

Para más información puedes consultar aquí la documentación oficial que explica muchísimas mas cosas y ademas está en castellano y con ejemplos.