Vous avez fait un commit que vous voulez annuler. Et maintenant ?
Ça arrive à tout le monde. Vous faites un commit trop tôt, incluez un fichier que vous n'auriez pas dû, écrivez le mauvais message ou réalisez que le code n'est tout simplement pas correct. La bonne nouvelle : Git est conçu pour gérer ça. La meilleure nouvelle : dans la plupart des cas, vous pouvez annuler un commit sans perdre votre travail.
La bonne approche dépend d'une question clé : le commit a-t-il été pushé vers un remote, ou est-il encore local ? Les commits locaux vous donnent plus de flexibilité. Les commits pushés nécessitent une stratégie plus sûre car d'autres personnes ont peut-être déjà pullé vos changements.
Annuler un commit local avec git reset
Si le commit est encore local (non pushé), git reset est l'outil le plus courant. Il déplace le pointeur de branch vers un commit précédent, annulant effectivement votre commit. Ce qui arrive à ces changements dépend du flag que vous utilisez.
git reset --soft : annuler le commit, tout garder en staging
git reset --soft HEAD~1
Cela annule le dernier commit mais garde tous les changements en staging (dans l'index). Votre répertoire de travail n'est pas touché. C'est comme si vous n'aviez jamais exécuté git commit -- vous êtes de retour au moment juste avant de commiter.
Quand l'utiliser : Vous voulez changer le message du commit, ajouter plus de fichiers au commit, ou diviser le commit en plusieurs plus petits. Votre code est correct, vous avez juste commité prématurément.
git reset --mixed : annuler le commit, retirer les changements du staging
git reset --mixed HEAD~1
C'est le comportement par défaut de git reset (vous pouvez omettre le flag --mixed). Cela annule le commit et retire les changements du staging, mais vos fichiers restent modifiés dans le répertoire de travail. Rien n'est perdu.
Quand l'utiliser : Vous voulez repenser ce qu'il faut inclure dans le commit. Peut-être voulez-vous ne mettre en staging que certains fichiers, ou vous voulez revoir les changements avant de recommiter.
git reset --hard : annuler le commit, supprimer tous les changements
git reset --hard HEAD~1
Cela annule le commit et supprime définitivement tous les changements. Votre répertoire de travail est réinitialisé pour correspondre au commit précédent. Il n'y a aucun moyen de récupérer les changements supprimés via les opérations Git normales.
Quand l'utiliser : Vous êtes certain de ne pas vouloir les changements du tout. Peut-être avez-vous commité du code expérimental qui n'a pas fonctionné et vous voulez repartir de zéro. Utilisez ceci avec prudence.
Revenir plus loin en arrière
HEAD~1 fait référence à un commit avant le HEAD actuel. Vous pouvez aller plus loin :
git reset --soft HEAD~3
Cela annule les trois derniers commits, combinant tous leurs changements dans la zone de staging. Vous pouvez aussi cibler un commit spécifique par son hash :
git reset --soft a1b2c3d
Corriger le dernier commit avec git commit --amend
Si vous avez juste besoin de modifier le dernier commit plutôt que de l'annuler complètement, --amend est l'option la plus rapide :
git commit --amend -m "corrected commit message"
Cela remplace le commit précédent par un nouveau. Vous pouvez aussi l'utiliser pour ajouter des fichiers oubliés :
git add forgotten-file.ts
git commit --amend --no-edit
Le flag --no-edit garde le message de commit original. Le résultat est un seul commit corrigé au lieu d'une séquence de commits "oups".
Important : Comme reset, amend réécrit l'historique. Utilisez-le uniquement sur des commits qui n'ont pas été pushés. Si vous faites un amend d'un commit pushé puis un force-push, toute personne ayant pullé le commit original aura des problèmes.
Annuler un commit pushé avec git revert
Une fois qu'un commit a été pushé vers un remote partagé, vous ne devriez pas réécrire l'historique. D'autres développeurs ont peut-être basé leur travail sur ce commit. Utilisez plutôt git revert :
git revert HEAD
Cela crée un nouveau commit qui fait exactement l'inverse du commit ciblé. Si le commit original ajoutait une ligne, le commit de revert la supprime. S'il supprimait un fichier, le commit de revert le restaure. Le commit original reste dans l'historique, et le revert est ajouté par-dessus.
Quand l'utiliser : Chaque fois que vous devez annuler un commit qui a déjà été pushé. C'est sûr car cela ajoute à l'historique plutôt que de le réécrire.
Reverter un commit plus ancien
Vous pouvez reverter n'importe quel commit, pas seulement le plus récent :
git revert a1b2c3d
Git tentera de créer un commit de revert qui annule uniquement les changements de ce commit spécifique. Si ces changements se chevauchent avec du travail ultérieur, vous pourriez obtenir un conflit nécessitant une résolution manuelle.
Reverter plusieurs commits
Pour reverter une série de commits :
git revert HEAD~3..HEAD
Cela crée des commits de revert individuels pour chaque commit de la série. Si vous préférez un seul commit de revert, ajoutez le flag --no-commit et faites le commit manuellement :
git revert --no-commit HEAD~3..HEAD
git commit -m "revert last 3 commits"
Choisir la bonne approche
| Situation | Méthode | Ce qui arrive à vos changements |
|---|---|---|
| Commité trop tôt, veut re-stager | git reset --soft HEAD~1 |
Les changements restent en staging |
| Commité trop tôt, veut retravailler | git reset --mixed HEAD~1 |
Les changements restent dans le répertoire de travail |
| Commité quelque chose à supprimer | git reset --hard HEAD~1 |
Les changements sont supprimés |
| Besoin de corriger le message ou ajouter un fichier | git commit --amend |
Le commit précédent est remplacé |
| Besoin d'annuler un commit pushé en toute sécurité | git revert HEAD |
Un nouveau commit annule les changements |
Récupérer après des erreurs
Même si vous utilisez git reset --hard et réalisez que vous n'auriez pas dû, il y a souvent un moyen de récupérer. Git conserve un journal des positions précédentes de HEAD, appelé le reflog :
git reflog
Cela montre une liste des positions récentes de HEAD. Vous pouvez trouver le commit que vous pensiez avoir perdu et revenir dessus :
git reset --hard HEAD@{2}
Le reflog est votre filet de sécurité. Les entrées sont conservées pendant 90 jours par défaut, vous avez donc une fenêtre généreuse pour récupérer de vos erreurs.
Annuler des commits dans GitSquid
GitSquid simplifie les opérations d'annulation les plus courantes. Vous pouvez appuyer sur Cmd+Z (ou Ctrl+Z sur Windows et Linux) immédiatement après avoir commité pour annuler le dernier commit, en gardant vos changements en staging et prêts à être retravaillés. Pour des opérations plus spécifiques, un clic droit sur n'importe quel commit dans le graphe vous donne accès aux options de reset et revert via un menu contextuel, vous permettant de cibler exactement le commit que vous voulez annuler sans mémoriser de flags.
Annuler un commit Git ne doit pas être stressant. Comprenez la différence entre reset, amend et revert, sachez lequel convient à votre situation, et vous pourrez corriger vos erreurs en toute confiance. La distinction la plus importante est simple : si c'est local, utilisez reset ou amend. Si c'est pushé, utilisez revert.