Tutoriel

git checkout, switch et restore : laquelle utiliser et quand

Mis à jour: · Skillaria.Top

git checkout fait deux choses très différentes : changer de branche et restaurer des fichiers. Depuis Git 2.23, ces rôles sont répartis entre git switch (branches) et git restore (fichiers). Utilisez git switch nom pour changer de branche, git restore fichier pour annuler des modifications non commitées, et gardez checkout pour les anciens scripts et les habitudes établies.

Pourquoi git checkout a deux rôles

Historiquement, git checkout réalise deux opérations fondamentalement différentes. Avec un nom de branche, il déplace HEAD et met à jour le répertoire de travail. Avec un chemin de fichier, il prend la version du fichier dans l'index ou dans un commit et écrase silencieusement vos modifications. La même commande tantôt passe d'une branche à l'autre sans risque, tantôt jette de manière irréversible du travail non sauvegardé.

C'est pourquoi Git 2.23 a introduit deux commandes distinctes : git switch pour les branches et git restore pour les fichiers. Personne n'a supprimé checkout, il fonctionne parfaitement, mais le code récent, la documentation et les messages de Git lui-même utilisent switch et restore. Si vous débutez, commencez par elles ; il faut tout de même connaître checkout, que l'on croise dans les tutoriels, les scripts et les entretiens techniques.

Correspondance des commandes

Tâchegit checkoutNouvelle commande
Changer de branchegit checkout maingit switch main
Créer une branche et s'y placergit checkout -b featuregit switch -c feature
Créer ou réinitialiser une branchegit checkout -B featuregit switch -C feature
Revenir à la branche précédentegit checkout -git switch -
Aller sur un commit (detached HEAD)git checkout 3f2a1c9git switch --detach 3f2a1c9
Annuler les modifications d'un fichiergit checkout -- app.jsgit restore app.js
Retirer un fichier de l'indexgit reset HEAD app.jsgit restore --staged app.js
Récupérer un fichier d'une autre branche ou d'un commitgit checkout main -- app.jsgit restore --source=main --staged --worktree app.js
Annuler toutes les modifications d'un dossiergit checkout -- .git restore .

Remarquez le -- dans les commandes checkout. C'est le séparateur « ce qui suit sont des chemins ». Il évite toute ambiguïté quand un fichier et une branche portent le même nom. Restore n'a pas ce problème, puisqu'il ne travaille qu'avec des fichiers.

git checkout pour les branches

git checkout feature/login        # changer de branche
git checkout -b feature/login     # créer depuis le commit courant et s'y placer
git checkout -b hotfix origin/main   # créer depuis une branche distante
git checkout -t origin/feature/x  # branche locale qui suit la branche distante

S'il n'existe pas de branche locale mais qu'une branche du même nom existe sur le serveur, git checkout feature/x (comme git switch feature/x) crée automatiquement la branche locale et configure le suivi. Il faut d'abord un git fetch, sinon Git ignore l'existence de la nouvelle branche distante.

Changer de branche ne fait pas perdre les modifications non commitées : elles sont transférées dans l'autre branche si elles n'entrent pas en conflit avec elle. En cas de conflit, Git refuse et propose de commiter ou de mettre de côté les modifications avec git stash. L'option -f (--force) change de branche en jetant les modifications locales — c'est déjà une opération dangereuse.

git switch : uniquement les branches

Switch reprend la partie « branches » de checkout, avec des règles plus strictes. Différence principale : il ne se place pas sur un commit ou un tag sans --detach explicite. La commande git switch v1.0 renvoie une erreur au lieu de basculer discrètement en detached HEAD, il est donc plus difficile de se retrouver « hors branche » par accident.

git switch main
git switch -c feature/cart
git switch -c feature/cart origin/main
git switch --detach v1.0
git switch -              # branche précédente
git switch -m main        # transférer les modifications avec une fusion à trois voies

git restore : le bouton « annuler » des fichiers

