Développement web

Comment annuler le dernier commit dans Git sans perdre de travail

Comment annuler le dernier commit avec reset, revert et amend, lequel utiliser quand le commit est déjà poussé et comment récupérer un commit que l’on croyait perdu.

Pour annuler le dernier commit dans Git, vous avez trois options selon ce que vous voulez conserver : git reset --soft HEAD~1 supprime le commit mais garde les modifications indexées ; git reset --hard HEAD~1 supprime le commit et les modifications ; et git revert HEAD crée un nouveau commit qui annule le précédent sans réécrire l’historique, ce qui en fait l’option sûre si vous avez déjà poussé.

Vous verrez ci-dessous quand utiliser chacune, comment corriger un commit au lieu de le supprimer (--amend) et comment récupérer un commit que vous pensiez perdu avec git reflog.

D’abord : avez-vous poussé ?

Cette question décide de tout le reste.

  • Vous n’avez pas poussé (le commit n’existe que sur votre machine) : vous pouvez réécrire l’historique avec git reset ou --amend sans déranger personne.
  • Vous avez poussé sur une branche partagée : ne réécrivez pas l’historique. Utilisez git revert, qui ajoute un nouveau commit au lieu de supprimer l’existant. Si vous forcez un push après un reset, le reste de l’équipe aura un historique différent du vôtre et les conflits sont garantis.

Option 1 : git reset (annuler en local)

git reset déplace la référence de la branche (HEAD) vers un commit antérieur. HEAD~1 signifie « un commit avant l’actuel ». Ce qu’il advient des modifications de ce commit dépend du mode :

# Supprime le commit ; les modifications restent dans l’index (staged)
git reset --soft HEAD~1

# Supprime le commit ; les modifications restent dans le répertoire de travail, non indexées (mode par défaut)
git reset --mixed HEAD~1
git reset HEAD~1

# Supprime le commit ET jette les modifications. Irréversible sauf via reflog.
git reset --hard HEAD~1
Mode Supprime le commit ? Garde les modifications ? Où vont-elles ?
--soft Oui Oui Indexées, prêtes pour un nouveau commit
--mixed (par défaut) Oui Oui Dans le répertoire de travail, non indexées
--hard Oui Non Jetées

Cas typique : vous avez commité trop tôt et voulez ajouter quelque chose. git reset --soft HEAD~1, ajoutez les fichiers manquants et recommitez.

Pour annuler plusieurs commits, changez le nombre : HEAD~3 recule de trois.

Option 2 : git commit –amend (corriger, pas supprimer)

Si vous voulez seulement changer le message du dernier commit ou y ajouter un fichier oublié, inutile de l’annuler :

# Changer seulement le message
git commit --amend -m "Message corrigé"

# Ajouter un fichier oublié au dernier commit en gardant le message
git add fichier-oublie.js
git commit --amend --no-edit

--amend remplace le dernier commit par un nouveau (avec un hash différent). C’est donc une réécriture de l’historique : la même règle s’applique, ne pas l’utiliser si vous avez déjà poussé sur une branche partagée.

Option 3 : git revert (annuler sans réécrire)

git revert crée un nouveau commit qui applique les modifications inverses du commit indiqué. L’historique conserve le commit d’origine et son annulation, ce qui le rend sûr sur les branches partagées.

# Annule le dernier commit et ouvre l’éditeur pour le message
git revert HEAD

# Idem, sans ouvrir l’éditeur
git revert --no-edit HEAD

# Annuler un commit précis par son hash
git revert a1b2c3d

Si le commit à annuler est un merge, il faudra indiquer quel parent conserver avec -m 1 ; la documentation de git-revert l’explique en détail.

Si vous avez poussé et devez quand même réécrire

Il arrive qu’un reset après push soit inévitable (par exemple, vous avez poussé un mot de passe par erreur et devez le retirer de l’historique). Dans ce cas :

git reset --hard HEAD~1
git push --force-with-lease

--force-with-lease est préférable à --force : il n’écrase la branche distante que si personne n’a poussé depuis votre dernier fetch, ce qui évite d’effacer le travail d’autrui par inadvertance. Prévenez l’équipe, qui devra mettre à jour sa copie. Et rappelez-vous qu’un secret publié doit être considéré comme compromis et renouvelé même si vous le retirez de l’historique.

J’ai fait un reset –hard et je dois récupérer le commit

git reflog garde une trace de tous les endroits par lesquels HEAD est passé ces dernières semaines, y compris les commits qui ne sont plus sur aucune branche :

git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# e4f5g6h HEAD@{1}: commit: Ajoute la validation du formulaire
# ...

# Revenir à l’état d’avant le reset
git reset --hard e4f5g6h

Tant que Git n’a pas exécuté son ramasse-miettes (par défaut, les objets sans référence sont conservés au moins 30 jours dans le reflog), le commit est toujours là.

Quelle commande utiliser : résumé

Je veux… Commande
Refaire le commit avec plus de modifications (sans push) git reset --soft HEAD~1
Rééditer les fichiers avant de commiter (sans push) git reset HEAD~1
Jeter le commit et ses modifications (sans push) git reset --hard HEAD~1
Changer le message ou ajouter un fichier (sans push) git commit --amend
Annuler un commit déjà publié git revert HEAD
Récupérer un commit après un reset malheureux git reflog + git reset --hard <hash>

Conclusion

Avant d’annuler un commit, demandez-vous si vous l’avez déjà partagé. Sinon, git reset (avec le bon mode) ou --amend vous donnent un contrôle total. Si oui, git revert garde un historique cohérent pour toute l’équipe. Et quoi qu’il arrive, git reflog est le filet de sécurité : dans Git, il est très difficile de perdre vraiment un commit.

Sources et références

  1. Documentation officielle : git-reset git-scm.com
  2. Documentation officielle : git-revert git-scm.com
  3. Documentation officielle : git-commit (option --amend) git-scm.com
  4. Documentation officielle : git-reflog git-scm.com
  5. Pro Git (livre officiel) : Annuler des actions git-scm.com