Trucos con comandos: guardar cambios con git

guardar cambios con gitGuardar cambios con git es sencillo mediante este truco-tutorial que os traigo hoy. A veces, mientras estás haciendo modificaciones en el código, otro miembro del equipo sube cambios que necesitas (o te resultan útiles de cualquier modo, correcciones de bugs, o nueva funcionalidad que resuelve el problema con el que te enfrentas). Es habitual hacer un commit, a continuación merge de la rama que contiene el cambio y continuar trabajando. Trabajar así no supone realmente un problema, salvo que estés intentando mantener un historial limpio en el repositorio (o que te interese que los cambios contengan funcionalidad completa, como vimos en el articulo sobre deshacer cambios con git).
Otra situación parecida ocurre cuando, si eres despistado, haces cambios sobre una rama que no deberías. Puedes intentar volver a la rama correcta antes de hacer el commit, pero lo más probable es que git te lo impida (precisamente porque hay cambios sin guardar).

1.- Guardar cambios con git sin hacer commit

En cualquier caso, lo que queremos es guardar cambios sin hacer commit. Y, sí, se puede, podemos guardar cambios con git.
Se puede guardar cambios con git stash temporalmente (como si de un commit se tratase). Stash guarda todos los cambios presentes y a continuación hace un hard reset al último commit (no es exactamente así, pero el resultado es el mismo):

$ git status
# On branch feature
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: wp-config-sample.php
#
$ git stash
Saved working directory and index state WIP on feature: 9c8a12a ....
HEAD is now at 9c8a12a ...
$ git status
# On branch feature
nothing to commit, working directory clean


El stash es común a todas las ramas. Ahora podemos cambiar de rama, hacer cambios sobre ésta, etc. Nuestros cambios seguirán en el stash, y podremos verlos con:

$ git stash list
stash@{0}: WIP on feature: 9c8a12a ...


Siguiendo con el primer ejemplo del artículo, vamos a mezclar con master, que contiene cambios necesarios para continuar trabajando (aún estamos en la rama “feature”):

$ git merge master
...

2.- Recuperar el contenido del stash

Y a continuación, vamos a recuperar el contenido del stash para continuar con nuestro trabajo:

$ git stash pop
# On branch feature
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: wp-config-sample.php
#

Ahí veis como el resultado es exactamente el mismo que el de git status antes de guardar cambios. La diferencia es que en el historial no aparece ningún commit entre el estado anterior (9c8a12a, en este ejemplo) y el merge con master, de forma que nuestros cambios están pendientes de hacer un commit posterior a la mezcla:

$ git log
abae6d2 merge master into feature
9c8a12a ...

El comando pop intentará aplicar los cambios contenidos en el stash sobre el código actual, independientemente de en qué rama nos encontremos. De esta forma, para solucionar el segundo ejemplo que planteábamos (nos hemos equivocado de rama donde hacer los cambios), simplemente habría que cambiar a la rama “correcta” antes de hacer el pop:

$ git status
# On branch feature
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: wp-config-sample.php
#
$ git stash
Saved working directory and index state WIP on feature: 9c8a12a ....
HEAD is now at 9c8a12a ...
$ git checkout master
Switched to branch 'master'
$ git stash pop
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: wp-config-sample.php
#

En este caso la diferencia antes y después del stash es simplemente el cambio de rama (lo muestra el mensaje de status en cada momento). Si ahora hacemos commit de los cambios, los estaremos haciendo sobre “master” en lugar de “feature“.

Por último, si quisiésemos descartar los cambios en el stash, el comando drop (git stash drop) elimina definitivamente ese conjunto de cambios (cuidado, porque se pierden de verdad). Tenéis más información sobre git stash en la página del manual o mediante git help stash.