Restore ramène les fichiers à un état enregistré et ne touche jamais à l'historique des commits. Pour l'utiliser en toute confiance, gardez en tête les trois zones de Git : le répertoire de travail (ce que vous voyez dans l'éditeur), l'index (ce qui a été préparé via git add) et les commits.

Annuler les modifications d'un fichier avant git add

git restore app.js         # restaurer la version de l'index
git restore src/           # tous les fichiers du dossier
git restore .              # tous les fichiers modifiés du projet

Sans option, restore restaure le répertoire de travail à partir de l'index. Si le fichier n'a pas été ajouté à l'index depuis le dernier commit, cela revient à la version du dernier commit. Les modifications disparaissent sans laisser de trace, elles ne vont pas dans la corbeille : jetez donc un œil à git diff avant un git restore ..

Retirer un fichier de l'index après git add

git restore --staged app.js

Le fichier n'est plus préparé pour le commit, mais vos modifications y restent. C'est la forme la plus sûre de restore : rien n'est perdu. C'est d'ailleurs la commande que suggère git status dans la section « Changes to be committed ».

Tout annuler : dans l'index et dans le fichier

git restore --staged --worktree app.js
# forme courte
git restore -SW app.js

Récupérer un fichier depuis un autre commit ou une autre branche

git restore --source=HEAD~2 app.js          # version d'il y a deux commits
git restore --source=main config.yml        # version de la branche main
git restore --source=3f2a1c9 -- docs/       # un dossier entier depuis un commit

Par défaut, avec --source, seul le répertoire de travail est modifié. Ajoutez --staged si vous voulez préparer directement la modification pour le commit. L'ancienne variante git checkout main -- app.js modifie toujours à la fois l'index et le répertoire de travail.

Restaurer un fichier supprimé

git restore deleted.txt                          # supprimé mais pas encore commité
git restore --source=HEAD~1 deleted.txt          # suppression déjà commitée

Si vous ne savez pas dans quel commit le fichier a été supprimé, retrouvez-le : git log --oneline -- deleted.txt. Le dernier commit de la liste est celui qui l'a supprimé, il faut donc restaurer depuis son parent : git restore --source=<hash>~1 deleted.txt.

restore, reset et revert : ne pas les confondre

Les trois commandes « annulent », mais pas au même niveau :

  • restore — agit sur les fichiers du répertoire de travail et de l'index, sans modifier l'historique. Sans risque pour l'équipe.
  • reset — fait reculer le pointeur de branche en réécrivant l'historique. --soft garde les modifications dans l'index, --mixed (par défaut) dans le répertoire de travail, --hard les supprime. Dangereux pour des commits déjà poussés sur des branches partagées.
  • revert — crée un nouveau commit qui inverse celui indiqué. L'historique n'est pas réécrit, c'est donc la bonne manière d'annuler un commit déjà présent sur le serveur.

Règle simple : modifications pas encore commitées — restore ; commit uniquement local — reset ; commit déjà chez les collègues — revert.

Detached HEAD après un checkout

Après git checkout 3f2a1c9 ou git checkout v1.0, vous verrez un long avertissement « You are in 'detached HEAD' state ». HEAD pointe désormais vers un commit et non vers une branche. C'est pratique pour consulter une ancienne version ou y lancer les tests.

On peut commiter dans cet état, mais les nouveaux commits n'appartiendront à aucune branche. Si vous avez modifié quelque chose et voulez le conserver :

git switch -c fix-for-v1

Si vous ne faisiez que regarder, revenez en arrière : git switch - ou git switch main. Si vous êtes parti en oubliant de créer une branche, les commits restent accessibles via git reflog : trouvez le hash et lancez git branch rescue <hash>.

Erreurs courantes

error: pathspec 'feature' did not match any file(s) known to git

Git n'a trouvé ni branche ni fichier portant ce nom. En général, la branche n'existe que sur le serveur et aucun fetch n'a été fait. Lancez git fetch et réessayez. Vérifiez aussi l'orthographe : les noms de branches sont sensibles à la casse.

Modifications jetées par erreur avec checkout -- ou restore

Git ne conserve pas les modifications non commitées qui n'étaient pas dans l'index, et il est impossible de les récupérer avec Git. Il reste l'historique local de l'éditeur ou de l'IDE. En revanche, si le fichier avait été ajouté via git add, son contenu se trouve dans la base sous forme d'objet « orphelin » et se retrouve avec git fsck --lost-found.

Un fichier et une branche du même nom

git checkout test, en présence d'une branche test et d'un dossier test, affiche un avertissement d'ambiguïté. Utilisez git switch test pour la branche et git restore test (ou git checkout -- test) pour les fichiers.

Scénarios du quotidien

Quelques situations qui reviennent sans cesse, et la bonne commande pour chacune :

  • Vous avez commencé à modifier un fichier et réalisez que vous faites fausse route — git restore fichier.
  • Vous avez ajouté un fichier de trop à l'index avant le commit — git restore --staged fichier.
  • Vous devez passer en urgence à une autre tâche en plein travail — git stash, puis git switch branche ; au retour, git switch - et git stash pop.
  • Vous voulez récupérer un seul fichier d'une branche voisine sans fusionner toute la branche — git restore --source=feature/x --staged --worktree chemin.
  • Vous devez vérifier si le bug existait dans une version précédente — git switch --detach v1.0, vérification, puis git switch -.
  • Vous voulez annuler seulement une partie des modifications d'un fichier — git restore -p fichier : Git affiche chaque fragment et demande s'il faut l'annuler.

Le mode interactif -p (--patch) est particulièrement utile : il existe pour checkout comme pour restore et permet de supprimer des traces de débogage tout en gardant les modifications utiles dans le même fichier.

Vérifier avant d'annuler

Restore et checkout avec des chemins jettent les modifications sans confirmation, il est donc utile de regarder d'abord ce qui va disparaître. git diff affiche les modifications du répertoire de travail par rapport à l'index, git diff --staged ce qui est prêt pour le commit, git diff main -- app.js la différence entre le fichier et sa version dans une autre branche. En cas de doute, sauvegardez l'état actuel avec git stash : contrairement à restore, on peut toujours en récupérer les modifications.

En résumé

git checkout combine changement de branche et restauration de fichiers, et c'est précisément ce qui le rend dangereux. Utilisez git switch pour les branches et git restore pour les fichiers : l'une ne modifie que la position de HEAD, l'autre uniquement le contenu des fichiers. Les branches, restore, reset et revert, avec les bons et les mauvais scénarios, sont mis en pratique dans le cours Git.

Questions fréquentes

git checkout est-il obsolète ?

Non, il n'a pas été déclaré obsolète et continuera de fonctionner. On recommande simplement, pour le travail quotidien, les commandes plus ciblées et plus sûres git switch et git restore.

Depuis quelle version de Git switch et restore existent-ils ?

Les deux commandes sont apparues dans Git 2.23 (en 2019). Vous pouvez vérifier votre version avec git --version.

Peut-on annuler un git restore ?

Si c'est le répertoire de travail qui a été restauré, Git n'a pas conservé les modifications jetées et on ne peut pas revenir en arrière. git restore --staged est sans risque : les modifications restent dans le fichier, il suffit de le rajouter avec git add.

Comment passer sur la branche d'un collègue ?

Lancez git fetch, puis git switch nom-de-branche : Git crée une branche locale liée à origin/nom-de-branche.

Quelle différence entre git checkout . et git reset --hard ?

git checkout . (ou git restore .) ramène les fichiers modifiés à la version de l'index, sans toucher à l'index ni à l'historique. git reset --hard réinitialise l'index et le répertoire de travail sur un commit et, si on lui passe un commit en argument, déplace aussi la branche.

Apprenez ce sujet en vidéo

Ce sujet est traité en détail avec de la pratique dans le cours « Git de zéro à développeur confirmé ».

Voir le cours