Salta el contingut
 

Reserva de canvis (stash)

Joan Puigcerver Ibáñez

j.puigcerveribanez@edu.gva.es

Llicència: CC BY-NC-SA 4.0

(Reconeixement - NoComercial - CompartirIgual) 🅭

Reserva de canvis (stash)

La reserva de canvis o stash en Git es un magatzem que permet guardar temporalment els canvis que encara no es volen confirmar (commit).

Aquesta funció és útil si heu de realitzar alguna acció de Git que, d'altra manera, vos faria perdre els canvis que heu realitzat al directori de treball.

  • Canviar de branca.
  • Incorporar canvis d'una altra branca (merge, rebase o pull).

La reserva de canvis permet guardar aquests canvis temporalment i recuperar-los posteriorment quan siga necessari.

Preparació repositori

Inicialitzem un repositori amb canvis en el fitxer README.md i una branca addicional altres_canvis on s'han fet canvis al mateix fitxer.

Danger

Crea el nou repositori en una carpeta independent per evitar problemes amb els exemples i exercicis anteriors.

setup_stash.sh
#!/bin/bash

# Elimina els repositori si existeix
if [ -d ~/git_stash ]; then
    rm -rf ~/git_stash
fi

mkdir -p ~/git_stash
cd ~/git_stash
git init
git branch -m main
echo "# Reserva de canvis" > README.md
git add README.md
git commit -m "Commit inicial"
git checkout -b altres_canvis
echo "Altres canvis" >> README.md
git commit -a -m "Altres canvis"
git checkout main
git lga
jpuigcerver@fp:~ $ mkdir -p ~/git_stash
jpuigcerver@fp:~ $ cd ~/git_stash
jpuigcerver@fp:~/git_stash $ git init
Initialized empty Git repository in ~/git_stash/.git/
jpuigcerver@fp:~/git_stash (main) $ git branch -m main
jpuigcerver@fp:~/git_stash (main) $ echo "# Reserva de canvis" > README.md
jpuigcerver@fp:~/git_stash (main) $ git add README.md
jpuigcerver@fp:~/git_stash (main) $ git commit -m "Commit inicial"
[main (root-commit) 5cc4104] Commit inicial
 1 file changed, 1 insertion(+)
 create mode 100644 README.md
jpuigcerver@fp:~/git_stash (main) $ git checkout -b altres_canvis
Switched to a new branch 'altres_canvis'
jpuigcerver@fp:~/git_stash (altres_canvis) $ echo "Altres canvis" >> README.md
jpuigcerver@fp:~/git_stash (altres_canvis) $ git commit -a -m "Altres canvis"
[altres_canvis 602f4b0] Altres canvis
 1 file changed, 1 insertion(+)
jpuigcerver@fp:~/git_stash (altres_canvis) $ git checkout main
Switched to branch 'main'
jpuigcerver@fp:~/git_stash (main) $ git lga
* 602f4b0 - (0 seconds ago) Altres canvis - Joan Puigcerver (altres_canvis)
* 5cc4104 - (0 seconds ago) Commit inicial - Joan Puigcerver (HEAD -> main)
Per què és útil git stash?

Imaginem que estem treballant en la branca principal main i hem realitzat canvis al fitxer README.md.

Aquests canvis resideixen en el Directori de Treball i encara no han estat confirmats (commit).

En aquest moment, podem decidir canviar a una altra branca. En el cas que aquesta operació modifique la mateixa part dels fitxers on hem realitzat canvis, Git ens impedirà per no perdre aquests canvis.

jpuigcerver@fp:~/git_stash (main) $ echo "Canvi A" >> README.md
jpuigcerver@fp:~/git_stash (main) $ git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")
jpuigcerver@fp:~/git_stash (main) $ git checkout altres_canvis
error: Your local changes to the following files would be overwritten by checkout:
    README.md
Please commit your changes or stash them before you switch branches.
Aborting

Si llegim el missatge d'error, Git ens recomana alguna de les següents opcions.

