Par Anonyme (non vérifié) , 29 avril 2026

Introduction

Un commit Git référence zéro, un ou plusieurs commits parents. Tout l'historique est un graphe acyclique dirigé (DAG) de ces liens parents. Les branches et tags sont simplement des étiquettes sur des nœuds de ce graphe.

Anatomie d'un lien parent

git cat-file -p HEAD
# tree 9f1a...
# parent b2c3...
# parent d4e5...        (uniquement sur les merge commits)
# author Ada ...
# committer Ada ...

Un parent : historique linéaire. Deux parents : un merge. Zéro parent : un commit racine. Trois ou plus : un merge octopus.

Parcourir le graphe

git log --oneline --graph --all
git log --first-parent           # suivre uniquement les premiers parents
git log --topo-order
git log --date-order

--first-parent sur main est excellent pour voir le « tronc » de l'historique sans le bruit des côtés de merges.

Requêtes d'ancêtralité

git merge-base A B               # ancêtre commun le plus récent
git merge-base --is-ancestor X Y   # exit 0 si X est ancêtre de Y
git rev-list A..B --count          # commits dans B pas dans A

Syntaxe de plage

  • A..B : commits atteignables depuis B mais pas A.
  • A...B : différence symétrique.
  • ^A B : équivalent à A..B.
  • B --not A : équivalent à A..B.
git log main..feature
git log main...feature --left-right --oneline

Le fichier commit-graph

Depuis Git 2.18, Git peut écrire un fichier commit-graph qui pré-calcule les données d'ancêtralité pour les énormes dépôts :

git commit-graph write --reachable
git config --global core.commitGraph true
git config --global gc.writeCommitGraph true

Cela accélère considérablement git log --graph, git merge-base et les vérifications d'atteignabilité.

Merges octopus

Un seul merge commit peut avoir plusieurs parents :

git merge feature1 feature2 feature3

Les merges octopus ne réussissent que sans conflits. Ils sont utiles pour les branches d'intégration dans certains workflows mais rarement nécessaires.

Visualiser le graphe

git log --oneline --graph --decorate --all
gitk --all
git log --pretty=format:'%h %p %s'

%p affiche les SHAs des parents.

Numéros de génération

Le fichier commit-graph stocke un numéro de génération par commit : 1 pour les commits racines, max(générations parents) + 1 sinon. Les numéros de génération transforment de nombreuses requêtes d'ancêtralité en opérations O(log n). Git moderne (2.27+) écrit des dates de commit corrigées et des numéros de génération v2 quand le commit-graph est activé :

git commit-graph write --reachable --changed-paths
git config gc.writeCommitGraph true
git config core.commitGraph true
git log --oneline --graph -n 5

--changed-paths enregistre en plus un filtre de Bloom par commit listant les chemins modifiés, accélérant considérablement les requêtes git log limitées par chemin.

Erreurs fréquentes

Imaginer les branches comme des piles séparées de commits ; ce sont des étiquettes sur des nœuds qui peuvent partager des ancêtres. Utiliser HEAD~3 sur un merge commit et être surpris : ~ suit toujours le premier parent. Utilisez ^2, ^3 pour sauter à d'autres parents. Oublier que rebase réécrit la topologie du graphe en créant de nouveaux commits avec de nouveaux pointeurs parents ; les anciens commits vivent dans le reflog. Enfin, croire que le commit graph stocke des diffs ; il ne stocke que les trees et les parents. Les diffs sont calculés à la demande en comparant les trees.