git stash stocke (ou stashe) temporairement les changements apportés à votre copie de travail pour que vous puissiez effectuer d'autres tâches, puis revenir et les réappliquer par la suite. Le stashing est pratique si vous avez besoin de changer rapidement de contexte et de travailler sur autre chose, mais que vous êtes en plein dans un changement de code et que n'êtes pas tout à fait prêt à commiter.

Faire un stash de votre travail

La commande git stash prend vos changements non commités (stagés et non stagés), les enregistre pour une utilisation ultérieure, puis les replace dans votre copie de travail. Par exemple :

$ 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

À ce stade, vous pouvez procéder à des changements, créer de nouveaux commits, basculer entre des branches et effectuer toute autre opération Git, puis revenir et réappliquer votre stash lorsque vous êtes prêt.

Notez que le stash est local pour votre dépôt Git. Les stashes ne sont pas transférés au serveur lors d'un push.

Appliquer à nouveau vos changements stashés

Vous pouvez réappliquer les changements stashés au préalable avec 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)

L'apparition de votre stash supprime les changements qu'il contient et les réapplique à votre copie de travail.

Vous pouvez également réappliquer les changements à votre copie de travail et les conserver dans votre stash avec 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

C'est utile si vous souhaitez appliquer les mêmes changements stashés à plusieurs branches.

Maintenant que vous connaissez les bases de la mise en stash, vous devez être attentif à un point avec git stash : par défaut, Git ne fera pas de stash des changements apportés aux fichiers non suivis ou ignorés.

Faire un stash des fichiers non trackés ou ignorés

Par défaut, l'exécution de git stash fera un stash :

  • des changements qui ont été ajoutés à votre index (changements stagés)
  • des changements apportés aux fichiers actuellement trackés par Git (changements non stagés)

Mais elle ne fera pas un stash :

  • des nouveaux fichiers dans votre copie de travail qui n'ont pas encore été stagés ;
  • des fichiers qui ont été ignorés.

Par conséquent, si nous ajoutons un troisième fichier à notre exemple ci-dessus, mais que nous ne le stageons pas (autrement dit, nous n'exécutons pas git add), git stash n'en fera pas un 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

Ajouter l'option -u (ou --include-untracked) dit à git stash de stasher également vos fichiers non trackés :

$ 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

Vous pouvez inclure des changements aux fichiers ignorés aussi bien en transmettant l'option -a (ou --all) lors de l'exécution de git stash.

Options Git Stash

Gérer plusieurs stashes

Vous n'êtes pas limité à un stash unique. Vous pouvez exécuter git stash à plusieurs reprises pour créer différents stashes, puis utiliser git stash list pour les consulter. Par défaut, les stashes sont simplement identifiés comme « WIP » (Work in progress, travail en cours) en haut de la branche et du commit à partir duquel vous avez créé le stash. Après un certain temps, il peut être difficile de se souvenir de ce que contient chaque 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

Pour donner plus de contexte, il peut être judicieux d'annoter vos stashes avec une description avec git stash save "message" :

$ git stash save "add style to our site"
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

Par défaut, git stash pop réappliquera le stash créé le plus récemment : stash@{0}

Vous pouvez choisir le stash à réappliquer en transmettant son identifiant comme le dernier argument, par exemple :

$ git stash pop stash@{2}

Affichage des comparaisons entre stashes

Vous pouvez afficher un résumé d'un stash avec git stash show :

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

Ou transmettez l'option -p (ou --patch) pour afficher la comparaison complète d'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 partiels

Vous pouvez également choisir de ne stasher qu'un fichier, qu'une collection de fichiers ou que des changements individuels depuis les fichiers. Si vous transmettez l'option -p (ou --patch) à git stash, elle itérera chaque « bloc » changé dans votre copie de travail et vous demandera si vous souhaitez le stasher :

$ 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

Appuyez sur ? pour obtenir une liste complète des commandes de bloc. Les plus fréquemment utilisées sont :

Commande Description
/ recherche d'un bloc via regex
 ? Aide
n Ne pas faire un stash de ce bloc
q quit (les blocs déjà sélectionnés seront stashés)
s Divise ce bloc en plus petits
y Faire un stash de ce bloc

Il n'existe aucune commande « d'annulation », mais appuyer sur CTRL-C(SIGINT) annulera le processus de stash.

Créer une branche depuis votre stash

Si les changements sur votre branche divergent des changements dans votre stash, vous risquez de rencontrer des conflits lors de l'apparition ou de l'application de votre stash. À la place, vous pouvez utiliser git stash branch pour créer une nouvelle branche à laquelle appliquer vos changements stashés :

$ 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)

