sábado, 6 de agosto de 2011

Fusionar commits

No hay excusa para no commitear con la frecuencia que mas nos convenga, ya que existen formas de editar el historial antes de publicarlo.
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~6
git commit -m 'mensaje de commit'
Previamente a ejecutar el comando commit, se pueden (o no) realizar los ajustes adicionales que se consideren necesarios

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/master
Resetea a un commit especifico por SHA para que el proximo commit tenga ese commit como parent
git reset --soft 01abcdef
HEAD@{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

1 comentario:

  1. Se debe tener cuidado con el reset ya que si luego se quiere pushear los cambios a un servidor, puede aparecer algo como esto:

    error: 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.

    ResponderEliminar