La primera opció és confirmar (commit) els canvis realitzats. Això ens permetria canviar de branca sense problemes, no obstant això, pot ser que no vulguem confirmar els canvis en aquest moment.

La segona opció és guardar els canvis de manera temporal mitjançant la comanda git stash.

Crear una reserva de canvis

La comanda git stash permet guardar els canvis que s'han realitzat al directori de treball.

git stash [-m <missatge>]

Consell

Amb l'opció -m podem afegir un missatge al stash per identificar millor els canvis guardats.

Els canvis s'emmagatzemen de manera temporal a una pila:

  • Els nous canvis es guardaran a la primera posició de la pila amb l'índex 0: stash@{0}.

    D'aquesta manera, els canvis més actuals es troben a la part superior de la pila i són més fàcils d'accedir (la majoria de comandes stash treballen per defecte amb el stash@{0}).

    Reserva de canvis una única entrada

    Figura 1. Reserva canvis amb una única entrada

  • L'índex dels canvis presents anteriorment a la pila incrementarà en 1.

    Reservar de canvis amb entrades existents anteriorment

    Figura 2. Reservar canvis amb entrades existents anteriorment

Exemple: Crear una reserva de canvis

Després de guardar els canvis amb git stash, podem observar que:

  • Els canvis ja no es troben al Directori de Treball.
  • Podem canviar de branca sense problemes.
jpuigcerver@fp:~/git_stash (main) $ git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")
jpuigcerver@fp:~/git_stash (main) $ git diff
diff --git a/README.md b/README.md
index d6704e3..e23e265 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
 # Reserva de canvis
+Canvi A
jpuigcerver@fp:~/git_stash (main) $ git stash -m "Canvi A"
Saved working directory and index state On main: Canvi A
jpuigcerver@fp:~/git_stash (main) $ git status
On branch main
nothing to commit, working tree clean
jpuigcerver@fp:~/git_stash (main) $ git checkout altres_canvis
Switched to branch 'altres_canvis'
jpuigcerver@fp:~/git_stash (altres_canvis) $ git checkout main
Switched to branch 'main'
Exemple: Crear vàries reserves de canvis

Vegem com l'índex dels canvis incrementa en cada nova reserva.

  • Canvi B:

    jpuigcerver@fp:~/git_stash (main) $ echo "Canvi B" >> README.md
    jpuigcerver@fp:~/git_stash (main) $ git stash -m "Canvi B"
    Saved working directory and index state On main: Canvi B
    jpuigcerver@fp:~/git_stash (main) $ git status
    On branch main
    nothing to commit, working tree clean
    jpuigcerver@fp:~/git_stash (main) $ git stash list
    stash@{0}: On main: Canvi B
    stash@{1}: On main: Canvi A
    

  • Canvi C:

    jpuigcerver@fp:~/git_stash (main) $ echo "Canvi C" >> README.md
    jpuigcerver@fp:~/git_stash (main) $ git stash -m "Canvi C"
    Saved working directory and index state On main: Canvi C
    jpuigcerver@fp:~/git_stash (main) $ git status
    On branch main
    nothing to commit, working tree clean
    jpuigcerver@fp:~/git_stash (main) $ git stash list
    stash@{0}: On main: Canvi C
    stash@{1}: On main: Canvi B
    stash@{2}: On main: Canvi A
    

Mostrar les reserves de canvis

Per mostrar els stash existents, cal executar la comanda:

git stash list

Aquesta comanda mostrarà una llista amb els stash existents, identificats per l'índex i el missatge que s'ha afegit al stash.

Exemple: Mostrar les reserves de canvis
jpuigcerver@fp:~/git_stash (main) $ git stash list
stash@{0}: On main: Canvi C
stash@{1}: On main: Canvi B
stash@{2}: On main: Canvi A

Mostrar els canvis d'una reserva

Els canvis guardats en una reserva de canvis poden ser consultats mitjançant l'acció show. Aquesta acció mostrarà els fitxers que s'han canviat.

git stash show [-p] [index]

Addicionalment, podem mostrar els canvis (diff) mitjançant l'opció -p.

També es pot indicar l'índex del stash que es vol consultar. Si no s'indica, mostrarà per defecte el stash@{0}.