Une nouvelle branche basée sur le commit à partir duquel vous avez créé votre stash fera l'objet d'un checkout, et vos changements stashés y figureront.

Nettoyez votre stash

Si vous décidez que vous n'avez plus besoin d'un stash spécifique, vous pouvez le supprimer git stash drop :

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

Vous pouvez également supprimer tous les stashes avec :

$ git stash clear

Fonctionnement du stash Git

Si vous désiriez simplement savoir comment utiliser git stash, vous pouvez vous arrêter de lire. Mais si vous souhaitez comprendre les rouages de Git (et de git stash), poursuivez votre lecture !

Les stashes sont en fait encodés dans votre dépôt en tant qu'objets de commit. La référence spéciale à .git/refs/stash pointe vers votre stash le plus récent, et les stashes créés au préalable sont référencés par le reflog de la référence stash. C'est pour cela que vous renvoyez vers les stashes via stash@{n}:, vous renvoyez en fait à l'entrée n du reflog pour la référence stash. Étant donné qu'un stash n'est qu'un commit, vous pouvez l'inspecter avec 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 fonction de l'élément stashé, une opération git stash unique crée deux ou trois nouveaux commits. Les commits dans le diagramme ci-dessus représentent :

  • stash@{0}, un nouveau commit pour stocker les fichiers trackés qui se trouvaient sur votre copie de travail lors de l'exécution de git stash ;
  • le premier parent de stash@{0}, le commit préexistant qui se trouvait au niveau de HEAD lorsque vous avez exécuté git stash ;
  • le deuxième parent de stash@{0}, un nouveau commit représentant l'index lorsque vous exécutez git stash
  • Le troisième parent de stash@{0}, un nouveau commit représentant les fichiers non trackés qui se trouvaient sur votre copie de travail lors de l'exécution de git stash. Ce troisième parent est uniquement créé si :
    • votre copie de travail contient réellement des fichiers non trackés ; et si
    • vous avez spécifié l'option --include-untracked ou l'option --all lorsque vous avez appelé git stash.

Voici comment git stash encode votre arborescence de travail et votre index sous forme de commits :

  • Avant de faire un stash, l'arborescence de travail peut contenir des changements apportés aux fichiers trackés, non trackés et ignorés. Certains de ces changements peuvent également être stagés dans l'index.

    Avant de faire un stash
  • Appeler git stash encode tous les changements apportés aux fichiers trackés sous forme de deux nouveaux commits dans votre graphe orienté acyclique (DAG) : un pour les changements non stagés et un pour les changements stagés dans l'index. La réf refs/stash spéciale est mise à jour pour pointer vers eux.

    Git Stash
  • L'utilisation de l'option --include-untracked encode également tout changement apporté aux fichiers non trackés sous forme de commit supplémentaire.

    Git stash --include-untracked
  • Utiliser l'option --all inclut les changements apportés à tous les fichiers ignorés avec les changements apportés aux fichiers non trackés dans le même commit.

    Git Stash --all

     

Lorsque vous exécutez git stash pop, les changements des commits ci-dessus sont utilisés pour mettre à jour votre copie de travail et votre index, et le reflog du stash est remanié de sorte à enlever le commit apparu. Notez que les commits apparus ne sont pas immédiatement supprimés, mais deviennent candidats pour une prochaine « garbage collection ».

Prêt à découvrir Git ?

Essayez ce tutoriel interactif.

Démarrez maintenant