Développement Web

Annuler et réparer dans Git : reset, revert, reflog, stash

13 min de lecture
📍 À lire d’abord : Maîtriser Git et GitHub — le guide complet. Ce tutoriel rassemble les outils de réparation : reset, revert, reflog et stash.

Tôt ou tard, vous commiterez sur la mauvaise branche, écraserez un fichier, ou voudrez annuler un changement déjà partagé avec l’équipe. La bonne nouvelle, c’est que Git oublie très peu : presque tout est récupérable, à condition de connaître le bon outil. Le secret n’est pas de mémoriser des dizaines de commandes, mais de se poser une question simple — « qu’est-ce que je veux annuler, et est-ce déjà partagé ? » — puis de choisir l’instrument adapté. À la fin de ce tutoriel, vous saurez défaire proprement n’importe quelle bévue, et surtout récupérer un travail que vous croyiez perdu.

🎯 Ce que vous allez apprendre

  • Annuler des modifications non commitées avec git restore.
  • Comprendre et choisir les trois modes de git reset (soft, mixed, hard).
  • Annuler un commit déjà partagé en sécurité avec git revert.
  • Récupérer des commits « perdus » grâce au reflog.
  • Mettre du travail de côté avec git stash.
  • Savoir quand utiliser quoi, sans jamais détruire de travail par accident.

🛠️ Ce que vous allez construire

Sur le dépôt boutique-inventaire, vous allez délibérément commettre des erreurs courantes — un mauvais commit, un reset --hard trop ambitieux, un changement urgent qui tombe au mauvais moment — puis vous les réparerez chacune avec l’outil approprié. Vous repartirez avec une véritable trousse de secours Git.

Prérequis

  • Maîtriser le cycle de base : voir Les bases de Git.
  • Comprendre branches et commits.
  • Niveau intermédiaire. ⏱️ Temps estimé : environ 50 minutes.

Étape 1 — Le bon cadre mental

Avant toute commande, posez-vous deux questions. Que voulez-vous annuler ? Une modification non encore commitée, un fichier ajouté par erreur à l’index, le dernier commit, ou un commit plus ancien ? Est-ce déjà partagé ? Si le commit n’existe que sur votre machine, vous pouvez le réécrire librement. S’il est déjà poussé et récupéré par d’autres, vous ne devez pas réécrire l’historique : il faut l’annuler « par-dessus », sans l’effacer.

Cette grille de lecture suffit à choisir : restore pour le travail non commité, reset pour réorganiser des commits locaux, revert pour annuler proprement un commit partagé, et le reflog comme filet de sécurité universel. Voyons chaque cas.

Étape 2 — Annuler des modifications non commitées

Vous avez modifié un fichier puis réalisé que c’était une fausse piste. Pour revenir à la dernière version enregistrée, git restore est l’outil dédié.

echo "ligne malencontreuse" >> app.js
git restore app.js

Le fichier retrouve son contenu du dernier commit ; votre ajout disparaît. Attention, cette opération est destructive pour le travail non sauvegardé : ce qui n’était pas commité est perdu. Autre cas fréquent : vous avez fait git add d’un fichier que vous ne vouliez pas encore inclure. Pour le retirer de l’index sans perdre vos modifications, ajoutez --staged.

git add app.js
git restore --staged app.js

Le fichier quitte l’index mais vos modifications restent dans le répertoire de travail. Notez que git restore (introduit avec git switch en Git 2.23) clarifie des usages autrefois portés par git checkout -- et git reset HEAD, que vous rencontrerez encore dans d’anciens tutoriels.

Étape 3 — Corriger le dernier commit avec –amend

Vous venez de commiter mais avez oublié un fichier, ou votre message comporte une faute. Plutôt que d’empiler un commit « correction du commit précédent », git commit --amend remplace le dernier commit.

git add fichier-oublie.js
git commit --amend -m "Message corrigé et complet"

Git fond vos changements en attente dans le dernier commit et vous laisse réécrire le message. Une mise en garde capitale : --amend réécrit le dernier commit (nouveau SHA). Ne l’utilisez donc que sur un commit non encore partagé, conformément au cadre de l’étape 1. Sur un commit déjà poussé, préférez l’approche de l’étape 5.

Étape 4 — Les trois visages de git reset

git reset déplace le pointeur de votre branche vers un commit antérieur. Ce qui change selon le mode, c’est le sort de l’index et du répertoire de travail. Comprendre ces trois modes, c’est maîtriser la moitié des réparations Git.

Mode Pointeur de branche Index Répertoire de travail Usage typique
--soft reculé préservé préservé Regrouper plusieurs commits en un seul (tout revient en zone préparée)
--mixed (défaut) reculé vidé préservé Défaire des commits en gardant les modifications à re-préparer
--hard reculé vidé écrasé Tout jeter et revenir à un état exact (DANGER)

Illustrons le cas le plus utile et le plus risqué. Supposons trois commits que vous voulez tous défaire tout en gardant le code pour le recomposer : git reset --mixed HEAD~3 recule de trois commits, vide l’index, mais laisse vos fichiers intacts. À l’inverse, git reset --hard HEAD~3 efface aussi vos fichiers — gardez-le pour les cas où vous êtes certain de vouloir tout perdre.

