AprendeGit
Capítulo 13 7 min de lectura 4 secciones

Stash, el almacén temporal de cambios

Guarda, aplica y elimina cambios temporales con stash.

A la hora de trabajar con Git no es raro que tengas que cambiar activamente entre ramas. Imagina que estás en una rama, desarrollando una funcionalidad, y de repente te das cuenta que hay un error en la rama principal. ¿Qué puedes hacer?

Por un lado, podrías crear un commit en tu rama para grabar los cambiosy, así, volver más tarde. Normalmente es la solución ideal, especialmente si quieres que ese cambio sea accesible por otras personas.

Sin embargo, si tu trabajo está a medias, es posible que no quieras hacercommitpero tampoco quieras perder los cambios. Otraopciónseríaclonarelrepositorioen otra ubicación y trabajar en esa copia, para tener dos copias y así que no se pierda ningún cambio.

Pero… ¿Qué pasa si no quieres grabar los cambios y tampoco quieres clonar el repositorio otra vez… pero no quieres perder los cambios? Para ello existe el stash, un almacén temporal de cambios. El almacén tiene forma de pila, de forma que se van apilando los cambios que tienes en tu directorio de trabajo en un momento dado para que puedas recuperarlos más tarde.

Git Stash es un almacén temporal para cambios que no queremos grabar pero tampoco queremos perder

Guarda tus cambios en un stash

En primer lugar tienes que tener en cuenta que los cambios que puedes almacenar en la pila provisional son los cambios que has hecho en tu directorio de trabajo o que se encuentran ya en el área de staging. Dicho de otra forma, cualquier cambio que no hayas todavía confirmado.

Para asegurarte de qué cambios serán los que almacenes en el stash, puedes usar primero el comando git statusy ver qué cambios están pendientes de grabar con un commit.

Imaginemos que tenemos un repositorio, con algún commit previo, donde hemos modificado dos ficheros. Uno lo hemos añadido ya al área destagingy otro lo hemos dejado modificado en el área de trabajo:

$ git status
On branch main
Changes to be committed:
modified: component.js

Changes not staged for commit: modified: index.js

Ahora quiero cambiar de rama y trabajar en otra cosa pero no quiero perder estos cambios. Vamos a almacenarlos en el almacén temporal de cambios (stash)

$ git stash
Saved working directory and index state WIP on main: ff56eac commit

git stashes la forma corta de git stash push. La diferencia es que git stashno acepta todos los argumentos que puedes usar con push.

¡Ya has creado tu primer almacén temporal de cambios! Si vuelvas a ejecutar git statusverás que ahora no tienes cambios en tu área de trabajo:

$ git status
On branch main
nothing to commit, working tree clean

¿Han desaparecido? ¡No! Están en una pila provisional, pero no en el área de trabajo. Esta pila es localy puedes revisarlo en la carpeta.git/refs/stash. Esto significa dos cosas:

  • No se transfieren al repositorio remoto.
  • Si borras tu repositorio local, perderás la pila de cambios temporales.

Para asegurarte que está a buen recaudo, puedes ejecutar el comando git stash list para ver los almacenes temporales disponibles que has creado:

$ git stash list

stash@{ 0 }: WIP on main: ff56eac commit

No confundas el área de almacenaje temporal (stash) con el área temporal transitoria (staging). El primero es, simplemente, un cajón dónde apilar cambios que puede ser que queramos recuperar más adelante y el segundo es una fase anterior a grabar los cambios en el repositorio.

¡Cuidado con los archivos nuevos creados!

Por defecto, git stashsólo almacena los ficheros modificados. Si estás creando un fichero por primera vez, que nunca ha sido grabado con uncommital repositorio, no lo almacenará por defecto y podrías perderlo si no se lo indicas…

# creamos un nuevo fichero new-file en el repositorio
$ touch new-file.html

# vemos que el nuevo fichero aparece sin seguimiento
$ git status
On branch main
Untracked files:
new-file.html

