Von Gast (nicht überprüft) , 29 April 2026

Einführung

Ein Git-Commit referenziert null, einen oder mehrere Eltern-Commits. Die gesamte Historie ist ein gerichteter azyklischer Graph (DAG) dieser Eltern-Verknüpfungen. Branches und Tags sind einfach Labels auf Knoten dieses Graphen.

Anatomie einer Eltern-Verknüpfung

git cat-file -p HEAD
# tree 9f1a...
# parent b2c3...
# parent d4e5...        (nur bei Merge-Commits)
# author Ada ...
# committer Ada ...

Ein Elternteil: lineare Historie. Zwei Eltern: ein Merge. Null Eltern: ein Wurzel-Commit. Drei oder mehr: ein Octopus-Merge.

Den Graph durchlaufen

git log --oneline --graph --all
git log --first-parent           # nur ersten Eltern folgen
git log --topo-order
git log --date-order

--first-parent auf main ist großartig, um den "Trunk" der Historie ohne Merge-Side-Rauschen zu sehen.

Vorfahrenabfragen

git merge-base A B               # jüngster gemeinsamer Vorfahre
git merge-base --is-ancestor X Y   # Exit 0 falls X Vorfahre von Y
git rev-list A..B --count          # Commits in B, nicht in A

Bereichssyntax

  • A..B: Commits von B aus erreichbar, nicht von A.
  • A...B: symmetrische Differenz.
  • ^A B: gleichbedeutend mit A..B.
  • B --not A: gleichbedeutend mit A..B.
git log main..feature
git log main...feature --left-right --oneline

Die commit-graph-Datei

Seit Git 2.18 kann Git eine commit-graph-Datei schreiben, die Vorfahren-Daten für riesige Repositories vorberechnet:

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

Dies beschleunigt git log --graph, git merge-base und Erreichbarkeitsprüfungen dramatisch.

Octopus-Merges

Ein einzelner Merge-Commit kann viele Eltern haben:

git merge feature1 feature2 feature3

Octopus-Merges gelingen nur ohne Konflikte. Sie sind in einigen Workflows für Integrationsbranches nützlich, aber selten nötig.

Den Graph visualisieren

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

%p gibt Eltern-SHAs aus.

Generationsnummern

Die commit-graph-Datei speichert eine Generationsnummer pro Commit: 1 für Wurzel-Commits, max(Eltern-Generationen) + 1 sonst. Generationsnummern verwandeln viele Vorfahrenabfragen in O(log n)-Operationen. Modernes Git (2.27+) schreibt korrigierte Commit-Daten und Generation-v2-Nummern, wenn der commit-graph aktiviert ist:

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 zeichnet zusätzlich pro Commit einen Bloom-Filter auf, der geänderte Pfade auflistet, was pfadbeschränkte git log-Abfragen dramatisch beschleunigt.

Häufige Fehler

Sich Branches als getrennte Stapel von Commits vorstellen; sie sind Labels auf Knoten, die Vorfahren teilen können. HEAD~3 auf einem Merge-Commit verwenden und überrascht sein: ~ folgt immer dem ersten Elternteil. Verwenden Sie ^2, ^3, um zu anderen Eltern zu springen. Vergessen, dass Rebase die Graph-Topologie umschreibt, indem es neue Commits mit neuen Eltern-Zeigern erstellt; alte Commits leben im Reflog weiter. Schließlich: Glauben, der Commit-Graph speichere Diffs; er speichert nur Trees und Eltern. Diffs werden bei Bedarf durch Vergleich der Trees berechnet.