Aller au contenu
Développement medium

Sélection de révisions Git

10 min de lecture

Git offre une dizaine de syntaxes pour désigner un commit précis : SHA court, HEAD~3, main^2, HEAD@{5}, A..B. Comprendre ces syntaxes est indispensable pour utiliser efficacement log, diff, reset, rebase et cherry-pick. Ce guide couvre toutes les formes de sélection de révisions.

Prérequis : Consulter l'historique et Les branches en bref.

  • Utiliser ^ et ~ pour naviguer dans l'historique commit par commit
  • Cibler des plages de commits avec les opérateurs A..B et A...B
  • Retrouver un commit perdu avec HEAD@{N} et le reflog
  • Résoudre n'importe quelle référence en SHA avec git rev-parse

Chaque commit est identifié par un hash SHA-1 de 40 caractères :

a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0

En pratique, les 7 premiers caractères suffisent (SHA court) :

Fenêtre de terminal
git show a1b2c3d
git log --oneline # Affiche les SHA courts automatiquement

Git résout le SHA court vers le hash complet tant qu'il n'y a pas d'ambiguïté. Pour un projet très gros, utilisez 8 à 12 caractères.

Pour obtenir le SHA complet à partir d'un court :

Fenêtre de terminal
git rev-parse a1b2c3d
# a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0

Les noms de branches et tags sont des alias vers un SHA :

Fenêtre de terminal
git rev-parse main # SHA du dernier commit de main
git rev-parse v1.2.0 # SHA du commit pointé par le tag
git rev-parse HEAD # SHA du commit courant

HEAD pointe toujours vers le commit courant (via la branche active).

Deux opérateurs pour naviguer vers les parents d'un commit :

~n remonte de n commits sur le premier parent :

HEAD~0 = HEAD
HEAD~1 = parent de HEAD
HEAD~2 = grand-parent de HEAD
HEAD~3 = arrière-grand-parent
Fenêtre de terminal
git show HEAD~3 # 3 commits avant HEAD
git diff HEAD~5 HEAD # Différences sur les 5 derniers commits

^n sélectionne le n-ième parent d'un commit de merge :

HEAD^ = HEAD^1 = premier parent (branche dans laquelle on a mergé)
HEAD^2 = deuxième parent (branche qui a été mergée)

Pour un commit normal (non-merge), ^ et ~ sont équivalents : HEAD^ = HEAD~1.

HEAD~2^2 = grand-parent de HEAD, deuxième parent
HEAD^^ = HEAD~2 (parent du parent, premier parent à chaque fois)
HEAD^2~3 = 3 commits avant le deuxième parent de HEAD

Le reflog enregistre chaque position de HEAD (et des branches) dans le temps. Contrairement à l'historique (qui suit les commits), le reflog suit les mouvements :

Fenêtre de terminal
git reflog
# a1b2c3d HEAD@{0}: commit: Ajout feature X
# e4f5a6b HEAD@{1}: checkout: moving from main to feature
# d7c8b9a HEAD@{2}: commit: Fix bug Y

Utilisation :

Fenêtre de terminal
git show HEAD@{3} # Position de HEAD il y a 3 mouvements
git show main@{yesterday} # Où pointait main hier
git show HEAD@{2.hours.ago} # HEAD il y a 2 heures
git diff HEAD@{0} HEAD@{5} # Ce qui a changé en 5 mouvements

Le reflog est votre filet de sécurité : même après un reset --hard, le commit précédent reste dans le reflog pendant 90 jours.

Fenêtre de terminal
git log main..feature # Commits dans feature, absents de main
git log origin/main..HEAD # Commits locaux non encore poussés

Cette syntaxe est la plus courante. Elle répond à la question : « quels commits dois-je pousser ? » ou « quels commits apporte cette branche ? ».

Triple-point A...B, commits dans l'un OU l'autre, mais pas les deux

Section intitulée « Triple-point A...B, commits dans l'un OU l'autre, mais pas les deux »
Fenêtre de terminal
git log main...feature # Exclusifs à main OU feature
git log --left-right main...feature # Indique < (main) ou > (feature)

Résultat avec --left-right :

< d7c8b9a Fix bug Y (seulement dans main)
> a1b2c3d Ajout feature X (seulement dans feature)
> e4f5a6b Refactor module Z (seulement dans feature)
Fenêtre de terminal
git log feature --not main # Équivalent à main..feature
git log feature ^main # Même chose (^ en début = exclusion)
git log feature ^main ^develop # Dans feature, ni dans main ni develop

git rev-parse traduit n'importe quelle syntaxe en SHA :

Fenêtre de terminal
git rev-parse HEAD~3 # SHA du commit 3 avant HEAD
git rev-parse main^2 # SHA du 2e parent du dernier commit de main
git rev-parse --short HEAD # SHA court (7 caractères)
git rev-parse --verify HEAD@{5} # Vérifie que la ref existe

Cas pratiques en scripting :

Fenêtre de terminal
# Vérifier qu'on est sur main
if [[ "$(git rev-parse --abbrev-ref HEAD)" != "main" ]]; then
echo "Pas sur main !"
exit 1
fi
# Comparer deux branches
MERGE_BASE=$(git merge-base main feature)
echo "Point de divergence : $MERGE_BASE"
SyntaxeSignificationExemple
abc1234SHA courtgit show abc1234
HEADCommit courantgit show HEAD
mainDernier commit de la branchegit log main
v1.0Commit du taggit show v1.0
HEAD~nN-ième ancêtre (premier parent)git show HEAD~3
HEAD^nN-ième parent (merge)git show HEAD^2
HEAD@{n}N-ième entrée refloggit show HEAD@{5}
@{yesterday}Reflog par dategit show main@{yesterday}
A..BDans B, pas dans Agit log main..feature
A...BExclusifs à A ou Bgit log main...feature
^A / --not AExclure Agit log feature ^main
SymptômeCause probableSolution
ambiguous argument 'HEAD^' (Windows)^ interprété par cmd.exeUtilisez HEAD^^ ou "HEAD^" entre guillemets
fatal: bad default revision 'HEAD'Repo vide, pas de commitFaites un premier commit
reflog affiche (unreachable)Commit orphelinNormal, récupérable pendant 90 jours
SHA court ambiguCollision de hash partielUtilisez plus de caractères (--abbrev=12)
  • ~n remonte de N commits en ligne droite (premier parent)
  • ^n choisit le N-ième parent d'un merge
  • A..B = commits dans B absents de A (le plus utilisé)
  • A...B = commits exclusifs à l'une ou l'autre branche
  • Le reflog (HEAD@{n}) est votre filet de sécurité local
  • git rev-parse traduit toute syntaxe en SHA

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn