git stash stocke (ou stashe) temporairement les changements apportés à votre copie de travail pour que vous puissiez effectuer d'autres tâches, revenir et les réappliquer par la suite. Le stash est utile 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 annule 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 des 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 stash 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 grâce à la commande 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'éclatement 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 grâce à la commande 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 du stash, soyez attentif à un point lorsque vous exécutez 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 stashera :

  • les changements ajoutés à votre index (stagés) ;
  • les changements apportés aux fichiers actuellement suivis par Git (non stagés).

Mais cette commande ne stashera pas :

  • les nouveaux fichiers dans votre copie de travail qui n'ont pas encore été stagés ;
  • les 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 ne les stashe pas.

$ 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 vous ajoutez l'option -u (ou --include-untracked), vous demandez à git stash de stasher également vos fichiers non suivis :

$ 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 également inclure des changements aux fichiers ignorés en transmettant l'option -a (ou --all) lorsque vous exécutez 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 stash, puis utiliser git stash list pour les consulter. Par défaut, les stash 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 stash avec une description grâce à 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 en tant que dernier argument, par exemple :

$ git stash pop stash@{2}

Affichage des comparaisons entre stashes

Vous pouvez afficher un résumé d'un stash grâce à la commande git stash show :

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

Sinon, 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 stasher uniquement un fichier, une collection de fichiers ou des changements individuels depuis les fichiers. Si vous transmettez l'option -p (ou --patch) à git stash, elle itérera chaque « bloc » modifié 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
/ Rechercher un bloc par regex
? Aide
n Ne pas stasher ce bloc
q Quitter (tous les blocs déjà sélectionnés seront stashés)
s Diviser ce bloc en plus petits
y Stasher 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 de ceux dans votre stash, vous risquez de rencontrer des conflits lors de l'éclatement ou de l'application de votre stash. À la place, vous pouvez utiliser git stash branch pour créer une 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 check-out, 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 grâce à la commande git stash drop :

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

Vous pouvez également supprimer tous vos stash grâce à la commande suivante :

$ git stash clear

Fonctionnement du stash Git

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

Les stash 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 stash. C'est pour cela que lorsque vous faites référence à des stash grâce à stash@{n}:, vous faites en fait référence à 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 grâce à la commande 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 commits. Les commits dans le diagramme ci-dessus représentent :

  • stash@{0}, un nouveau commit permettant de stocker les fichiers suivis qui se trouvaient dans votre copie de travail lorsque vous avez exécuté 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 au moment où vous avez exécuté git stash ;
  • le troisième parent de stash@{0}, un nouveau commit représentant les fichiers non suivis qui se trouvaient dans votre copie de travail lorsque vous avez exécuté git stash. Ce troisième parent est uniquement créé si :
    • votre copie de travail contenait véritablement des fichiers non suivis ; et
    • vous aviez spécifié l'option --include-untracked ou --all lorsque vous avez appelé git stash.

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

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

    Before stashing
  • Lorsque vous appelez git stash, vous encodez tous les changements apportés aux fichiers suivis sous forme de deux nouveaux commits dans votre graphe orienté acyclique (Directed acyclic graph, 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 de sorte à pointer vers eux.

    Git stash
  • L'option --include-untracked encode également tout changement apporté aux fichiers non suivis sous forme de commit supplémentaire.

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

    Git Stash --all

     

Lorsque vous exécutez git stash pop, les changements introduits par les 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 à supprimer le commit apparu. Notez que les commits apparus ne sont pas immédiatement supprimés, mais deviennent candidats pour une prochaine opération « garbage collection ».

Prêt à découvrir Git ?

Essayez ce tutoriel interactif.

Démarrez maintenant