# al crear la entrada en el stash, nos dice que no

$ git stash
Nolocal changes to save

Como ves, no se ha grabado nada en el almacén temporal porque el fichero era nuevo. ¡Ten mucho cuidado! A veces, si mezclas entre ficheros modificados y ficheros creados, podría indicarte que elstashha funcionado correctamente… pero lo cierto es quesólo habrá almacenado los ficheros modificados y no los creados.¡Fíjate!

# creamos un nuevo fichero new-file en el repositorio
$ touch new-file.html

# modificamos en el editor el fichero index.js
$ nano index.js

# revisamos el estado de los ficheros
$ git status
On branch main
Changes not staged for commit
modified: index.js
Untracked files:
new-file.html
# movemos los cambios locales a un stash
$ git stash
Saved working directory and index state WIP on main:
afaf06b first branch commit
# al mirar el status vemos que el fichero new-file.html
# está todavía como sin seguimiento
$ git status
On branch main
Untracked files:
new-file.html
# y luego veríamos que el stash no tiene
# el fichero new-file.html
# ¡Si lo borramos, lo perderíamos!

Para solucionar esto debes usar la opción—include-untrackedo, de forma más corta, -u. De esta forma le indicamos a git stashque también queremos guardar en la pila provisional los archivos de los que todavía no hacemos un seguimiento.

# guarda en el almacenaje temporal también los recién creados
$ git stash -u
Saved working directory and index state WIP on main:
5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch main
nothing to commit, working tree clean

Puedes incluso incluir archivos ignorados por Git en el almacén temporal. Para ello, usa la opción—allo, de forma más corta,-a. Ten en cuenta que sólo puedes hacer git stashen un repositorio que tenga, como mínimo, uncommitya grabado. De lo contrario, te dará un error.

Comentando stashes con descripción

Como has podido ver en el ejemplo anterior cuando hemos visto la lista destashes disponibles, los nombres no son excesivamente útiles. Esto es porque por defecto, git stashguarda las modificaciones locales y le genera un nombre como”WIP on : ”.

Si tuvieramos tres cambios en la pila temporal de una misma rama, lo veríamos así:

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

No es muy útil, ¿verdad? Es difícil saber qué cambios han sido grabados en cada stash. ¡Vamos a solucionarlo! Si quieres añadir un mensaje más descriptivo para saber qué es lo que has hecho, puedes añadir la opción-mo—messagede forma que puedas añadir una descripción personalizada.

$ git stash -m "Trying new images types"
Saved working directory and index state On main:
Trying new images types
$ git stash list
stash@{ 0 }: On my-branch: Trying new images types

git stash -m <descripción>es la forma corta de usar el comando git stash push —message <descripción>. Existe otro comando en git stashque te permite añadir un comentario. Es git stash save. Sin embargo, esta opción está obsoleta y no se recomienda usarla. En su lugar, usa git stash pushpara añadir un comentario a un stash.

Aplicando los cambios del stash

Si tienes cambios en el almacén temporal (stash) y quieres recuperarlos tienes dos opciones para hacerlo. La primera opción los recuperará pero los eliminará de la pila mientras que la segunda forma los aplicará y los mantendrá igualmente en el stash.

Aplicar y eliminar cambios del stash

Como hemos dicho, el almacén temporal es como una pila donde se van acumulando los cambios. Por eso, es muy conveniente tener un sub comandopopque aplicará los últimos cambios almacenados. Una vez aplicados los sacará del almacén temporal.

$ git status
On branch main
nothing to commit, working tree clean

$ git stash list
stash@{ 0 }: On main: Changes on index.html file
stash@{ 1 }: On main: Trying new images types

# le decimos que queremos aplicar los últimos

$ git stash pop
On branch main

Changes not staged for commit: modified: index.html

Dropped refs/stash@{ 0 } (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)

# vemos los cambios que quedan en el almacén
$ git stash list
stash@{ 0 }: On main: Trying new images types

