NOTA: Los cambios en los archivos que aparecen en esta Pull Request son todas las ediciones que se han ido haciendo durante las últimas 9 commits.
Las 9 últimas commits afectan a un solo archivo y tienen el mismo nombre.
Con esta Pull Request no se cambia ningún archivo, únicamente se 'aligera' el historial de commits, fundiendo en 1 las últimas 9.
A continuación detallo el proceso por si prefieres hacerlo tú mismo.
Como aclaración: rebase supone cambiar la commit de la que parte HEAD (commit actual). En tu repositorio, HEAD parte de la commit anterior, y esta de la anterior, etc. Lo que queremos es que HEAD parta de la primera Update README.md de las 9 que hay. Con squash, lo que hacemos en integrar las commits intermedias en HEAD. Más adelante se entenderá mejor.
Iniciar git rebase de las últimas 9 commits
Lo primero que he hecho ha sido un fork del repositorio original.
Después, git clone mi fork a mi ordenador.
# Clonar mi fork en mi ordenador
git clone git@github.com:pabloqpacin/D4TA-HUNTER.git
cd ~/path/D4TA-HUNTERS
Lo primero es un git status para demostrar que el repositorio está tal y como lo he forkeado.
A continuación cuento el número de commits que quiero agrupar con git log y aplicando un formato. Uso un alias del comando completo copio íntegro más adelante.
Como se puede observar, las últimas 9 son iguales.
# Git log con un formato determinado usando el alias 'glol'
git status
git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset'
Ahora lo que queremos hacer es un rebase --interactive de las últimas 9 commits desde HEAD (la actual) para poder efectuar el squash (el agrupamiento).
Con tldr git rebase puedes ver información aparte de lo que haya por internet.
# Iniciar proceso de rebase interactivo en la terminal
tldr git rebase
git rebase -i HEAD~9
Aplicar squash en Vim
Mi editor predeterminado es Vim, no nano. A continuación detallo los pasos que sigo para hacer lo que hay que hacer. En algunos casos uso key bindings propios así que quizá tengas que usar diferentes teclas para obtener el mismo resultado. Este enlace puede ser de ayuda.
1. Cambiar pick por squash
Lo que hay que hacer es reemplazar todos los pick por squash para todas las commits menos la de la primera línea.
La commit primera línea debe corresponderse con la primera commit (no la última) de todas las que queremos agrupar. De esta manera, el historial de commits pasará directamente de la primera commit que seleccionamos (el primer Update README.md) al estado presente, ignorando todas las commits intermedias (todas las posteriores a la primera hasta el presente) pero manteniendo sus cambios. Por aclarar: esto no altera los archivos del respositorio sino el historial de commits.
En caso de duda, puedes comparar los números de commits que ves en estos menús con los del historial de Github.
# Replace PICK for SQUASH except first line (oldest commit from HEAD)
j # move cursor to line 2, first letter first word
Ctrl+B # enter VISUAL BLOCK mode -- key binding might be different
lll # select next three letters, (complete word 'pick')
jjjjjjj # selecting 'pick' IN all lines but the first
s # substitute selected text and enter INSERT MODE
squash # will do squash operation -- displayed in only one line atm
kj # <Esc> INSERT mode -- see 'squash' displayed in all lines!!
:wq # write and quit to the next screen
2. Dejar fuera mensajes de commits
Ahora que hemos seleccionado la operación squash, podemos cambiar el mensaje que veremos en HEAD (es decir, la commit actual).
Aparte de mantener el primer Update README.md, se podría añadir el texto Rebase commit history como mensaje aclaratorio. Es innecesario y en este caso no lo hacemos.
Como resultado, todas las líneas estarán comentadas menos una.
Creo que esta parte se podría hacer mejor con una búsqueda de coincidencias en Vim para evitar la repetición. Quizá la próxima vez.
# Now just comment out all the instances of 'Update README.md' but one :)
3j # go down 3 lines -- leave the first 'Update README.md' as it is
3j # go down 3 lines
I # enter INSERT mode at the beginning of the line
'# ' # type 1 pound and 1 space
kj # <Esc> INSERT MODE
3j # go down 3 lines
# REPEAT until all 'Update README.md' instances are commented out excepct the first
:wq # write and quit -- LIKELY SUCCESS!!
Push cambios a HEAD en el repo remoto
Tras leer los mensajes post-rebase, combrobemos el historial de commit tal y como ha quedado.
git status
glol | grep "("
Con el siguiente comando podemos ver gráficamente la operación.
La línea roja (no commiteada) será el nuevo historial de commits. Las líneas verdes (commiteadas) se integrarán en la roja, manteniendo los cambios efectuados en cada commit.
Si hubiéramos cambiado el mensaje que dejamos sin comentar durante el rebase, lo veríamos en la commit de arriba, que seguirá siendo HEAD.
Con el rebase hecho, esta es la parte más crítica.
Tenemos que hacer push de los cambios en el repositorio local al repositorio remoto. Si hubiéramos editado archivos lo ideal habría sido hacer un commit antes del rebase. No es el caso, no hemos editado archivos, solo hemos condensado el historial de commits.
El push tiene que ser forzado, es decir, sobreescribirá el repositorio remoto. Hay que asegurarse de que el repositorio local está actualizado y contiene todo lo que hay en el remoto porque, como digo, el remoto va a ser sobreescrito.
Creo que puede haber otras opciones para aplicar el rebase como merge pero no estoy seguro y esta es la más pragmática.
# Aplicar los cambios y pushear al repo remoto
git status
git push origin +main
Con todo hecho, no hay más que mirar el historial de commits en Github para ver que merece la pena dejarlo bonito.
Reducir historial de commits
rebase
supone cambiar la commit de la que parteHEAD
(commit actual). En tu repositorio,HEAD
parte de la commit anterior, y esta de la anterior, etc. Lo que queremos es queHEAD
parta de la primeraUpdate README.md
de las 9 que hay. Consquash
, lo que hacemos en integrar las commits intermedias enHEAD
. Más adelante se entenderá mejor.Iniciar
git rebase
de las últimas 9 commitsgit clone
mi fork a mi ordenador.git status
para demostrar que el repositorio está tal y como lo he forkeado.git log
y aplicando un formato. Uso un alias del comando completo copio íntegro más adelante.rebase --interactive
de las últimas 9 commits desdeHEAD
(la actual) para poder efectuar elsquash
(el agrupamiento).tldr git rebase
puedes ver información aparte de lo que haya por internet.Aplicar
squash
en VimVim
, nonano
. A continuación detallo los pasos que sigo para hacer lo que hay que hacer. En algunos casos uso key bindings propios así que quizá tengas que usar diferentes teclas para obtener el mismo resultado. Este enlace puede ser de ayuda.1. Cambiar
pick
porsquash
pick
porsquash
para todas las commits menos la de la primera línea.Update README.md
) al estado presente, ignorando todas las commits intermedias (todas las posteriores a la primera hasta el presente) pero manteniendo sus cambios. Por aclarar: esto no altera los archivos del respositorio sino el historial de commits.2. Dejar fuera mensajes de commits
squash
, podemos cambiar el mensaje que veremos enHEAD
(es decir, la commit actual).Update README.md
, se podría añadir el textoRebase commit history
como mensaje aclaratorio. Es innecesario y en este caso no lo hacemos.Vim
para evitar la repetición. Quizá la próxima vez.Push
cambios aHEAD
en el repo remotorebase
, combrobemos el historial de commit tal y como ha quedado.rebase
, lo veríamos en la commit de arriba, que seguirá siendoHEAD
.rebase
hecho, esta es la parte más crítica.push
de los cambios en el repositorio local al repositorio remoto. Si hubiéramos editado archivos lo ideal habría sido hacer un commit antes delrebase
. No es el caso, no hemos editado archivos, solo hemos condensado el historial de commits.push
tiene que ser forzado, es decir, sobreescribirá el repositorio remoto. Hay que asegurarse de que el repositorio local está actualizado y contiene todo lo que hay en el remoto porque, como digo, el remoto va a ser sobreescrito.rebase
comomerge
pero no estoy seguro y esta es la más pragmática.