Annuler, défaire et corriger avec Git (reset, revert, restore…)
Tôt ou tard, tout le monde se trompe avec Git : un mauvais commit, un add de trop, une branche à supprimer, un fichier écrasé par erreur. La bonne nouvelle, c’est que Git garde la trace de presque tout — il suffit de connaître la commande adaptée à chaque situation. Ce guide répertorie les cas concrets, du plus courant au plus délicat, avec la commande exacte à taper. Gardez-le sous la main : l’important n’est pas de tout mémoriser, mais de retrouver le bon geste au bon moment.
Comprendre les trois zones de Git
Avant d’annuler quoi que ce soit, il faut visualiser où se trouve votre modification. Git manipule trois espaces : le répertoire de travail (vos fichiers tels qu’ils sont sur le disque), l’index (staging area, ce que git add a préparé) et l’historique (les commits). Chaque commande d’annulation agit sur une ou plusieurs de ces zones, et c’est ce qui explique leurs différences.
# Photographier l'état actuel avant toute manipulation
git status
git log --oneline -5
Prenez le réflexe de lancer git status avant et après chaque annulation : il vous dit exactement dans quelle zone se trouve chaque fichier.
Défaire des modifications non validées
Annuler les changements d’un fichier suivi
Vous avez modifié un fichier et vous voulez revenir à la version du dernier commit, en jetant vos changements :
# Restaurer un fichier à l'état du dernier commit (destructif)
git restore fichier.js
# Restaurer tout le répertoire de travail
git restore .
git restore est la commande moderne (Git 2.23+). L’ancienne syntaxe, encore très répandue, était git checkout -- fichier.js. Attention : cette opération écrase vos modifications sans filet, elles ne partent pas dans le stash.
Désindexer un fichier ajouté par erreur
Vous avez fait git add sur un fichier que vous ne vouliez pas encore valider :
# Retirer un fichier de l'index, sans toucher son contenu
git restore --staged fichier.js
# Tout désindexer d'un coup
git restore --staged .
Le contenu du fichier reste intact dans votre répertoire de travail ; seul l’index est vidé. L’équivalent historique était git reset HEAD fichier.js.
Supprimer les fichiers non suivis
Les nouveaux fichiers jamais indexés ne sont pas concernés par restore. Pour faire le ménage :
# Simuler la suppression (aperçu, ne supprime rien)
git clean -n
# Supprimer les fichiers non suivis
git clean -f
# Inclure aussi les dossiers non suivis
git clean -fd
# Inclure les fichiers ignorés par .gitignore
git clean -fdx
Lancez toujours git clean -n d’abord : c’est un aperçu qui liste ce qui va disparaître, sans rien détruire.
Corriger le dernier commit
Modifier le message ou ajouter un oubli
Vous venez de committer mais le message contient une faute, ou vous avez oublié un fichier :
# Corriger uniquement le message du dernier commit
git commit --amend -m "Nouveau message correct"
# Ajouter un fichier oublié au dernier commit
git add fichier-oublie.js
git commit --amend --no-edit
--no-edit conserve le message existant. Règle d’or : n’utilisez --amend que sur un commit non encore poussé. Amender un commit déjà partagé réécrit l’historique et forcera un push --force qui perturbera vos collègues.
Annuler un ou plusieurs commits
C’est ici que se joue la distinction la plus importante de Git : reset réécrit l’historique local, revert ajoute un commit d’annulation.
reset —soft : reculer en gardant tout indexé
# Annuler le dernier commit, garder les changements dans l'index
git reset --soft HEAD~1
Le commit disparaît, mais tout son contenu reste prêt à être re-committé. Idéal pour regrouper plusieurs petits commits en un seul, ou refaire un commit mal découpé.
reset —mixed : reculer en désindexant
# Annuler le dernier commit, garder les changements NON indexés (défaut)
git reset --mixed HEAD~1
# équivalent :
git reset HEAD~1
C’est le comportement par défaut. Le commit et l’indexation sont annulés, mais vos modifications restent dans le répertoire de travail. Parfait pour reprendre à zéro la préparation du commit.
reset —hard : tout effacer
# Annuler le dernier commit et SUPPRIMER les changements (destructif)
git reset --hard HEAD~1
# Reculer de trois commits
git reset --hard HEAD~3
--hard est la seule variante qui touche le répertoire de travail : elle jette définitivement les modifications. À réserver aux cas où vous êtes certain de vouloir tout perdre. Si vous hésitez, faites d’abord --soft ou --mixed.
revert : annuler proprement sur une branche partagée
Sur une branche déjà poussée, on ne réécrit pas l’histoire — on l’enrichit. revert crée un nouveau commit qui inverse les effets d’un commit passé :
# Créer un commit qui annule un commit précis
git revert <hash-du-commit>
# Annuler le dernier commit
git revert HEAD
# Annuler plusieurs commits sans créer un commit pour chacun
git revert --no-commit HEAD~2..HEAD
git commit -m "Annule les trois derniers changements"
C’est la méthode sûre et partageable : chacun voit clairement qu’un changement a été annulé, et personne n’a besoin de forcer quoi que ce soit. Pour bien distinguer ces gestes, notre mémo des commandes Git essentielles reprend ce socle en une page.
Supprimer une branche
Branche locale
# Supprimer une branche déjà fusionnée (sécurisé)
git branch -d nom-de-la-branche
# Forcer la suppression d'une branche non fusionnée
git branch -D nom-de-la-branche
Le -d minuscule refuse de supprimer une branche contenant du travail non fusionné : c’est un garde-fou. Le -D majuscule force la suppression, y compris si vous risquez de perdre des commits. Impossible de supprimer la branche sur laquelle vous êtes actuellement — basculez ailleurs d’abord :
git switch main
git branch -d nom-de-la-branche
Branche distante
Supprimer la branche localement ne la retire pas du dépôt distant. Pour cela :
# Supprimer une branche sur le dépôt distant
git push origin --delete nom-de-la-branche
# Syntaxe équivalente plus ancienne
git push origin :nom-de-la-branche
Nettoyer les références aux branches distantes disparues
Après qu’un collègue a supprimé une branche distante, votre dépôt en garde une trace fantôme :
# Supprimer les références locales aux branches distantes disparues
git fetch --prune
# Voir les branches locales dont le distant a disparu
git branch -v
Récupérer ce qu’on croyait perdu : reflog
Voici le filet de sécurité que trop peu de développeurs connaissent. Même après un reset --hard ou une suppression de branche, Git conserve un journal de tous les déplacements de HEAD pendant plusieurs semaines : le reflog.
# Afficher l'historique des positions de HEAD
git reflog
La sortie ressemble à ceci :
a1b2c3d HEAD@{0}: reset: moving to HEAD~1
e4f5g6h HEAD@{1}: commit: Ajoute la fonctionnalité de tri
i7j8k9l HEAD@{2}: commit: Corrige l'affichage mobile
Repérez le hash du commit perdu et récupérez-le :
# Recréer une branche pointant sur le commit perdu
git branch recuperation e4f5g6h
# Ou revenir directement dessus
git reset --hard e4f5g6h
Tant qu’un commit apparaît dans le reflog, il n’est jamais vraiment perdu. C’est la raison pour laquelle on peut oser les manipulations : dans la quasi-totalité des cas, un reset --hard malencontreux se rattrape.
Le bon réflexe selon la situation
Résumons la logique de décision. Vous voulez jeter des modifications non validées ? git restore. Désindexer ? git restore --staged. Corriger le dernier commit local ? git commit --amend. Reculer dans l’historique local ? git reset (soft, mixed ou hard selon ce que vous gardez). Annuler sur une branche partagée ? git revert. Supprimer une branche ? git branch -d en local, git push origin --delete à distance. Et si vous avez trop supprimé, git reflog reste votre dernier recours.
La règle transversale : tant que le travail est local, vous pouvez réécrire l’histoire librement ; dès qu’il est partagé, préférez les commandes additives comme revert. Avec ces repères, plus aucune erreur Git n’est irréversible.