Git restore porte le coup de grâce à git checkout
git checkout a longtemps été la commande tout-en-un de Git. Branches, fichiers, restauration… elle faisait tout, et c’est bien là le problème : trop de fonctions, trop d’ambiguïtés, trop de pièges.
Pour mieux comprendre ce que GitCheckout faisait auparavant côté branches, commence par lire GitSwitch, l’assassin de git checkout.
⚡️ Résumé express
En 2019, les développeurs de Git ont tranché : il fallait séparer les responsabilités.
- 👉
git switch
a repris la gestion des branches. - 👉
git restore
s’est occupé de la restauration des fichiers.
Résultat: git checkout est relégué au rang de commande héritée, tolérée pour la compatibilité, mais à éviter au quotidien.
📚 Pour ceux qui aiment lire la doc officielle
(Mais si tu veux comprendre ce qu’il se passe vraiment et éviter les pièges du quotidien, continue à lire 👇)
😡 Quand la communauté a craqué
Si git restore
a vu le jour, c’est parce que la communauté avait atteint son point de rupture avec git checkout
.
Même après des années, git checkout
restait un mystère et les auteurs de Git eux-mêmes l’avouent : leur propre
commande était devenue un piège.
"I've been working with Git for years, but my knowledge is limited to very basic workflows"
Développeur sur Stack Overflow
"People are confused by these different ways to use git checkout, as you can see from the many questions regarding git checkout here on Stack Overflow"
Discussion sur Stack Overflow
"git checkout doing too many things is a source of confusion for many users (and it even bites old timers sometimes)"
Commit officiel Git d787d31 par Nguyễn Thái Ngọc Duy, 2 avril 2019
"I've lost plenty of data with git. Most of it has to do with innocuous-sounding commands that don't ask for confirmation when deleting data. For example,git checkout filename
is equivalent to{' '}svn revert filename
. Of coursegit checkout branchname
does something completely different."
Témoignage sur Stack Overflow
"If a branch and a file share the same name, git will default to switching branches, but that doesn't stop bash autocomplete from ruining the day"
Même développeur, même thread Stack Overflow
"Here's a crazy idea: If you have an innocuous action and a dangerous action, do not label them with the same command"
Réponse sur Stack Overflow
"The ambiguity of the git syntax constantly forces you to reach for a cheat sheet. The commands do not clearly describe their corresponding actions"
Article "The most confusing git terminology"
🩻 L’autopsie de git checkout
Qui peut, sans regarder la documentation ou tester dans son terminal, expliquer la différence entre ces commandes ? Fais le test dans ton équipe, tu verras qu'il y a de fortes chances pour que personne ne sache répondre correctement.
BASH❯ git checkout HEAD -- . ❯ git checkout -- . ❯ git checkout HEAD ❯ git checkout fichier.txt
💀 Piège 1 - Annuler toutes les modifs (Arbre de travail + index)
BASH❯ git checkout HEAD -- .
Git prend les fichiers qui sont dans HEAD et vient écraser l'arbre de travail et l'index. Et bien entendu, pas de retour arrière possible 😱.
💀 Piège 2 - Annuler les modifs en cours non indexées
BASH❯ git checkout -- .
Contrairement à git checkout -- .
on ne précise pas ici la source (HEAD). => Dans ce cas de figure git se base sur
l'index pour venir mettre à jour l'arbre de travail. Tu trouves ça intuitif ? Moi non plus.
Et bien entendu, toujours pas de retour arrière possible 😱.
💀 Piège 3 - Restaurer un fichier
BASH❯ git checkout fichier.txt
On ne précise pas la source (HEAD), donc normalement git devrait se baser sur l'index. Oui mais non. Comme on passe un fichier en paramètre, git va se baser sur le HEAD et annuler toutes les modifs du fichier, qu'elles soient indexées ou non.
Mais par contre si tu as eu le malheur d'appeler ta branche fichier.txt
(bon ok c'est vraiment peu probable) et bien
tu finiras par faire un checkout de ta branche fichier.txt
et non pas de restaurer ton fichier fichier.txt
.
C'est ça d'avoir une commande qui fait tout : un coup elle change de branche, une autre fois elle crée une branche, et dans d'autres contextes elle reset l'index et/ou le working directory (ta copie de travail). C'est un peu la roulette russe, non ?
💀Piège 4 - Le mode "Detached HEAD" surprise
BASH❯ git checkout HEAD
Celle là c'est cadeau. On pourrait croire qu'elle ne fait rien, alors qu'en fait elle nous fait passer en mode détaché !
Et oui c'est comme si on avait voulu changer de branche, comme avec un git checkout feature/auth
, sauf que la
référence que l'on a passé est HEAD, on pointe donc directement sur le commit. N'étant plus sur une branche, il va
falloir faire attention à ne pas perdre son travail au prochain changement de branche 😉.
BASH❯ git checkout HEAD Note: switching to 'HEAD'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by switching back to a branch. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -c with the switch command. Example: git switch -c <new-branch-name> Or undo this operation with: git switch - Turn off this advice by setting config variable advice.detachedHead to false HEAD is now at 8776833 ✨ feat: Ajoute des diagrammes pour git checkout
📋 Petit tableau récap de git checkout :
Commande | Source → Destination | Effet |
---|---|---|
git checkout HEAD -- . | HEAD → Index + Working tree | Annule toutes les modifs + reset index |
git checkout -- . | Index → Working tree | Annule modifs non validées (sans toucher à l’index) |
git checkout HEAD | Passe en mode détaché (HEAD detached) | Ne change rien aux fichiers |
git checkout fichier.txt | HEAD → Index + Working tree (sauf si fichier.txt est une branche) | Restaure un fichier… sauf si c’est une branche ! |
🌈 Git restore : l'alternative claire à git checkout
En 2019, Git 2.23 introduit une alternative claire :
👉 git switch
pour les branches
👉 git restore
pour annuler les modifs sur les fichiers
📝 Une syntaxe explicite
On est d'accord, le problème de git checkout
n'est pas que la commande ne fonctionne pas, mais plutôt que la commande
fait trop de choses et ses options ne sont pas claires :
- est-on en train de faire un changement de branche ?
- ou un reset complet ?
- ou une annulation de modifs ?
- etc.
Pour répondre à cela les équipes Git se sont calées sur le principe de responsabilité unique (Single Responsibility
Principle, SRP) et c'est tant mieux ! Ainsi en 2019 ils introduisent git restore
et simplifient le process avec 2
options :
--worktree
→ pour mettre à jour l'arbre de travail--staged
→ pour mettre à jour l'index
Une dernière option quant à elle permet de choisir un commit d'origine autre que HEAD :
--source
→ pour utiliser un commit différent de celui sur lequel on est.
🌲 L'option --worktree
BASHgit restore --worktree <fichier>
Enfin une option claire pour annuler les modifs en cours dans l'arbre de travail.
Petit rappel : les modifs en cours sont celles qui n'ont pas encore été indexées (à ne pas confondre avec l'ensemble des modifs = modifs dans la copie de travail + modifs dans l'index).
Pour cette raison, en interne Git va logiquement se reposer sur l'index pour venir écraser les fichiers dans l'arbre de travail.
Comme c'est le besoin le plus fréquent, les équipes Git en ont fait l'option par défaut. Donc si tu n'utilises pas d'autres options, ces 2 commandes sont équivalentes :
BASHgit restore --worktree <fichier> git restore <fichier> # --worktree par défaut
📦 L'option --staged
BASHgit restore --staged <fichier>
Comme son nom l'indique, on cherche ici à supprimer les modifs que l'on avait enregistrées dans l'index via git add
.
Pour réinitialiser l'index, git va l'écraser avec le contenu de HEAD.
Cette commande n'est absolument pas dangereuse car les modifications en cours restent présentes dans la copie de travail (working directory).
Dit autrement, cette commande permet d'annuler tous les git add
effectués depuis le dernier commit tout en laissant
les modifs en cours dans la copie de travail.
🔀 Et si on cumulait les deux options : --worktree --staged
BASHgit restore --worktree --staged <fichier>
Comme prévu, Git va enchaîner les 2 options :
- 1ère étape : restauration de l'index (-->
--staged
)
- 2ème étape : restauration de l'arbre de travail (-->
--worktree
)
🔥 A la fin des 2 étapes, on a un alignement parfait entre l'arbre de travail, l'index et HEAD.
🎯 L'option --source
BASHgit restore --source=<commit> <fichier>
Cette option est différente des 2 autres options, car comme son nom l'indique elle ne sert pas à indiquer la zone cible mais le point de départ.
Par défaut, et c'est le cas dans 99% des cas, on voudra partir de HEAD.
Mais dans certains cas, il peut être utile de récupérer les informations à partir d'un commit spécifique, et c'est ce
que permet l'option --source
.
Récupérer un fichier d’une autre branche sans changer de branche
Tu es sur main mais tu veux récupérer uniquement la version de docker-compose.yml
de feature-x
:
BASHgit restore --source=feature-x docker-compose.yml
👉 Tu n’as pas besoin de faire git switch feature-x
puis de copier-coller le fichier. C’est un vrai gain de temps.
Revenir à l’état d’un fichier avant un bug
Un bug est apparu après le commit abc123
. Tu veux tester rapidement si la version précédente de app.js
corrige le
problème :
BASHgit restore --source=abc123 app.js
👉 Tu isoles le bug sans reset/checkout de tout le repo.
Travailler avec une version “propre” d’un seul fichier
Tu as commencé à modifier config.json
, mais tu veux repartir de la version qui existait au tag v1.0.0
:
BASHgit restore --source=v1.0.0 config.json
👉 Tu gardes ton repo à jour, mais avec ce fichier dans une version plus ancienne.
Cherry-pick manuel de fichiers
Tu sais qu’un collègue a fait une modif utile dans un commit précis, mais tu veux seulement son fichier README.md, pas tout le commit :
BASHgit restore --source=commit_sha README.md
👉 Tu évites un cherry-pick complet et tu prends uniquement le fichier qui t’intéresse.
Construire un patch partiel
Avant un refactoring, tu veux avoir à disposition deux versions d’un même fichier (HEAD et une version ancienne) pour
les comparer. Avec --source
, tu remets l’ancienne version directement dans ton WD pour faire un diff local.
BASHgit restore --source=v1.0.0 config.json
✅ En résumé :
--source
est rare au quotidien.- Il devient vraiment utile quand tu veux restaurer un fichier précis d’une autre référence (branche, commit, tag) sans toucher le reste du repo.
📋 Tableau récap de git restore
Option | Source → Destination | Effet |
---|---|---|
git restore . est la même chose que git restore --worktree . | Index → Working tree | Restaure tous les fichiers depuis l'index vers l'arbre de travail. Cela a pour effet d'annuler les modifications en cours non indexées |
git restore --staged . | HEAD → Index | Restaure tous les fichiers depuis HEAD vers l'index (unstage). Cela revient à supprimer tous les git add effectués depuis le dernier commit |
git restore --staged --worktree . | HEAD → Index → Working tree | Supprime tous les changements, que ce soit dans l'index ou dans l'arbre de travail |
git restore --source=HEAD~2 . | HEAD~2 → Working tree | Récupération de la version d'un fichier d'une autre référence (branche, commit, tag) |
⏳ Avant 2019 vs Maintenant
Action | Avant 2019 (checkout) | Maintenant (restore) | Gain |
---|---|---|---|
Annuler modifs working tree | git checkout -- file | git restore <fichier> | ✅ Explicite |
Unstager un fichier | 🚨 pas possible avec git checkout . Il faut passer par reset pour avoir l'équivalent : git reset HEAD file | git restore --staged <fichier> | ✅ Logique |
Reset complet (WD + Index) | git checkout HEAD -- file | git restore --staged --worktree <fichier> | ✅ Clair |
Depuis un commit | git checkout abc123 -- file | git restore --source=abc123 <fichier> | ✅ Source explicite |
⚰️ Git checkout est-il vraiment mort ?
Git restore n’est pas juste une nouvelle commande. C’est l’exécuteur qui a achevé ce que git switch
avait
commencé.
En revanche, non, il n'est pas mort. Il survit pour la rétrocompatibilité. Mais soyons clairs : c’est une relique.
- ✅
git switch
→ branches - ✅
git restore
→ fichiers - ❌
git checkout
→ héritage à éviter
👉 1 job = 1 commande, c'est le principe de responsabilité unique (Single Responsibility Principle, SRP).
L’enquête est close. Git checkout peut enfin reposer en paix, pendant que switch et restore veillent sur nos dépôts.
❓ FAQ Express
Quelle différence entre restore et checkout pour les fichiers ?
👉 git restore
est explicite et sûr, là où git checkout
était ambigu car cette commande faisait trop de choses et
ses options sont ambigües.
Git checkout va-t-il disparaître ?
Non. Il reste pour la compatibilité. Mais il est officiellement considéré comme “héritage”.
Depuis quelle version existe git restore ?
👉 Depuis Git 2.23 (août 2019), en même temps que git switch
.
Dois-je oublier git checkout ?
Oui, dans ton quotidien. Utilise git switch
et git restore
à la place.
🚀 Va plus loin : Maîtrise Git en entreprise avec nos formations sur mesure
Pourquoi choisir la formation "Maître Git" pour ton entreprise ?
- Expertise certifiée: Bénéficie de l'expérience d'un formateur spécialisé, capable de démystifier Git pour tous les niveaux.
- Programmes sur mesure: Chaque formation est adaptée à la culture de ton entreprise, à tes outils et à tes workflows spécifiques.
- Productivité accrue: Des équipes formées à l'excellence Git travaillent plus vite, avec moins d'erreurs et une meilleure collaboration.
- Sécurité renforcée: Apprends les bonnes pratiques pour protéger ton historique de code et éviter les pièges courants.
Prêt à transformer la gestion de version de ton entreprise ?
Ne laisse plus les complexités de Git freiner tes projets. Investis dans la compétence de tes équipes et assure une collaboration fluide et efficace.