El comando

git stash almacena temporalmente (o guarda en un stash) los cambios que hayas efectuado en el código en el que estás trabajando para que puedas trabajar en otra cosa y, más tarde, regresar y volver a aplicar los cambios más tarde. Guardar los cambios en stashes resulta práctico si tienes que cambiar rápidamente de contexto y ponerte con otra cosa, pero estás en medio de un cambio en el código y no lo tienes todo listo para confirmar los cambios.

Cómo guardar el trabajo en un stash

El comando git stash coge los cambios sin confirmar (tanto los que están preparados como los que no los están), los guarda aparte para usarlos más adelante y, acto seguido, los deshace en el código en el que estás trabajando. Por ejemplo:

$ git status
On branch master
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
$ git stash
Saved working directory and index state WIP on master: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch master
nothing to commit, working tree clean

Llegados a este punto, tienes libertad para hacer cambios, crear confirmaciones, cambiar de rama y efectuar cualesquiera otras operaciones de Git; y, luego, regresar y volver a aplicar el stash cuando lo tengas todo listo.

Ten en cuenta que el stash es local para tu repositorio de Git y que los stashes no se transfieren al servidor cuando subes los cambios al repositorio remoto.

Cómo volver a aplicar los cambios de un stash

Puedes volver a aplicar los cambios de un stash mediante el comando git stash pop:

$ git status
On branch master
nothing to commit, working tree clean
$ git stash pop
On branch master
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
Dropped refs/stash@{0} (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)

Al hacer pop del stash, se eliminan los cambios de este y se vuelven a aplicar en el código en el que estás trabajando.

Otra opción es volver a aplicar los cambios en el código en el que estás trabajando y conservarlos en tu stash mediante el comando git stash apply:

$ git stash apply
On branch master
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html

Esto resulta útil si deseas aplicar los mismos cambios de un stash en varias ramas.

Ahora que ya conoces los conceptos básicos de los stashes, hay una puntualización sobre el comando git stash de la que debes ser consciente: de forma predeterminada, Git no guardará en un stash los cambios efectuados en archivos sin seguimiento o ignorados.

Cómo almacenar en un stash archivos ignorados y sin seguimiento

De forma predeterminada, al ejecutar el comando git stash, se guardará en un stash lo siguiente:

  • los cambios que se hayan añadido a tu índice (cambios preparados)
  • los cambios efectuados en archivos de los que Git está haciendo un seguimiento (cambios sin preparar)

Pero no lo siguiente:

  • los archivos nuevos del código en el que estás trabajando que todavía no se hayan preparado
  • los archivos que se hayan ignorado

Así pues, si añadimos un tercer archivo al ejemplo anterior, pero no lo preparamos (es decir, si no ejecutamos el comando git add), git stash no lo guardará en el stash.

$ script.js
$ git status
On branch master
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
Untracked files:
script.js
$ git stash
Saved working directory and index state WIP on master: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch master
Untracked files:
script.js

Si añadimos la opción -u (o --include-untracked), se indica a git stash que también guarde en el stash los archivos sin seguimiento:

$ git status
On branch master
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
Untracked files:
script.js
$ git stash -u
Saved working directory and index state WIP on master: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch master
nothing to commit, working tree clean

También puedes incluir los cambios en los archivos ignorados utilizando la opción -a (o --all) al ejecutar el comando git stash.

Opciones de git stash

Cómo gestionar varios stashes

No tienes por qué limitarte a un solo stash. De hecho, puedes ejecutar git stash varias veces para crea varios stashes y, luego, usar git stash list para verlos. De forma predeterminada, los stashes simplemente mediante el acrónimo "WIP" (que significa "trabajo en curso") en la parte superior de la rama y la confirmación a partir de las cuales creaste el stash. Pasado un tiempo, puede costar acordarse del contenido de cada stash:

$ git stash list
stash@{0}: WIP on master: 5002d47 our new homepage
stash@{1}: WIP on master: 5002d47 our new homepage
stash@{2}: WIP on master: 5002d47 our new homepage

Para contextualizar un poquito más, es recomendable comentar los stashes con una descripción mediante el comando git stash save "mensaje":

$ git stash save "agregar estilo al sitio"
Saved working directory and index state On master: add style to our site
HEAD is now at 5002d47 our new homepage
$ git stash list
stash@{0}: On master: add style to our site
stash@{1}: WIP on master: 5002d47 our new homepage
stash@{2}: WIP on master: 5002d47 our new homepage

De forma predeterminada, git stash pop volverá a aplicar el último stash creado: stash@{0}

Puedes elegir el stash que deseas volver a aplicar poniendo su identificador como último argumento, por ejemplo:

$ git stash pop stash@{2}

Cómo ver las diferencias en un stash

Puedes visualizar un resumen de un stash mediante el comando git stash show:

$ git stash show
index.html | 1 +
style.css | 3 +++
2 files changed, 4 insertions(+)

Otra opción es utilizar la opción -p (o --patch) para ver todas las diferencias de un stash:

$ git stash show -p
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..d92368b
--- /dev/null
+++ b/style.css
@@ -0,0 +1,3 @@
+* {
+ text-decoration: blink;
+}
diff --git a/index.html b/index.html
index 9daeafb..ebdcbd2 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,2 @@
+<link rel="stylesheet" href="style.css"/>

Stashes parciales

También puedes optar por guardar en un stash solo un archivo, una colección de archivos o cambios sueltos de los archivos. Si utilizas la opción -p (o --patch) en el comando git stash, este irá iterando cada uno de los "fragmentos" modificados del código en el que estás trabajando y te preguntará si deseas guardarlo en un stash:

