Die vier fundamentalen Objekttypen in Git đ
Git ist im Kern nichts anderes als eine inhaltsadressierte Datenbank â jedesein elegantes System, das auf nur vier fundamentalen Objekttypen basiert. Wenn du verstehst, wie diese Objekte funktionieren und zusammenhĂ€ngen, wirst du Git nie wieder als âmagische Black Box" wahrnehmen, sondern als das durchdachte, transparente System, das es wirklich ist.
Das Fundament: Gits Objektmodell
Jedes Git-Repository speichert seine gesamte Geschichte in Form von Objekten im Verzeichnis .git/objects/. Jedes Objekt wird durch seineneinen SHA-1-Hash identifiziert.identifiziert Dieseâ Architektureine basiert40-stellige hexadezimale Zeichenkette, die aus dem Inhalt des Objekts berechnet wird. Das bedeutet: Gleicher Inhalt ergibt immer den gleichen Hash, egal auf genauwelchem vierComputer fundamentalenoder Objekttypen,in diewelchem zusammenRepository.
flowchart gesamteTB
Versionshistoriesubgraph abbilden.Objektdatenbank[".git/objects/"]
B1["Blob\nfa3c2..."]
B2["Blob\n8b137..."]
B3["Blob\ne69de..."]
T1["Tree\na1b2c..."]
T2["Tree\nd4e5f..."]
C1["Commit\n7f8d9..."]
C2["Commit\n3a4b5..."]
TAG["Tag\nc6d7e..."]
end
C1 --> T1
C2 --> T2
C2 -.->|parent| C1
T1 --> B1
T1 --> B2
T1 --> T2
T2 --> B3
TAG --> C2
style B1 fill:#e8f4e8,color:#000000
style B2 fill:#e8f4e8,color:#000000
style B3 fill:#e8f4e8,color:#000000
style T1 fill:#fff3e0,color:#000000
style T2 fill:#fff3e0,color:#000000
style C1 fill:#e3f2fd,color:#000000
style C2 fill:#e3f2fd,color:#000000
style TAG fill:#fce4ec,color:#000000
Die1. Objekttypen im Ăberblick
Blob â derDer Dateiinhalt đ
Ein Blob (Binary Large Object) ist das einfachste Git-Objekt. Es speichert den reinen Inhalt einer Datei â ohne Metadaten wie Dateinamen oder Berechtigungen. Zwei Dateien mit identischem Inhalt teilen sich denselben Blob, unabhĂ€ngig von ihrem Namen oder Speicherort.
Eigenschaften:
Eigenschaften des Blob-Objekts
Das Letztere ist besonders clever: Wenn du dieselbe Datei in zehn verschiedenen Verzeichnissen hast, speichert Git sie nur einmal als Blob. Alle Trees verweisen dann auf denselben Blob.
Blob mit git cat-file untersuchen
Lass uns das praktisch ausprobieren. Erstelle zunÀchst ein Test-Repository:
# Neues Repository erstellen
mkdir git-objekte-demo && cd git-objekte-demo
git init
# Eine einfache Datei erstellen
echo "Hallo Git-Welt!" > hallo.txt
git add hallo.txt
Mit git add wurde die Datei in die Staging Area aufgenommen â und dabei wurde ein Blob-Objekt erstellt. Finde den Hash heraus:
# Hash des Blobs anzeigen (aus dem Index/Staging Area)
git ls-files -s
Ausgabe:
100644 d6a96ae3b442218a91512b9e1c57b9578b8998e8 0 hallo.txt
Die Zahl 100644 sind die Dateiberechtigungen, d6a96ae... ist der SHA-1-Hash seinesdes InhaltsBlobs. identifiziert
wir den Blob untersuchen:
# Typ des Objekts anzeigen
git cat-file -t d6a96ae3b442218a91512b9e1c57b9578b8998e8
Ausgabe:
blob
# Inhalt des Blobs anzeigen
git cat-file -p d6a96ae3b442218a91512b9e1c57b9578b8998e8
Ausgabe:
Hallo Git-Welt!
# GröĂe des Blobs in Bytes
git cat-file -s d6a96ae3b442218a91512b9e1c57b9578b8998e8
Ausgabe:
16
đĄ Tipp: Du musst nicht den vollstĂ€ndigen Hash eingeben. Git akzeptiert auch eindeutige PrĂ€fixe, z.B.
git cat-file -p d6a96ae oder sogargit cat-file -p d6a96.
2. Tree â dieDas VerzeichnisstrukturVerzeichnis đł
Ein Tree reprĂ€sentiert ein Verzeichnis undin verknĂŒpftGit. Er ist quasi das âInhaltsverzeichnis", das Dateinamen mit Blobs oderverknĂŒpft. weiterenEin TreesTree (fĂŒrenthĂ€lt Unterverzeichnisse).eine ErListe fungiertvon alsEintrĂ€gen, âInhaltsverzeichnis"wobei eines Ordners zu einem bestimmten Zeitpunkt.
Jederjeder Eintrag inaus einemfolgenden TreeKomponenten enthÀlt:besteht:
Den DateimodusModus (Dateiberechtigungen, z.B.100644fĂŒr normale Dateien,100755Â fĂŒr ausfĂŒhrbare Dateien,040000fĂŒrVerzeichnisse)Unterverzeichnisse)DenObjekttyp (blobodertree)tree)DenSHA-1-Hash des referenzierten ObjektsDenNameDatei-der Datei oderVerzeichnisnamendes Unterverzeichnisses
Tree-Struktur visualisiert
flowchart TB
ROOT["Tree: Wurzelverzeichnis\na1b2c3d..."]
ROOT --> E1["100644 blob fa3c2...\nhallo.txt"]
ROOT --> E2["100644 blob 8b137...\nREADME.md"]
ROOT --> E3["040000 tree d4e5f...\nsrc/"]
SRC["Tree: src/\nd4e5f6g..."]
E3 -.-> SRC
SRC --> E4["100644 blob e69de...\nindex.php"]
SRC --> E5["100755 blob 12345...\nscript.sh"]
style ROOT fill:#fff3e0,color:#000000
style SRC fill:#fff3e0,color:#000000
style E1 fill:#e8f4e8,color:#000000
style E2 fill:#e8f4e8,color:#000000
style E3 fill:#fff3e0,color:#000000
style E4 fill:#e8f4e8,color:#000000
style E5 fill:#e8f4e8,color:#000000
Tree praktisch untersuchen
Erweitern wir unser Demo-Repository und erstellen einen Commit, damit wir Trees untersuchen können:
# Weitere Dateien und ein Verzeichnis erstellen
echo "# Mein Projekt" > README.md
mkdir src
echo "<?php echo 'Hello World';" > src/index.php
git add .
git commit -m "Erster Commit mit Projektstruktur"
Jetzt können wir den Tree des letzten Commits anschauen:
# Den Tree-Hash des letzten Commits finden
git cat-file -p HEAD
Ausgabe:
tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
author Max Mustermann <max@example.com> 1703847600 +0100
committer Max Mustermann <max@example.com> 1703847600 +0100
Erster Commit mit Projektstruktur
Den Tree-Hash (hier beginnt er mit 4b825dc..., dein Hash wird anders sein) können wir nun untersuchen:
# Tree-Inhalt anzeigen (ersetze den Hash durch deinen)
git cat-file -p 4b825dc642cb6eb9a060e54bf8d69288fbee4904
Ausgabe:
100644 blob d6a96ae3b442218a91512b9e1c57b9578b8998e8 hallo.txt
100644 blob 7e59600739c96546163833214c36459e324bad0a README.md
040000 tree 8f94139338f9404f26296befa88755fc2598c289 src
Du siehst: Der Tree enthÀlt Verweise auf zwei Blobs (die Dateien) und einen weiteren Tree (das src-Verzeichnis). Lass uns auch den Unter-Tree anschauen:
# Unter-Tree (src/) untersuchen
git cat-file -p 8f94139338f9404f26296befa88755fc2598c289
Ausgabe:
100644 blob 8b137891791fe96927ad78e64b0aad7bded08bdc index.php
Praktischer Shortcut mit git ls-tree
FĂŒr die Untersuchung von Trees gibt es auch den spezialisierten Befehl git ls-tree:
# Tree des aktuellen Commits rekursiv anzeigen
git ls-tree -r HEAD
Ausgabe:
100644 blob d6a96ae3b442218a91512b9e1c57b9578b8998e8 hallo.txt
100644 blob 7e59600739c96546163833214c36459e324bad0a README.md
100644 blob 8b137891791fe96927ad78e64b0aad7bded08bdc src/index.php
3. Commit â derDer Schnappschuss mit Geschichte đž
Ein Commit ist derdas zentraleHerzstĂŒck Objekttypvon fĂŒrGit. Er reprĂ€sentiert einen Schnappschuss deines gesamten Projekts zu einem bestimmten Zeitpunkt. Wichtig zu verstehen: Ein Commit speichert nicht die Versionskontrolle.Ănderungen Er(Diffs), referenziertsondern verweist auf einen TreeTree, (der den kompletten Zustand desaller gesamtenDateien Projekts) und enthĂ€lt Metadaten zur Ănderung.beschreibt.
Bestandteile eines Commits:
Commit-Objekts
tree
SHA-1-Hash des Root-parent
author
Name, E-Mail und Zeitstempel der Person, die die Ănderung ursprĂŒnglich erstellt committer
Name, E-Mail und Zeitstempel der Person, die den Commit Commit praktisch untersuchen
# Einen zweiten Commit erstellen
echo "Neue Zeile" >> hallo.txt
git add hallo.txt
git commit -m "hallo.txt erweitert"
# Die letzten beiden Commits anzeigen
git log --oneline -2
Ausgabe:
a7b3c9d (HEAD -> main) hallo.txt erweitert
f1e2d3c Erster Commit mit Projektstruktur
Jetzt untersuchen wir den neuesten Commit:
git cat-file -p HEAD
Ausgabe:
tree 9f8e7d6c5b4a3210fedcba9876543210abcdef12
parent f1e2d3c4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0
author Max Mustermann <max@example.com> 1703851200 +0100
committer Max Mustermann <max@example.com> 1703851200 +0100
hallo.txt erweitert
Du siehst hier den parent-Eintrag, der auf den vorherigen Commit verweist. Diese Verkettung durch Parent-Referenzen bildet die Commit-Historie â eine einfach verkettete Liste (oder bei Merges: ein gerichteter azyklischer Graph).
Die Commit-NachrichtKette visualisiert
flowchart RL
C3["Commit C3\na7b3c9d\n\nhallo.txt erweitert"]
C2["Commit C2\nf1e2d3c\n\nErster Commit"]
C1["Commit C1\n0a1b2c3\n\nInitial commit"]
C3 -->|parent| C2
C2 -->|parent| C1
HEAD["HEAD"]
MAIN["main"]
HEAD -.-> MAIN
MAIN -.-> C3
style C3 fill:#e3f2fd,color:#000000
style C2 fill:#e3f2fd,color:#000000
style C1 fill:#e3f2fd,color:#000000
style HEAD fill:#ffecb3,color:#000000
style MAIN fill:#c8e6c9,color:#000000
Merge-Commits haben mehrere Parents
Bei einem Merge-Commit gibt es mehrere parent-EintrÀge:
# Beispiel eines Merge-Commits (nach einem Merge erstellt)
git cat-file -p <merge-commit-hash>
Ausgabe:
tree 1234567890abcdef...
parent aaaaaaa111111... <-- erster Parent (der Branch, IN den gemerged wurde)
parent bbbbbbb222222... <-- zweiter Parent (der Branch, DER gemerged wurde)
author Max Mustermann <max@example.com> 1703854800 +0100
committer Max Mustermann <max@example.com> 1703854800 +0100
Merge branch 'feature/login'
4. Tag â derDie benannte MeilensteinMarkierung đ·ïž
Ein annotiertes Tag ist ein eigenstĂ€ndigesbenannter Objekt, dasZeiger auf einen bestimmten Commit zeigtâ typischerweise verwendet fĂŒr Release-Versionen wie v1.0.0 oder v2.3.1. Git kennt zwei Arten von Tags:
Lightweight Tags vs. Annotated Tags
.git/refs/tags/
Eigenes Tag-Objekt in .git/objects/
Metadaten
Keine
Tagger, Datum, Nachricht
GPG-Signatur
Nicht möglich
Möglich
Empfehlung
FĂŒr temporĂ€re/lokale Markierungen
FĂŒr Releases und Annotated zurTag Markierung von Releases.
Bestandteile:
# Tag-NachrichtAnnotated Tag erstellen
đĄHinweis: Sogenanntelightweight Tags sind keine eigenen Objekte, sondern nur Referenzen (wie Branches). Nurannotierte Tags (git tag -a v1.0.0 -m "Erste stabile Version" # Tag-Objekt untersuchen git cat-file -t v1.0.0
Ausgabe:
tag
git cat-file -p v1.0.0
Ausgabe:
object a7b3c9d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0
type commit
tag v1.0.0
tagger Max Mustermann <max@example.com> 1703858400 +0100
Erste stabile Version
Das Tag-Objekt enthÀlt:
commit)
Lightweight Tag zum Vergleich
# Lightweight Tag erstellen
git tag v1.0.0-beta
# Typ prĂŒfen - zeigt direkt auf den Commit!
git cat-file -t v1.0.0-beta
Ausgabe:
commit
Ein Lightweight Tag ist kein eigenes Objekt, sondern nur eine Referenz-Datei. Wenn du git cat-file -p v1.0.0-beta ausfĂŒhrst, siehst du direkt den Commit-Inhalt, nicht ein Tag-Objekt.
Wie diealles ObjektezusammenhĂ€ngt zusammenhĂ€ngenđ
DieJetzt, Objektewo bildendu einenalle gerichtetenvier azyklischenObjekttypen Graphenkennst, (DAG),lass inuns demdas jedesgroĂe ObjektGanze aufbetrachten. andereEin verweist:typisches Git-Repository mit zwei Commits könnte intern so aussehen:
flowchart TB
subgraph CommitsReferenzen
C1[HEAD["CommitHEAD\nâ abc123\nInitialrefs/heads/main"]
commit"MAIN["refs/heads/main\nâ commit 2"]
TAG["refs/tags/v1.0.0\nâ tag-objekt"]
end
subgraph Objekte
TAGO["Tag-Objekt\nv1.0.0\nâ commit 2"]
C2["Commit def456\nAdd2\ntree: feature"T2\nparent: C1"]
end
subgraph Trees
T1[C1["TreeCommit 1\nRoot-Verzeichnis"ntree: T1\nparent: keine"]
T2["Tree 2\nRoot-Verzeichnis"T2\nhallo.txt â B2\nREADME.md â B3\nsrc/ â T3"]
T1["Tree T1\nhallo.txt â B1\nREADME.md â B3"]
T3["Tree 3\nUnterordnerT3\nindex.php src"â B4"]
B1["Blob B1\nHallo Git-Welt!"]
B2["Blob B2\nHallo Git-Welt!\nNeue Zeile"]
B3["Blob B3\n# Mein Projekt"]
B4["Blob B4\nPHP-Code..."]
end
subgraphHEAD Blobs-.-> B1["Blob\nREADME.md"]MAIN
B2["Blob\nindex.js"]MAIN B3["Blob\napp.js"]-.-> end
subgraph Tags
TAG["Tag v1.0.0"]
endC2
TAGÂ -.-> TAGO
TAGO --> C2
C2 --> C1T2
C2 -->|parent| T2C1
C1 --> T1
T1T2 --> B1B2
T2 --> B1B3
T2 --> T3
T3T1 --> B2B1
T1 --> B3
T3 --> B3B4
style HEAD fill:#ffecb3,color:#000000
style MAIN fill:#c8e6c9,color:#000000
style TAG fill:#e1bee7,#c8e6c9,color:#000000
style TAGO fill:#fce4ec,color:#000000
style C1 fill:#bbdefb,#e3f2fd,color:#000000
style C2 fill:#bbdefb,#e3f2fd,color:#000000
style T1 fill:#c8e6c9,#fff3e0,color:#000000
style T2 fill:#c8e6c9,#fff3e0,color:#000000
style T3 fill:#c8e6c9,#fff3e0,color:#000000
style B1 fill:#fff9c4,#e8f4e8,color:#000000
style B2 fill:#fff9c4,#e8f4e8,color:#000000
style B3 fill:#fff9c4,#e8f4e8,color:#000000
style B4 fill:#e8f4e8,color:#000000
WichtigeBeachte ZusammenhÀnge:
README.md ObjekteDie inspizieren mitwichtigsten git cat-file-Optionen đim Ăberblick
Das Kommando git cat-file ist dein Werkzeug, um âunter die Haube" zu schauen. Es hat mehrere nĂŒtzliche Optionen:
| Option | Beschreibung |
|---|
-t
Zeigt den Typ des Objekts
git cat-file -t HEADÂ â commit
-p
Pretty-Print: Zeigt den Inhalt formatiert an
git cat-file -p HEAD
-s
Zeigt die GröĂe in Bytes
git cat-file -s HEAD
-pe
git cat-file -e abc123
PraktischeNĂŒtzliche BeispieleKombinationen und Shortcuts
# Alle Objekte im Repository auflisten
find .git/objects -type f | head -20
# Typ und GröĂe aller Objekte eines ObjektsCommits ermitteln:
git rev-list --objects HEAD | while read hash name; do
echo "$hash $(git cat-file -t HEAD$hash) Ausgabe:
commit
Einen Commit inspizieren:
$(git cat-file -ps HEAD$hash) $name"
Ausgabe:
tree# 4b825dc642cb6eb9a060e54bf8d69288fbee4904Direkter parentZugriff 8a7b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b
author Max Mustermann <max@example.de> 1719670258 +0200
committer Max Mustermann <max@example.de> 1719670258 +0200
Implement user authentication
Denauf Tree eines Commits anschauen:
ZunÀchst den Tree-Hash aus dem Commit extrahieren, dann:
git cat-file -p 4b825dc642cb6eb9a060e54bf8d69288fbee4904
Ausgabe:
100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad README.md
100644 blob a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0 package.json
040000 tree 9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e src
Einen Blob (Dateiinhalt) lesen:
git cat-file -p 3b18e512dba79e4c8300dd08aeb37f8e728b8dad
Ausgabe:
# Mein Projekt
Dies ist die README-Datei des Projekts.
Ein annotiertes Tag inspizieren:
git cat-file -p v1.0.0
Ausgabe:
object 8a7b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b
type commit
tag v1.0.0
tagger Max Mustermann <max@example.de> 1719670258 +0200
Release version 1.0.0 - Production ready
NĂŒtzliche AbkĂŒrzungen
Du musst nicht immer den vollstÀndigen SHA-1-Hash angeben:
# Die ersten 7 Zeichen reichen meist
git cat-file -p abc1234
# HEAD und andere Referenzen funktionieren
git cat-file -p HEAD
git cat-file -p main
git cat-file -p v1.0.0
# Der Tree des aktuellen Commits
git cat-file -p HEAD^{tree}
# EineDirekter bestimmteZugriff auf eine Datei imin aktuelleneinem Commit
git cat-file -p HEAD:src/index.jsphp
WoPraktische liegenĂbung diesezum Objekte?Selbermachen đđŻ
AlleUm Objektedas werdenGelernte imzu Verzeichnisfestigen, probiere .git/objects/gespeichert.Folgendes Diein ersteneinem zwei Zeichen des Hashes bilden einen Unterordner, der Rest ist der Dateiname:Test-Repository:
.git/objects/DieErstelle ein neues Repository mit einigen Dateien sindund Unterverzeichnissen
Finde die Blob-Hashes deiner Dateien mit git ls-files -s
zlibUntersuche komprimiertden Tree âdeines deshalbletzten kannstCommits du sie nicht direkt lesen, sondern brauchstmit git cat-file -p HEAD^{tree}.
đŻVergleiche zwei Commits: Erstelle eine kleine Ănderung, committe sie, und vergleiche die Tree-Hashes beider Commits. Welche Blobs haben sich geĂ€ndert, welche sind gleich geblieben?
Tipp:Erstelle einen Annotated Tag und untersuche sein Objekt
Mit ĂŒber gitdiesem count-objectsWissen -vsiehstGit-Interna du,bist du bestens vorbereitet fĂŒr die fortgeschrittenen Themen wie vieleRebase, Objekte dein Repository enthĂ€ltReflog und wieTroubleshooting vielâ Speicherplatzdenn siedu belegen.verstehst jetzt, was Git eigentlich tut, wenn du diese Befehle ausfĂŒhrst! đ