Exemple: Mostrar els canvis d'una reserva
jpuigcerver@fp:~/git_stash (main) $ git stash list
stash@{0}: On main: Canvi C
stash@{1}: On main: Canvi B
stash@{2}: On main: Canvi A
jpuigcerver@fp:~/git_stash (main) $ git stash show -p
diff --git a/README.md b/README.md
index d6704e3..208685c 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
 # Reserva de canvis
+Canvi C
jpuigcerver@fp:~/git_stash (main) $ git stash show -p 1
diff --git a/README.md b/README.md
index d6704e3..5a36536 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
 # Reserva de canvis
+Canvi B
jpuigcerver@fp:~/git_stash (main) $ git stash show -p 2
diff --git a/README.md b/README.md
index d6704e3..e23e265 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
 # Reserva de canvis
+Canvi A

Recuperar els canvis

Els canvis reservats poden recuperar-se mitjançant l'acció apply.

git stash apply [index]

Aquesta acció aplicarà els canvis guardats al directori de treball.

També es pot indicar l'índex del stash que es vol aplicar. Si no s'indica, s'aplicarà per defecte el stash@{0}.

Recuperar canvis amb stash apply

Figura 3. Recuperar canvis amb stash apply

Exemple: Recuperar els canvis amb apply
jpuigcerver@fp:~/git_stash (main) $ git status
On branch main
nothing to commit, working tree clean
jpuigcerver@fp:~/git_stash (main) $ git stash apply
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")
jpuigcerver@fp:~/git_stash (main) $ git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")
jpuigcerver@fp:~/git_stash (main) $ git diff
diff --git a/README.md b/README.md
index d6704e3..208685c 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
 # Reserva de canvis
+Canvi C
jpuigcerver@fp:~/git_stash (main) $ git stash list
stash@{0}: On main: Canvi C
stash@{1}: On main: Canvi B
stash@{2}: On main: Canvi A

Si a més, volem esborrar la reserva de canvis, podem utilitzar l'opció pop.

git stash pop [index]

Recuperar canvis i esborrar la reserva amb stash pop

Figura 4. Recuperar canvis i esborrar la reserva amb stash pop

Exemple: Recuperar els canvis amb pop
jpuigcerver@fp:~/git_stash (main) $ git restore README.md # (1)!
jpuigcerver@fp:~/git_stash (main) $ git status
On branch main
nothing to commit, working tree clean
jpuigcerver@fp:~/git_stash (main) $ git stash pop
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (5421da4ebcbd229b003f105eeefea1b6cfa13f3e)
jpuigcerver@fp:~/git_stash (main) $ git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")
jpuigcerver@fp:~/git_stash (main) $ git diff
diff --git a/README.md b/README.md
index d6704e3..208685c 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
 # Reserva de canvis
+Canvi C
jpuigcerver@fp:~/git_stash (main) $ git stash list
stash@{0}: On main: Canvi B
stash@{1}: On main: Canvi A
  1. Descartem els canvis del Directori de Treball que teníem de l'exemple anterior.

Descartar els canvis

Una reserva de canvis pot ser eliminada de la pila de canvis mitjançant l'acció drop.

git stash drop [index]

També es pot indicar l'índex del stash que es vol descartar. Si no s'indica, es descartarà per defecte el stash@{0}.

Exemple: Descartar els canvis
jpuigcerver@fp:~/git_stash (main) $ git stash list
stash@{0}: On main: Canvi B
stash@{1}: On main: Canvi A
jpuigcerver@fp:~/git_stash (main) $ git stash drop
Dropped refs/stash@{0} (a1be7febfb9e812173942ae63be37375e8d27d13)
jpuigcerver@fp:~/git_stash (main) $ git stash list
stash@{0}: On main: Canvi A
📌 Aquest document pot quedar desactualitzat després d’imprimir-lo. Pots consultar la versió més recent a la pàgina web.
🌿 Abans d’imprimir aquest document, considera si és realment necessari. Redueix el consum de paper i ajuda a protegir el nostre entorn.