Aller au contenu

Git : annuler et corriger

Git permet presque toujours de revenir en arrière. Le choix de la commande dépend de où en est la modification et de son partage avec d’autres.

Situation Commande
Annuler des modifications non ajoutées git restore fichier
Retirer un fichier de l’index (avant commit) git restore --staged fichier
Corriger le dernier commit (non poussé) git commit --amend
Annuler un commit déjà poussé git revert
Défaire des commits locaux git reset
Mettre de côté des modifications git stash
Retrouver un commit « perdu » git reflog
Fenêtre de terminal
git restore fichier.txt # remet le fichier dans l'état du dernier commit
git restore . # tous les fichiers modifiés
git restore --staged fichier.txt # désindexe (garde les modifications dans le fichier)
git restore --source=HEAD~2 fichier.txt # récupère le fichier tel qu'il était 2 commits plus tôt
Fenêtre de terminal
git commit --amend -m "fix(auth): correct login redirect" # change seulement le message
git add oubli.txt
git commit --amend --no-edit # ajoute un fichier oublié au dernier commit

--amend réécrit le commit : à n’utiliser que s’il n’est pas encore poussé (sinon voir --force-with-lease dans Dépôts distants).

Fenêtre de terminal
git reset --soft HEAD~1 # annule le dernier commit, garde les modifications dans l'index
git reset HEAD~1 # idem (--mixed), garde les modifications dans les fichiers, non indexées
git reset --hard HEAD~1 # annule le commit ET supprime les modifications
git reset --hard origin/main # aligne la branche locale sur le dépôt distant (perd le travail local)
Mode Commits Index Fichiers
--soft annulés conservé conservés
--mixed (défaut) annulés vidé conservés
--hard annulés vidé supprimés

revert crée un nouveau commit qui annule les effets d’un commit existant, sans réécrire l’historique :

Fenêtre de terminal
git revert a1b2c3d # annule ce commit
git revert HEAD # annule le dernier
git revert -m 1 <commit-de-fusion> # annule une fusion (garde le parent 1)
git revert --no-commit a1b2c3d..e4f5g6h # plusieurs commits en un seul

Pour changer de branche sans valider un travail en cours :

Fenêtre de terminal
git stash # met de côté les modifications suivies
git stash -u # inclut aussi les fichiers non suivis
git stash push -m "essai de la recherche"
git stash list
git stash pop # réapplique le dernier stash et le supprime
git stash apply stash@{1} # réapplique sans supprimer
git stash drop stash@{0}
git stash show -p stash@{0} # contenu

Le reflog enregistre chaque déplacement de HEAD (commits, resets, changements de branche) :

Fenêtre de terminal
git reflog # historique des positions de HEAD
git switch -c secours a1b2c3d # recrée une branche sur un commit retrouvé
git reset --hard HEAD@{2} # revient à l'état d'il y a 2 mouvements

Les entrées du reflog sont conservées environ 90 jours (30 jours pour les commits inaccessibles), en local seulement.

Fenêtre de terminal
git clean -n # simulation : liste ce qui serait supprimé
git clean -fd # supprime fichiers et dossiers non suivis
git clean -fdx # supprime aussi les fichiers ignorés
  1. Révoquer immédiatement le secret (mot de passe, jeton, clé) chez son émetteur : même supprimé, il reste dans l’historique et dans toutes les copies déjà récupérées.
  2. Si le commit n’est pas poussé : git reset --soft HEAD~1, retirer le secret, recommiter.
  3. Sinon, réécrire l’historique avec git filter-repo (outil externe : sudo apt install git-filter-repo) :
Fenêtre de terminal
git filter-repo --path .env --invert-paths # retire le fichier .env de tout l'historique
git push --force-with-lease --all

Tous les collaborateurs doivent ensuite re-cloner le dépôt. La révocation reste l’action essentielle.

Fenêtre de terminal
git bisect start
git bisect bad # le commit actuel est défectueux
git bisect good v1.0.0 # cette version fonctionnait
# Git propose un commit intermédiaire : tester, puis indiquer git bisect good ou git bisect bad
git bisect reset # terminer et revenir