Cómo unir commits en git en uno sólo [ACTUALIZADO]

En ocasiones ocurre que necesitamos juntar varios commits the git. Casó típico: en tu trabajo diario con git vas cumpliendo poco a poco mini hitos que te pones, pero a la hora de compartir el trabajo o de enviar los cambios a un repositorio compartido sólo se permite enviar el trabajo en un único commit agrupado.

¿Cómo solucionarlo? La solución se llama hacer un squash de los commits.

Una forma es usar un rebase de git e indicar los últimos X commits hasta el HEAD que queremos juntar.

Con un ejemplo, he creado un repo git con un fichero “ejemplo.txt” y he puesto 3 líneas, para cada una he hecho un commit como se puede ver:

PS C:\Users\jperez\Desktop\SquashCommits> git log --pretty=format:"%h - %an, %ar : %s"
c38c676 - Jose PEREZ, 13 seconds ago : commit 3
e6cf0c2 - Jose PEREZ, 23 seconds ago : commit 2
e9f1267 - Jose PEREZ, 35 seconds ago : commit 1

Ahora, lo que busco es tener esos cambio en un único commit (ponemos ~3 para índicar que desde HEAD vamos a trabajar con los último 3 commits (b58318d, 6967fdf y 7c45e93):

git rebase -i HEAD~3

Esto abrirá un editor de texto (en mi caso vim) y pondrá algo así:

pick c38c676 commit 3
squash e6cf0c2 commit 2
squash e9f1267 commit 1


# Rebase 710f0f8..e9f1267 onto 710f0f8 
# 
# Commands: 
# p, pick <commit> = use commit 
# r, reword <commit> = use commit, but edit the commit message 
# e, edit <commit> = use commit, but stop for amending 
# s, squash <commit> = use commit, but meld into previous commit 
# f, fixup <commit> = like "squash", but discard this commit's log message 
# x, exec <command> = run command (the rest of the line) using shell 
# b, break = stop here (continue rebase later with 'git rebase --continue') 
# d, drop <commit> = remove commit 
# l, label <label> = label current HEAD with a name 
# t, reset <label> = reset HEAD to a label 
# m, merge [-C <commit> | -c <commit>] <label> [
# <oneline>] 
# . create a merge commit using the original merge commit's 
# . message (or the oneline, if no original merge commit was 
# . specified). Use -c <commit> to reword the commit message. 
#

(las líneas con # no hay que tocarlas son anotaciones que nos pone GIT para que sepamos que operaciones podemos poner aqui).

Con esto indicamos que los dos primeros commit se tienen que integrar (squash) en commit que hemos “codigo” (pick) y así todo queda un uno solo. Al guardar el editor y cerrar se nos abre otro donde escribimos el mensaje del nuevo commit que reescribe la historia de git.

Aquí suelen venir los mensajes de los commits indicados y podemos ver la lista de los ficheros implicados como en un parche.

Al final se nos queda un único commit nuevo con todos los cambios de todos los anteriores y el mensaje de commit que uno todos los anteriores.

¡Solucionado!

Actualización (usando intellij)

El proceso que hemos descrito anteriormente se puede hacer muy fácilmente con un IDE. En mi caso, uso IntelliJ y se sigue el procedimiento:

  1. Ir a la pestaña “git” del IDE
  2. Ir a la rama que se quiere (la actual o checkout a otra)
  3. Elegir los commits sucesivos que queremos unir
  4. Seleccionar “squash commits”

Como en este imagen:

Deja un comentario

Tu dirección de correo electrónico no será publicada.

This site uses Akismet to reduce spam. Learn how your comment data is processed.