Uno de los trucos mas utiles es el de fusionar commits, que permite fusionar una serie de commits consecutivos en solo uno. Por ej, si se necesita condensar los ultimos 6 commits, se deben ejecutar los siguientes comandos:
git reset --soft HEAD~6Previamente a ejecutar el comando commit, se pueden (o no) realizar los ajustes adicionales que se consideren necesarios
git commit -m 'mensaje de commit'
Como disclaimer aclaro que no se deben fusionar commits que ya se hayan pusheado
Deshacer
Para deshacer el efecto de los dos comandos, se debe restaurar el branch a su estado original, asi:
git reset --hard HEAD@{2}
Git reset
git reset es el comando que permite modificar a mismo tiempo el puntero HEAD y el puntero del branch activo.
Si se usa con --soft mantiene el indice y el working tree, por lo que todo queda listo para efectuar el commit, en este caso se reseteo el branch activo a un estado 6 commits previos al que se encontraba manteniendo el contenido del ultimo commit en el indice por lo que el commit posterior sera equivalente en contenido al ultimo commit con la diferencia de que el parent sera el viejo commit y asi este por si solo contendra el cambio hecho por los otros 6
Para deshacer, se utilizo git reset --hard para restaurar el estado del branch a como era antes, --hard indica que no se mantienen ni el indice ni el working copy
HEAD~6
Hace referencia al commit que esta 6 pasos atras del commit HEAD (el commit activo), en el ejemplo se pudo haber especificado otra cosas como un SHA, un branch, un tag, una entrada de reflog, etc... Ejemplos:
Resetea al remote master para que el proximo commit tenga el remote branch como parent
git reset --soft origin/masterResetea a un commit especifico por SHA para que el proximo commit tenga ese commit como parent
git reset --soft 01abcdefHEAD@{2}
Hace referencia a una entrada en el reflog, el reflog es un registro de los valores que adquiere una ref, el reflog principal es el de HEAD al que se puede acceder a todos los valores que HEAD ha adquirido historicamente. HEAD@{1} hara referencia al anterior del ultimo valor que adquierio, HEAD@{2} hara referencia al anterior del anterior y asi sucesivamente...
Y sea que se efectuen commits, resets, checkouts o lo que sea las entradas de reflog permiten acceder a los commits previos, muy util para localizar commits "perdidos"
Links
- Manual de git-reset: http://www.kernel.org/pub/software/scm/git/docs/git-reset.html
- Manual de git-rev-parse (explica el lenguaje de los commits): http://www.kernel.org/pub/software/scm/git/docs/git-rev-parse.html
Se debe tener cuidado con el reset ya que si luego se quiere pushear los cambios a un servidor, puede aparecer algo como esto:
ResponderEliminarerror: src refspec (no does not match any.
error: src refspec branch) does not match any.
error: failed to push some refs to 'https://github.com/usuario/repositorio'
El ejemplo es de Github, pero es posible que se den errores similares en Bitbucket, Gitorius y otros sitios. Lo mas recomendable seria hacer un squash con rebase tal como lo explican aquí y luego forzar el push.