Git : annuler le dernier commit sans rien perdre
Annuler le dernier commit sans risque : reset --soft pour garder les changements, --mixed pour désindexer, revert pour un commit poussé — commandes exactes.
Remove, delete, cancel ou undo le dernier commit — quelle que soit la recherche, la commande qui garde les changements est la même. TL;DR : pour annuler le dernier commit en gardant les changements, lance git reset --soft HEAD~1 (changements restés indexés) ou git reset HEAD~1 (changements dans le répertoire de travail). Si le commit est déjà poussé, lance plutôt git revert HEAD — il crée un nouveau commit qui l'annule sans réécrire l'historique. Ces trois commandes couvrent quasiment tous les « j'ai commité trop tôt ». La suite passe chaque cas en revue avec des commandes à copier-coller, explique la différence entre --soft, --mixed et --hard, et montre comment récupérer la mise si quelque chose tourne mal. Toutes les commandes ci-dessous fonctionnent sur toute installation récente de Git sous Linux, macOS ou Windows.
Comment annuler le dernier commit en gardant les changements ?
Le cas le plus courant : tu as commité, puis repéré une coquille, un fichier manquant, ou réalisé que le changement appartient à un autre commit. Rien n'est poussé. Annule le commit et remets tout en place :
# Le commit disparaît de l'historique — les changements retournent dans l'index
git reset --soft HEAD~1
# Les changements retournent plutôt dans le répertoire de travail (non indexés)
git reset HEAD~1
HEAD~1 signifie « un commit avant l'endroit où HEAD pointe maintenant ». Après l'une ou l'autre commande, tes fichiers sont intacts sur le disque — seul le pointeur de branche a bougé. Vérifie avec git status : avec --soft les changements sont indexés, prêts à être re-commités avec les corrections ; sans flag ils sont non indexés, donc tu peux retoucher librement avant.
Habitude plus sûre encore, quand tu veux juste ajouter des fichiers au dernier commit : ne l'annule pas du tout.
git add forgotten-file.txt
git commit --amend --no-edit
--amend remplace le dernier commit sur place (pas de changement de message ici). À noter : amender un commit déjà poussé réécrit l'historique — on y revient plus bas.
Quelle différence entre --soft, --mixed et --hard ?
C'est le passage à mémoriser, parce que le flag décide où finissent tes changements — et s'ils peuvent être perdus :
| Flag | Commit annulé ? | Changements sur disque | Changements indexés ? | Usage typique |
|---|---|---|---|---|
--soft |
Oui | Conservés | Oui | Re-committer avec de petites corrections |
--mixed (défaut) |
Oui | Conservés | Non | Regrouper autrement, ré-indexer sélectivement |
--hard |
Oui | Supprimés | — | Jeter le travail entièrement |
git revert |
Non (nouveau commit) | Conservés | — | Annuler un commit déjà poussé |
--hard est le seul dangereux : il jette le commit et les changements. Avant tout reset --hard, mets ce que tu as à l'abri :
git branch backup-before-reset # assurance pas chère
git reset --hard HEAD~1 # commit + changements effacés
Si tu as déjà lancé la version dangereuse, tout n'est pas perdu — git reflog se souvient du passage de HEAD :
git reflog # repère le hash du commit perdu
git reset --hard HEAD@{1} # ou : git reset --hard <hash>
Le reflog conserve les commits orphelins environ 90 jours par défaut, donc « j'ai fait un hard-reset par erreur » se récupère presque toujours si tu agis avant le garbage collection.
Et si le commit est déjà poussé ?
Si le commit est sur une branche partagée (tout sauf ta propre branche de fonctionnalité), ne réécris pas l'historique. Utilise git revert, qui calcule le changement inverse et en fait un commit :
git revert HEAD
git push
Tous ceux qui pull reçoivent simplement un nouveau commit qui retire les changements de l'ancien. Pas de force-push, pas de collègues cassés. Pour annuler une série de commits, revert une plage : git revert --no-commit HEAD~3..HEAD && git commit.
L'alternative — git reset --hard HEAD~1 && git push --force-with-lease — n'est acceptable que sur une branche que personne d'autre ne consomme, et --force-with-lease (jamais le --force nu) est la seule forme sûre : elle refuse si quelqu'un a poussé entre-temps. Forcer la poussée sur des branches partagées, c'est ainsi que des équipes perdent des commits et que les logs de la CI cessent mystérieusement de correspondre au checkout de quiconque.
Comment garder le commit de côté pour plus tard ?
Parfois le commit est du bon travail à la mauvaise adresse — mauvaise branche, ou trop tôt. Plutôt que de l'annuler, déplace-le :
git branch stash-commit # gare le commit sur une nouvelle branche
git reset --hard HEAD~1 # puis nettoie ta branche courante
Ou emmène juste ce commit sur une autre branche sans toucher la tienne :
git cherry-pick <hash> # depuis la branche cible
Entre reset --soft, cherry-pick et revert, il n'existe aucun commit que tu ne puisses déplacer ou annuler — la subtilité, c'est de choisir « déplacer » ou « annuler » avant de tendre la main vers un flag.
Undo, revert, reset, remove, cancel — chaque mot a sa commande
La moitié de la confusion vient du vocabulaire : six verbes tapés dans un moteur de recherche, trois commandes qui existent vraiment. Associez le mot que vous avez en tête au drapeau qui le fait :
| Le mot tapé | Ce que vous voulez | La commande | Changements conservés ? |
|---|---|---|---|
| undo / uncommit | commit parti, travail de retour | git reset --soft HEAD~1 | oui — indexés |
| undo, non indexés | commit parti, travail en vrac | git reset HEAD~1 | oui — mixed |
| remove / drop | commit et modifications supprimés | git reset --hard HEAD~1 | non — reflog ~90 jours |
| revert / cancel, poussé | annulation publique, historique intact | git revert HEAD | oui — nouveau commit |
Ces verbes ne sont pas synonymes dans Git : revert ne touche jamais au passé, reset le réécrit. Le mauvais mot dit à un collègue, c'est la mauvaise commande reçue.
Quelle méthode d'annulation choisir ? Le guide express
- Non poussé, tu veux corriger et re-committer →
git reset --soft HEAD~1 - Non poussé, tu veux ré-indexer sélectivement →
git reset HEAD~1(mixed) - Tu veux les changements disparus complètement →
git reset --hard HEAD~1(le reflog sait, si tu regrettes) - Déjà poussé sur une branche partagée →
git revert HEAD - Le commit appartient à une autre branche →
cherry-pick, ne l'annule pas
Tu veux que la décision soit prise pour toi ? Le générateur git undo pose ces trois questions et imprime la commande.
Dernier conseil d'exploitation : si un mauvais commit a fini sur un serveur — un hook de déploiement raté, un runner CI qui déraille après un force-push — le prochain endroit où regarder, ce sont les logs de la machine, pas Git. Sur toute machine systemd, journalctl -u <service> -n 100 montre exactement ce qui a tourné et quand ; notre mémo journalctl a les motifs à copier-coller. Et si ton flux de travail inclut un LLM local pour relire les diffs, nous avons comparé les deux options principales dans Ollama vs LM Studio.