Mettre du travail de côté avec le stash
Par Maxime Bréhin • Publié le 18 octobre 2021 • 4 min

Il arrive régulièrement qu’on ait besoin de mettre du travail de côté le temps de traiter une tâche prioritaire sur notre projet ou de récupérer les nouveautés produites par nos collègues qui sont nécessaires à notre travail courant. Plutôt que de créer un commit dont les contenus seront mal finis, nous préférerons isoler ce travail dans la remise Git, appelée stash en anglais.

Vous préférez une vidéo ?

Si vous êtes du genre à préférer regarder que lire pour apprendre, on a pensé à vous :

Principes de fonctionnement

Le scénario d’utilisation classique est le suivant :

  • on met de côté ;
  • on réalise la tâche prioritaire ;
  • on reprend ce qu’on avait mis de côté.

Le stash est une zone au même titre que la copie de travail (working directory), le stage et le dépôt local. On y place tout ou partie du travail en cours en appelant la commande git stash ….

Il est géré sous forme de pile, c’est-à-dire qu’on peut y ajouter plusieurs lots de modifications et que ces lots seront « empilés ». Ça signifie que pour « dépiler », on récupérera par défaut le dernier lot inséré (sauf appel explicite).

Fonctionnement de Git stash sans option

Note : si vous n’êtes pas à l’aise avec les zones et états Git, vous pouvez comprendre ces mécanismes dans notre cours gratuit d’introduction aux concepts fondamentaux de Git. Pour un rappel plus succinct, nous vous recommandons cette cheatsheet interactive très complète.

Que désigne-t-on par « travail en cours » ?

Il s’agit des fichiers connus de Git (ayant déjà fait l’objet de commits antérieurs) qui ont subi des modifications ou qui ont été supprimés.

De base ça exclut les nouveaux fichiers (non suivis par Git), mais l’option -u (ou sa version longue --include-untracked) nous permet de forcer leur mise dans le stash.

Ajouter les untracked avec -u

Comprendre ce qu’on peut mettre dans le stash et comment

Classiquement on met tout ce qui “traîne” dans le stash sans trop se poser de question. La plupart des gens utilisent alors git stash sans option. Ceci a pour conséquence d’ajouter dans le stash une entrée nommée sur la base du message du commit courant, préfixé par “WIP” (Working In Progress / travail en cours) et le nom de la branche courante.

Liste de stash mal nommés

Ça n’est clairement pas idéal pour déterminer ce que contient l’enregistrement dans le stash. Aussi nous recommandons-vous, comme pour un commit, de bien nommer votre stash : git push -m 'Un message clair concernant le stash'.

Pour résumer, l’usage “classique” que nous vous recommandons pour mettre du travail de côté consiste à prendre tout le travail en cours, nouveaux fichiers compris, et de nommer tout ça correctement :

git stash push -u -m 'Message clair'

Doit-on tout mettre dans le stash ?

Git nous permet de faire du stash chirurgical, en choisissant précisément les fichiers, voire les portions de fichiers qu’on souhaite mettre de côté.

Pour choisir les fichiers, il suffit de les désigner via leur chemin complet ou des globs (exemple : git stash index.txt styles/*.css).

Pour l’ajout de portions de fichiers on utilisera l’option interactive git stash push -p … (ou --patch) qui nous proposera de choisir parmi des segments de modifications (équivalent de git add -p … pour l’ajout au stage).

Ajout chirugical avec l’option --patch

Analyser le stash

On a parfois besoin de vérifier ou analyser ce qui est contenu dans le stash.

De base bon nombres d’interfaces graphiques et terminaux améliorés (via le prompt) sauront vous retransmettre une information globale sur le nombre d’entrées présentes dans le stash. Ensuite vous devrez aller chercher l’info, par exemple avec la ligne de commande.

On peut ainsi afficher l’ensemble des entrées du stash avec :

git stash list

On comprend alors l’intérêt d’avoir correctement nommé les entrées du stash.

Entrées bien nommées de stash

Pour obtenir la liste des fichiers modifiés on pourra faire un :

# Pour prendre la dernière entrée (stash@{0})
git stash show
# ou pour cibler une version précise
git stash show stash@{<version-ciblée>}

Les fichiers non-suivis ne sont pas affichés par défaut, il faut renseigner l’option -u ou --include-untracked pour les voir :

git stash show --include-untracked stash@{<version-ciblée>}

On peut aussi demander à afficher les modifications elles-mêmes, au sein des fichiers :

git show stash@{<version-ciblée>}

git stash show vs. git show <stash>

Attention : avec git show, en raison du mode stockage du stash, seules les modifications non stagées seront affichées. C’est parce que le commit technique référencé par le stash stocke uniquement ces infos, utilisant des commits techniques parents distincts pour les nouveaux fichiers et les modifications stagées.

Extraire du stash

On peut choisir 2 modes d’extraction du stash :

  • on extrait et on garde une copie dans le stash : git stash apply
  • on extrait sans garder l’entrée dans le stash : git stash pop (= apply + drop).

Dans les deux cas Git ne tentera pas de replacer dans le stage les fichiers stagés lors de la mise dans le stash. Pour tenter de restaurer cet état vous pouvez renseigner l’option --index (valable pour apply comme pop).

Le plus fréquemment vous souhaiterez sortir l’entrée du stash au moment de son extraction :

git stash pop --index stash@{<version-ciblée>}

Et si le stash ne peut pas être extrait ?

Git vous indiquera alors la marche à suivre, à savoir qu’il faut commiter vos modifications en cours qui gênent l’application du stash.

Stash non autorisé et demande de commit

Une fois ce commit réalisé, si les modifications extraites de votre stash touchent des fichiers modifiés entre-temps, vous vous retrouverez avec un conflit que vous pourrez alors arbitrer. L’entrée du stash sera quant à elle conservée par mesure de précaution.

Stash appliqué mais conflit local

Nettoyer le stash

Vu que laisser traîner du stash n’est pas forcément une bonne idée, surtout si vous n’en avez pas l’usage, vous voudrez nettoyer celui-ci. Deux solutions s’offrent à vous :

  • purger des entrées précises du stash : git stash drop stash@{<version ciblée>} ;
  • purger la totalité sans vous poser de question : git stash clear.

Bonus 1 : le contenu de mon stash mérite d’être sur une branche

On peut classiquement créer une branche et la rendre active (git switch --create=nouvelle-branche) pour y appliquer notre stash et vérifier sa bonne application dans notre copie de travail et notre stage (git status).

Cette tâche peut être simplifiée par la commande :

git stash branch nouvelle-branche stash@{<version-désirée>}

Bonus 2 : automatiser le stash autour des récupérations de mises à jour (pull)

Pour récupérer sans contrainte des mises à jour depuis notre dépôt distant alors que nous avons des modifications en cours, nous pouvons configurer Git pour qu’il applique automatiquement le stash autour de la commande git pull 🤘 :

git config --global rebase.autoStash true

Attention, ça ne fonctionne que si vous avez configuré git pull en mode rebase, ce que vous devriez vraiment faire !

J’ai trop de choses en cours, ne peut-on pas faire autrement ?

Aucun problème, dans des situations plus « extrêmes » on peut passer par les worktrees Git, ce qu’on vous décrit dans cet autre article.

Tu veux aller plus loin et maîtriser pleinement les fondamentaux de Git ou être accompagné pour garantir la qualité de tes projets grâce à une bonne mise en place de Git ? On peut t’aider ou te former, il suffit de nous décrire ton besoin !