Introduction
Git garde plusieurs refs spéciales « auxiliaires » dans .git/ pour enregistrer l'état pendant les opérations multi-étapes. Les connaître transforme les récupérations effrayantes en one-liners.
ORIG_HEAD
ORIG_HEAD est défini chaque fois qu'une opération « dangereuse » déplace beaucoup HEAD : merge, rebase, reset, am. Il capture la pointe précédente pour que vous puissiez annuler :
git merge feature
# décide que c'était une erreur
git reset --hard ORIG_HEAD
Même astuce après un mauvais rebase ou reset :
git rebase main
git reset --hard ORIG_HEAD # retour à l'état pré-rebase
MERGE_HEAD
Pendant un merge, MERGE_HEAD enregistre la pointe de la branche en cours de merge. Il existe du début de git merge jusqu'à ce que le merge commit soit créé ou que le merge soit annulé :
git merge feature
cat .git/MERGE_HEAD
git merge --abort # supprime MERGE_HEAD
Si vous avez fini de résoudre les conflits et voulez écrire le merge commit :
git commit # utilise MERGE_HEAD pour enregistrer le second parent
MERGE_MSG et AUTO_MERGE
Les fichiers compagnons incluent .git/MERGE_MSG (le message de commit préparé) et, depuis Git 2.40, AUTO_MERGE (un tree contenant la meilleure résolution automatique de Git). Ce dernier est utile pour différencier votre résolution manuelle.
CHERRY_PICK_HEAD et REVERT_HEAD
Pendant un cherry-pick ou un revert, Git enregistre le commit source :
git cherry-pick a1b2c3d
cat .git/CHERRY_PICK_HEAD
git cherry-pick --abort
git cherry-pick --continue # après résolution des conflits
Le même motif s'applique à git revert avec REVERT_HEAD.
BISECT_HEAD et REBASE_HEAD
Lors d'un bisect ou rebase, Git écrit aussi BISECT_HEAD ou REBASE_HEAD pour suivre l'état en cours. Des outils comme git status les utilisent pour afficher des messages précis « vous êtes au milieu d'un X ».
FETCH_HEAD
Après un fetch, FETCH_HEAD liste ce qui a été fetché, une ref par ligne. git pull le lit pour savoir quoi merger :
git fetch origin main
cat .git/FETCH_HEAD
git merge FETCH_HEAD
Mettre tout ensemble
git status # référence tous ces refs au besoin
ls .git/*HEAD # liste les refs auxiliaires courantes
Détecter les opérations en cours
git status lit ces refs auxiliaires pour vous dire ce qui est en cours. Les scripts peuvent faire de même en testant l'existence des fichiers :
if test -f "$(git rev-parse --git-dir)/MERGE_HEAD"; then
echo "merge en cours"
fi
if test -f "$(git rev-parse --git-dir)/CHERRY_PICK_HEAD"; then
echo "cherry-pick en cours"
fi
if test -d "$(git rev-parse --git-dir)/rebase-merge"; then
echo "rebase interactif en cours"
fi
C'est exactement ce que font les intégrations d'invite shell comme __git_ps1 pour afficher (main|MERGING).
Erreurs fréquentes
Essayer de supprimer MERGE_HEAD manuellement pour échapper à un merge ; utilisez git merge --abort. Oublier l'existence d'ORIG_HEAD et recréer des commits à la main après un mauvais reset. Confondre FETCH_HEAD (dernier fetch, transitoire) avec les refs de tracking distant comme origin/main (persistantes). Et enfin, scripter autour de ces refs en supposant qu'elles existent ; MERGE_HEAD n'existe que pendant un merge, donc testez toujours l'existence du fichier avant de le lire.