$ git stash -p
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..d92368b
--- /dev/null
+++ b/style.css
@@ -0,0 +1,3 @@
+* {
+ text-decoration: blink;
+}
Stash this hunk [y,n,q,a,d,/,e,?]? y
diff --git a/index.html b/index.html
index 9daeafb..ebdcbd2 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,2 @@
+<link rel="stylesheet" href="style.css"/>
Stash this hunk [y,n,q,a,d,/,e,?]? n
git stash -p

Puedes pulsar en ? para ver una lista completa de los comandos para los fragmentos. Los siguientes suelen resultar útiles:

Comando Descripción
/ buscar un fragmento mediante expresiones regulares
? ayuda
n no guardar este fragmento en un stash
q salir (se guardarán en un stash todos los fragmentos ya seleccionados)
s dividir este fragmento en otros más pequeños
y guardar este fragmento en un stash

No hay ningún comando explicito para "anular" el comando, pero si pulsas CTRL+C (SIGINT) se anulará el proceso de stash.

Cómo crear una rama a partir de un stash

Si los cambios en la rama divergen de los cambios en el stash, podrías encontrarte con conflictos al hacer pop del stash o al aplicarlo. En vez de eso, puedes usar git stash branch para crear una rama nueva en la que aplicar los cambios del stash:

$ git stash branch add-stylesheet stash@{1}
Switched to a new branch 'add-stylesheet'
On branch add-stylesheet
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
Dropped refs/stash@{1} (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)

De este modo, se extrae una rama nueva basada en la confirmación a partir de la cual creaste el stash y, después, se hace pop en ella con los cambios del stash.

Cómo limpiar el stash

Si decides que ya no necesitas algún stash en particular, puedes eliminarlo mediante el comando git stash drop:

$ git stash drop stash@{1}
Dropped stash@{1} (17e2697fd8251df6163117cb3d58c1f62a5e7cdb)

También tienes la opción de eliminar todos los stashes mediante el siguiente comando:

$ git stash clear

Cómo funciona git stash

Si lo único que querías saber era cómo usar git stash, ya puedes dejar de leer. Ahora bien, si te pica la curiosidad por saber cómo funciona Git (y git stash) entre bambalinas, sigue leyendo.

En realidad, los stashes se codifican en el repositorio como objetos de confirmación. La referencia especial en .git/refs/stash te dirige al último stash creado, y el registro de referencias de la referencia de stash hace referencia a los stashes creados anteriormente. Es por este motivo por el que nos referimos a los stashes empleando stash@{n}: a lo que nos referimos realmente es a la n.ª entrada del registro de referencias de la referencia del stash. Dado que un stash es solo una confirmación, puedes inspeccionarla mediante el comando git log:

$ git log --oneline --graph stash@{0}
*-. 953ddde WIP on master: 5002d47 our new homepage
|\ \
| | * 24b35a1 untracked files on master: 5002d47 our new homepage
| * 7023dd4 index on master: 5002d47 our new homepage
|/
* 5002d47 our new homepage

En función de lo que hayas guardado en un stash, una sola operación git stash creará dos o tres confirmaciones nuevas. Las confirmaciones del diagrama anterior son las siguientes:

  • stash@{0}: una nueva confirmación para almacenar los archivos que estaban en el código en el que estabas trabajando cuando ejecutaste el código git stash
  • la primera confirmación principal de stash@{0}, es decir, la confirmación preexistente que se hallaba en HEAD cuando ejecutaste git stash
  • la segunda confirmación principal de stash@{0}, una nueva confirmación que representa el índice cuando ejecutaste git stash
  • la tercera confirmación principal de stash@{0}, una nueva confirmación que representa los archivos sin seguimiento que estaban en el código en el que estabas trabajando cuando ejecutaste git stash. Esta tercera confirmación principal solo se crea en los supuestos siguientes:
    • si el código en el que estabas trabajando contenía realmente archivos sin seguimiento; y
    • si especificaste la opción --include-untracked o --all al invocar git stash.

Cómo codifica el comando git stash tu árbol de trabajo y tu índice como confirmaciones:

  • Antes de ejecutar el comando stash, el árbol de trabajo podía contener cambios en archivos con seguimiento, sin seguimiento e ignorados. Además, algunos de estos cambios podrían estar preparados en el índice.

    Before stashing
  • Si invocas git stash, todos los cambios efectuados en los archivos con seguimiento se codifican como dos confirmaciones nuevas en el DAG: una para los cambios sin preparar y la otra para los cambios preparados en el índice. La referencia especial refs/stash se actualiza para apuntar hacia ellos.

    Git stash
  • Si utilizas la opción --include-untracked, también se codifican todos los cambios efectuados en los archivos sin seguimiento como una confirmación adicional.

    Git stash --include-untracked
  • Si utilizas la opción --all, se incluyen todos los cambios efectuados en todos los archivos ignorados, así como los realizados en los archivos sin seguimiento de la misma confirmación.

    Git Stash --all

     

Cuando ejecutas el comando git stash pop, los cambios de las confirmaciones anteriores se emplean para actualizar el código y el índice con el que estás trabajando, y el registro de referencias del stash se ordena aleatoriamente para eliminar la confirmación de la que se ha hecho pop. Ten en cuenta que las confirmaciones de las que se ha hecho pop no se eliminan inmediatamente, sino que se convierten en candidatas para la futura recopilación de basura.

¿Listo para aprender a usar Git?

Prueba este tutorial interactivo.

Comienza ahora