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
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
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