Un parcours du tutoriel Annuler un commit : pourquoi le dernier commit est cassé, et comment git reset --soft permet de le corriger sans perdre de travail.
Ce scénario commence dans un projet de portfolio où le dernier commit est subtilement cassé. Vous allez lire l'historique, annuler ce commit en gardant vos changements, et le recommiter correctement. Voici ce qui se passe à chaque étape et pourquoi.
La situation
Seuls certains fichiers ont été indexés, le commit est donc incomplet.
Le projet a deux commits. Le dernier, « Add header section », a ajouté un header de navigation dans index.html. Le CSS correspondant pour ce header a été écrit dans style.css, mais il n'a jamais été indexé : il est toujours dans l'arbre de travail en tant que changement non commité.
Le commit est donc incomplet. Le site commité contient le balisage du header qui pointe vers des styles non sauvegardés. Quiconque récupère ce commit obtient un header cassé.
Commencez par exécuter git log --oneline et git status. Le log montre le commit « Add header section » ; le status montre style.css comme modifié mais non indexé. Cet écart est tout le problème.
La correction, étape par étape
git reset --soft recule HEAD d'un commit et garde vos changements indexés.
Inspecter ce qui a été commité
git log confirme le dernier commit, et git status montre que style.css est toujours modifié dans l'arbre de travail. Vous savez maintenant que le commit a capturé index.html mais pas style.css.
Annuler le commit, garder les changements
git reset --soft HEAD~1
Cela recule le pointeur de la branche d'un commit. Le changement d'index.html qui était dans le commit revient dans l'index, prêt à être commité à nouveau. Rien dans vos fichiers n'est supprimé.
Tout indexer cette fois
git add index.html style.css
Le balisage et ses styles sont maintenant indexés ensemble, pour que le prochain commit soit complet.
Recommiter le changement complet
git commit -m "Add header section"
L'historique contient à nouveau un seul commit « Add header section », mais cette fois il inclut style.css. Le site est entier.
Pourquoi --soft est le bon mode ici
git reset a trois modes, et la différence porte uniquement sur l'endroit où atterrissent vos changements :
--soft recule HEAD et garde les changements indexés. Idéal ici, car vous voulez immédiatement recommiter.
--mixed (par défaut) garde les changements mais désindexés, dans l'arbre de travail.
--hard jette entièrement les changements.
git reset --hard HEAD~1 supprimerait ici le travail du header en même temps que le commit. Réservez --hard aux cas où vous voulez vraiment perdre les changements.
Si vous lancez --hard par accident, le commit est généralement encore récupérable avec git reflog, qui liste chaque position prise par HEAD. Le tutoriel « Recover Lost Commits » traite ce flux.
Une nuance : commits partagés
Tout ce qui précède réécrit l'historique, ce qui est parfaitement sûr pour un commit qui n'existe que sur votre machine. Une fois un commit poussé et récupéré par d'autres, le réécrire force tout le monde à composer avec une branche divergée. Sur une branche partagée, annulez le changement avec un nouveau commit :
git revert HEAD
Toutes les façons d'annuler un commit
Les trois modes de reset diffèrent uniquement par l'endroit où atterrissent vos changements.
La bonne commande dépend de ce que vous voulez garder. Ce scénario a utilisé --soft ; voici l'ensemble complet :
- Annuler le dernier commit, garder les changements indexés —
git reset --soft HEAD~1
- Annuler le dernier commit, garder les changements désindexés —
git reset HEAD~1 (le mode --mixed par défaut)
- Annuler le dernier commit et jeter ses changements —
git reset --hard HEAD~1
- Annuler les N derniers commits, garder le travail —
git reset --soft HEAD~N
- Modifier sur place le message ou le contenu du dernier commit —
git commit --amend
- Annuler un commit déjà poussé —
git revert <commit>
reset réécrit l'historique et convient aux commits qui n'existent que sur votre machine ; revert ajoute un nouveau commit qui annule un ancien et constitue le choix sûr sur une branche que d'autres ont récupérée. Essayez chacune ici pour que la différence entre garder, désindexer et jeter votre travail devienne une seconde nature.