git reset --soft HEAD~3   # les 3 commits redeviennent des changements préparés
git reset --mixed HEAD~3  # ... des changements non préparés (défaut)
git reset --hard HEAD~3   # ... totalement effacés (irréversible en apparence)

Point d’étape — Après un reset, vérifiez avec git status et git log --oneline que vous êtes dans l’état voulu. Si un --hard a effacé un commit que vous regrettez, ne paniquez pas : l’étape 6 le récupère.

Étape 5 — Annuler un commit partagé avec revert

Quand un commit est déjà poussé et utilisé par l’équipe, le réécrire avec reset casserait l’historique des autres. La bonne méthode est git revert : au lieu d’effacer le commit fautif, Git crée un nouveau commit qui applique l’inverse exact de ses changements. L’historique est préservé, et l’effet du commit fautif est annulé.

git revert a1b2c3d

Git ouvre un message de commit déjà rédigé (« Revert … ») ; enregistrez-le. Le commit fautif reste visible dans l’historique, mais ses effets sont neutralisés par le commit de revert que vous pouvez pousser sans danger. C’est la différence fondamentale à retenir.

Critère git reset git revert
Effet sur l’historique Réécrit (supprime des commits) Ajoute un commit inverse
Sécurité si partagé Dangereux Sûr
Quand l’utiliser Commits locaux, non partagés Commits déjà poussés

Étape 6 — Le reflog, votre filet de sécurité

Voici l’outil qui transforme la peur en sérénité. Git tient un journal de tous les endroits où HEAD est passé : le reflog (journal des références). Même après un reset --hard dévastateur, un rebasage raté ou une branche supprimée, les commits « perdus » y sont encore référencés et restent récupérables pendant un bon moment (plusieurs semaines par défaut).

git reflog

Vous obtenez une liste numérotée des états récents, chacun noté HEAD@{n} avec sa description (commit, reset, rebase, checkout…). Repérez l’état d’avant la catastrophe, puis revenez-y. Pour restaurer la branche courante à cet état précis :

git reset --hard HEAD@{2}

Vous pouvez aussi, plus prudemment, créer une nouvelle branche sur le commit retrouvé sans toucher à l’actuelle, afin d’inspecter avant de décider :

git branch sauvetage HEAD@{2}

Le même mécanisme récupère une branche supprimée : retrouvez dans le reflog le SHA de son dernier commit, puis recréez la branche dessus. Tant que vous gardez le reflog en tête, presque rien n’est définitivement perdu sous Git.

Étape 7 — Mettre du travail de côté avec stash

Scénario classique : vous êtes en plein développement quand un correctif urgent doit partir sur une autre branche. Vos modifications ne sont pas prêtes à être commitées, mais elles empêchent de basculer proprement. git stash les met de côté et restaure un répertoire propre.

git stash push -m "WIP tri des produits"
git switch main
# ... traiter l'urgence, commiter, revenir ...
git switch feature/tri-produits
git stash pop

La commande git stash pop restaure vos modifications et retire l’entrée de la pile. Si vous voulez les réappliquer sans les retirer de la pile (par exemple sur plusieurs branches), utilisez git stash apply. Gérez la pile avec git stash list, et supprimez une entrée avec git stash drop. Par défaut, le stash ignore les fichiers non suivis ; ajoutez -u pour les inclure.

git stash list
git stash apply stash@{0}
git stash drop stash@{0}
git stash -u           # inclure aussi les fichiers non suivis

Deux outils d’appoint : cherry-pick et clean

Pour récupérer un commit précis d’une autre branche sans tout fusionner — par exemple appliquer ici un correctif fait ailleurs — git cherry-pick <sha> rejoue ce seul commit sur votre branche courante. C’est l’outil idéal quand vous avez commité sur la mauvaise branche : cherry-pickez le commit là où il devait aller, puis nettoyez l’origine.

Enfin, pour supprimer les fichiers non suivis qui encombrent votre dossier (artefacts de compilation, fichiers générés), git clean existe — mais c’est l’une des rares commandes vraiment destructrices. Faites toujours un essai à blanc avec -n avant de supprimer pour de vrai.

git clean -nd   # essai à blanc : liste ce qui SERAIT supprimé
git clean -fd   # supprime réellement (irréversible)

Point d’étapegit clean -nd ne supprime rien : il vous montre la liste. N’exécutez -fd qu’après avoir vérifié cette liste, car les fichiers supprimés ne passent pas par le reflog ni par aucun filet.

L’arbre de décision : quel outil pour quelle annulation

Avec autant d’outils, il est utile de figer une logique de choix applicable en quelques secondes. Posez-vous les questions dans cet ordre. Le changement est-il encore non commité ? Alors git restore (ou git restore --staged s’il est seulement préparé) suffit. Est-ce le tout dernier commit, et n’a-t-il pas été poussé ? git commit --amend le corrige. Voulez-vous défaire plusieurs commits locaux non partagés ? git reset, en choisissant soft, mixed ou hard selon ce que vous gardez.