# se ha eliminado el índice 0 y el que estaba

Los stashes se guardan en forma de pila por lo que si haces un pop, entonces recuperarás directamente el último guardado y lo extraerá de ahí

Si tienes archivos modificados en tu directorio de trabajo al aplicar un stash y estos son los mismos que se verían afectados por el stash, entoncespodrías recibirunproblemaindicandoquetuscambioslocalestienenquesergrabados, eliminados o guardados en otro stash antes de seguir. Los cambios no aplicados no se perderán de la pila.

Aplicar un stash sin eliminarlo

Mientras quepopaplica y elimina un stash de la pila temporal, applylo aplica sin eliminarlo. Es bastante útil cuando quieres aplicar un mismo cambio a diferentes ramas o, simplemente, por si quieres aplicar un cambio y conservarlo en el stash.

# para aplicar el último cambio que hemos guardado
$ git stash apply

# para aplicar el cambio guardado en un índice
$ git stash apply stash@{ 0 }

# también se puede usar directamente el número
$ git stash apply 2

Crea una rama a partir de un stash

A veces los cambios que has hecho en el almacén temporal son demasiado golosos para dejarlos ahí. Por suerte, git stashte ofrece un comando para comenzar una nueva rama a partir de un stash.

Para ello, debes usar el comando git stash brancho git stash branch e indicarle el índice del stash que quieres usar. El índice lo puedes ver al usar el comando git stash listenvuelto entre llaves stash@{n}dondenes el índice del stash.

$ git stash list
stash@{ 0 }: On my-branch: Trying new images types
stash@{ 1 }: On my-branch: Optimize styles

# le indicamos a git que queremos crear una rama a partir

$ git stash branch optimize-css 1

Switched to a new branch’optimize-css’ On branch css Changes not staged for commit: modified: styles.css

Dropped refs/stash@{ 1 } (aca9b94292a7d37977095916cd9d212c09e137b6)

¡Ten en cuenta que al hacer esta operaciónelstashseperderádelapilatemporal! Por desgracia no existe ningún argumento que puedas pasar para evitar esto.

Crear una rama de un stash es útil cuando los cambios que almacenaste en el stash podrían dar conflictos al aplicarlos en la rama. Dicho de otra forma, que los archivos del directorio de trabajo difieren tanto que recuperar los cambios del stash podría ser un lío.

Esto es porque la rama que va a crear lo hará con el HEADapuntando al commit cuando se creó el stash. Así no tendrás conflictos al crear la rama.

Eliminando el almacén temporal

Si quieres eliminar el almacén temporal, puedes usar el comando git stash drope indicar la posición del stash que quieres eliminar.

# revisamos todos los stashes disponibles
$ git stash list
stash@{ 0 }: On my-branch: Trying new images types
stash@{ 1 }: On my-branch: Optimize styles

# eliminamos el stash en la posición 1
$ git stash drop 1
Dropped refs/stash@{ 1 } (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)

Si quieres que eldropno muestre ningún tipo de información, puedes pasar el argumento—quieto-q.

Si tienes claro que lo que quieres es limpiar la pila entera destashes, puedes usar el comando git stash clear.

# eliminar todos los stashes
$ git stash clear

¡Ten mucho cuidado! Limpiar la pila del almacén temporal no requiere ningún tipo de confirmación. Al ejecutar el comando git stash clear, todos los stashes serán eliminados… sin preguntas ni segundas oportunidades.

¿Terminaste de leer la teoría?

Márcalo para registrar tu avance y salta al quiz.

Quiz de comprobación

3 preguntas · 70% para aprobar
  1. 1

    ¿Qué hace `git stash`?

  2. 2

    ¿Cómo recuperas los cambios del último stash y lo eliminas de la pila?

  3. 3

    ¿Qué comando muestra la lista de stashes guardados?

¿Quieres practicar comandos reales? Abre la terminal simulada y experimenta sin miedo.

Abrir terminal