Le commit est-il déjà poussé et partagé ? Ne le réécrivez pas : git revert crée un commit inverse sans danger. Pensez-vous avoir tout perdu après une manipulation ? git reflog avant toute chose, presque rien ne disparaît vraiment. Et si vous devez simplement libérer votre répertoire de travail le temps d’une urgence, git stash met votre travail de côté. Cet ordre — non commité, dernier commit, commits locaux, commit partagé, récupération, mise de côté — couvre la quasi-totalité des situations réelles et vous évite d’hésiter au mauvais moment.

🐞 Pièges fréquents

Symptôme / erreur Cause probable Correctif
« J’ai perdu des commits après un reset --hard » Le pointeur a reculé, les commits semblent disparus git reflog puis git reset --hard HEAD@{n}
Collègues cassés après annulation d’un commit poussé reset utilisé sur de l’historique partagé Utiliser git revert à la place
git stash pop provoque un conflit La branche a changé depuis la mise de côté Résoudre le conflit comme un conflit de fusion, puis git add
Fichiers supprimés par git clean introuvables clean ne passe pas par Git Toujours faire git clean -nd d’abord
Commit fait sur la mauvaise branche Oubli de basculer avant de commiter git cherry-pick vers la bonne branche, puis reset de l’origine

Travailler avec une connexion limitée

Toutes ces réparations sont locales : restore, reset, revert, reflog, stash et cherry-pick n’exigent aucune connexion, puisqu’ils n’agissent que sur votre dépôt et son journal. C’est une assurance précieuse : même hors ligne, vous pouvez expérimenter hardiment, sachant que le reflog vous rattrapera. La seule précaution liée au réseau concerne revert versus reset : dès qu’un commit a été poussé, basculez sur revert pour ne pas perturber les autres lors de la prochaine synchronisation.

✅ Récapitulatif

Vous disposez maintenant d’une trousse de secours complète. git restore annule le travail non commité ; git commit --amend corrige le dernier commit local ; git reset réorganise des commits locaux selon trois modes (soft garde tout en préparé, mixed garde le code, hard efface) ; git revert annule sans danger un commit partagé ; le reflog récupère ce qu’on croyait perdu ; et git stash met du travail de côté le temps d’une urgence. La règle d’or qui relie tout : réécrire en local, annuler par-dessus quand c’est partagé. Avec ces réflexes, plus aucune fausse manœuvre Git ne devrait vous effrayer.

🧾 Aide-mémoire

Commande Rôle
git restore <fichier> Annuler les modifications non commitées
git restore --staged <fichier> Retirer de l’index sans perdre les modifications
git commit --amend Corriger le dernier commit (local uniquement)
git reset --soft / --mixed / --hard Reculer la branche (3 niveaux d’effacement)
git revert <sha> Annuler un commit partagé par un commit inverse
git reflog Lister les états passés de HEAD (filet de sécurité)
git stash push / pop / list / drop Mettre de côté et restaurer un travail en cours
git cherry-pick <sha> Rejouer un commit précis sur la branche courante

💪 À vous de jouer

Créez trois commits, puis « perdez-les » avec un git reset --hard HEAD~3. Récupérez-les ensuite intégralement grâce au reflog, sans avoir noté aucun SHA à l’avance.

Voir une solution
echo a > a.txt && git add a.txt && git commit -m "commit A"
echo b > b.txt && git add b.txt && git commit -m "commit B"
echo c > c.txt && git add c.txt && git commit -m "commit C"
git reset --hard HEAD~3      # les trois semblent perdus
git reflog                   # repérer l'état "commit C"
git reset --hard HEAD@{1}    # tout est de retour

Le reflog conserve la trace de « commit C » : un simple reset --hard vers cet état restaure les trois commits. La leçon : tant que le reflog existe, un --hard n’est pas une condamnation.

FAQ

Q : reset ou revert ?
R : reset réécrit l’historique (réservé au local) ; revert ajoute un commit inverse (sûr pour ce qui est déjà partagé). En cas de doute sur du partagé, revert.

Q : J’ai fait reset --hard, tout est perdu ?
R : Presque jamais. git reflog liste les états récents de HEAD ; vous y retrouverez le commit et pourrez y revenir.

Q : Différence entre stash pop et stash apply ?
R : pop restaure puis retire l’entrée de la pile ; apply restaure en gardant l’entrée, utile pour réappliquer ailleurs.

Q : git clean est-il réversible ?
R : Non. Les fichiers non suivis qu’il supprime ne passent pas par Git. Faites toujours git clean -nd (essai à blanc) avant -fd.

Q : Combien de temps le reflog garde-t-il les commits ?
R : Par défaut, environ 90 jours pour les commits atteignables et 30 jours pour les autres, avant le nettoyage automatique. Largement de quoi se rattraper.

Ressources

Dans la même série

🔝 Retour au guide complet : Maîtriser Git et GitHub.

Partager