Schnelleres Klonen großer Historien
Ein vollständiger git clone überträgt jede Version jeder Datei aus der gesamten Historie, auch wenn nur der aktuelle Stand benötigt wird. Partial Clone und Shallow Clone reduzieren die übertragene Datenmenge auf unterschiedliche Weise und eignen sich für unterschiedliche Einsatzszenarien, von CI Runnern bis zu Entwicklerarbeitsplätzen.
Inhaltsverzeichnis
- 1. Warum große Historien beim Klonen zum Problem werden
- 2. Shallow Clone: Historie auf wenige Commits begrenzen
- 3. Partial Clone: Objekte statt Commits filtern
- 4. Filter Varianten im Detail: blob:none, blob:limit und tree:0
- 5. Wie fehlende Objekte im Hintergrund nachgeladen werden
- 6. Partial Clone und Shallow Clone in CI Pipelines
- 7. Partial Clone in Kombination mit Submodulen
- 8. Best Practices für die Wahl der richtigen Strategie
- 9. Typische Fallstricke bei flachen und partiellen Klonen
- 10. Zusammenfassung
- 11. FAQ
1. Warum große Historien beim Klonen zum Problem werden
Ein Repository mit zehn Jahren Historie, tausenden Commits und großen Binärdateien kann problemlos mehrere Gigabyte an Objektdaten ansammeln, selbst wenn der aktuelle Stand des Codes vergleichsweise klein ist. Ein Standard git clone lädt jedoch grundsätzlich alle Commits, alle Baum Objekte und alle Blob Objekte jeder jemals committeten Datei herunter, unabhängig davon, ob sie für die aktuelle Arbeit relevant sind.
Für CI Pipelines, die pro Lauf ein frisches Repository klonen, summiert sich diese unnötige Datenmenge schnell zu spürbaren Zeit und Kostenfaktoren. Auch Entwickler, die nur am aktuellen Stand arbeiten wollen und selten in die Historie zurückgehen, profitieren davon, wenn Git nicht jede jemals existierende Version jeder Datei vorab herunterladen muss.
2. Shallow Clone: Historie auf wenige Commits begrenzen
Shallow Clone begrenzt die Anzahl der übertragenen Commits über das Flag --depth. Statt der kompletten Historie erhält der Client nur die letzten n Commits jedes geklonten Branches, dargestellt durch spezielle Grenz Commits, die Git als shallow markiert und deren Elternbeziehung im lokalen Repository nicht weiter aufgelöst wird.
Der große Vorteil ist die Einfachheit: Ein --depth=1 Clone lädt praktisch nur den aktuellen Snapshot, was für CI Builds, die lediglich den aktuellen Stand kompilieren oder testen müssen, ideal ist. Der Nachteil zeigt sich, sobald Historie gebraucht wird, etwa bei git blame, git log über ältere Commits oder einem git bisect, die in einer flachen Historie nur eingeschränkt funktionieren.
# Nur den letzten Commit jedes Branches herunterladen
git clone --depth=1 https://git.example.com/repo.git
# Nachträglich zusätzliche Historie nachladen
git fetch --deepen=50
# Vollständige Historie nachträglich wiederherstellen
git fetch --unshallow
3. Partial Clone: Objekte statt Commits filtern
Partial Clone verfolgt einen anderen Ansatz als Shallow Clone: Statt die Anzahl der Commits zu begrenzen, bleibt die vollständige Commit Historie und Baumstruktur erhalten, aber bestimmte Objekttypen, meist große Blob Objekte, werden erst bei Bedarf nachgeladen. Damit funktionieren Befehle wie git log sofort vollständig, während der tatsächliche Dateiinhalt für ältere Commits erst beim Zugriff vom Server angefordert wird.
Möglich wird das durch das --filter Flag, das seit Git 2.19 existiert und dem Server mitteilt, welche Objekttypen beim initialen Clone weggelassen werden dürfen. Der Server muss dafür Partial Clone unterstützen, was bei modernen Hosting Anbietern wie GitHub, GitLab und selbst gehosteten Git Servern mit aktueller Version standardmäßig der Fall ist.
# Alle Blob Objekte erst bei Bedarf nachladen, Historie bleibt vollständig
git clone --filter=blob:none https://git.example.com/repo.git
# Zusätzlich auch Baum Objekte jenseits der Wurzel erst bei Bedarf laden
git clone --filter=tree:0 https://git.example.com/repo.git
4. Filter Varianten im Detail: blob:none, blob:limit und tree:0
Der Filter blob:none ist der gebräuchlichste: Er lädt keinerlei Dateiinhalte vor, sondern nur Commits und Baumstruktur, und lädt jeden Blob genau dann nach, wenn ein Checkout oder git show ihn tatsächlich benötigt. Der Filter blob:limit=1m ist ein Kompromiss, der kleine Dateien sofort überträgt, aber große Blobs oberhalb der angegebenen Größe auslagert, was sich für Repositories mit wenigen sehr großen Assets eignet.
Der Filter tree:0 geht noch einen Schritt weiter und lädt auch Baum Objekte für Verzeichnisse jenseits der Wurzel erst on demand. Kombiniert mit Sparse Checkout ergibt sich daraus die minimalste Datenübertragung überhaupt, weil weder Baum noch Blob Objekte für Verzeichnisse geladen werden, die im Sparse Profil ohnehin nicht sichtbar sind.
# Kleine Dateien sofort laden, große Blobs erst bei Bedarf
git clone --filter=blob:limit=1m https://git.example.com/repo.git
# Partial Clone und Sparse Checkout für minimale Datenübertragung kombinieren
git clone --filter=blob:none --sparse https://git.example.com/monorepo.git
5. Wie fehlende Objekte im Hintergrund nachgeladen werden
Sobald ein Befehl wie git checkout, git log -p oder git blame auf ein noch nicht lokal vorhandenes Objekt trifft, fragt Git es automatisch beim sogenannten Promisor Remote nach, also dem Server, der beim Clone als Quelle für nachträglich benötigte Objekte hinterlegt wurde. Dieser Vorgang läuft transparent ab, ist aber netzwerkabhängig und kann bei langsamer Verbindung einzelne Befehle spürbar verlangsamen.
Für Operationen, die viele historische Objekte auf einmal anfordern, etwa ein vollständiges git log -p über die gesamte Historie, kann das Nachladen viele einzelne Serveranfragen auslösen. In solchen Fällen empfiehlt sich ein gezieltes git fetch --filter=blob:none --unshallow oder das bewusste Nachladen mit git backfill, sofern die Git Version dieses seit 2.30 verfügbare Kommando bereits unterstützt.
# Prüfen, welche Objekte lokal fehlen und als Promisor markiert sind
git rev-list --objects --all --missing=print | head
# Fehlende Blob Objekte für den aktuellen Branch gezielt nachladen
git backfill
6. Partial Clone und Shallow Clone in CI Pipelines
In CI Pipelines ist die richtige Wahl stark vom Job Typ abhängig: Ein Job, der nur den aktuellen Stand baut und testet, profitiert am meisten von --depth=1, weil dort schlicht keine Historie benötigt wird. Ein Job, der Changed Files gegenüber einem Ziel Branch ermitteln muss, braucht dagegen zumindest die gemeinsame Historie beider Branches und scheitert mit einem zu flachen Clone an fehlenden Merge Base Commits.
Für solche Fälle liefert Partial Clone oft das bessere Verhältnis, weil die vollständige Commit Historie erhalten bleibt und nur die teuren Blob Objekte eingespart werden. Viele CI Systeme unterstützen mittlerweile GIT_CLONE_FILTER Umgebungsvariablen oder entsprechende Pipeline Optionen, um Partial Clone projektweit als Standard zu setzen.
# Beispiel für eine CI Konfiguration mit Partial Clone
variables:
GIT_STRATEGY: clone
GIT_CLONE_FILTER: "blob:none"
GIT_DEPTH: "0"
7. Partial Clone in Kombination mit Submodulen
Partial Clone wirkt zunächst nur auf das Hauptrepository, während eingebundene Submodule standardmäßig vollständig geklont werden, sobald sie initialisiert werden. Wer ein Repository mit vielen großen Submodulen klont, verliert dadurch schnell wieder den Geschwindigkeitsvorteil, den Partial Clone für das Hauptrepository eigentlich bringen sollte, weil jeder Submodule Checkout erneut die vollständige Objektmenge des jeweiligen Submodule Repositories herunterlädt.
Seit Git 2.36 lässt sich der Filter mit dem Flag --also-filter-submodules automatisch auch auf rekursiv initialisierte Submodule anwenden, sodass Blob Objekte in Submodulen ebenso erst bei Bedarf nachgeladen werden wie im Hauptrepository. In älteren Git Versionen muss der Filter für jedes Submodule manuell mit git submodule update --init --filter=blob:none angewendet werden, was in Skripten für die Erstkonfiguration eines Arbeitsplatzes explizit berücksichtigt werden sollte.
# Partial Clone Filter automatisch auch auf Submodule anwenden
git clone --filter=blob:none --also-filter-submodules --recurse-submodules https://git.example.com/repo.git
# Ältere Git Version: Filter manuell pro Submodule anwenden
git submodule update --init --filter=blob:none
8. Best Practices für die Wahl der richtigen Strategie
Als Faustregel gilt: --depth=1 für isolierte Build und Test Jobs ohne Historienbedarf, --filter=blob:none für alles, was Historie braucht, aber nicht jede Datei in jeder Version. Entwicklerarbeitsplätze sollten in der Regel Partial Clone statt Shallow Clone verwenden, weil sie oft doch einmal git blame oder ältere Commits brauchen und ein nachträgliches --unshallow teurer ist als das transparente Nachladen einzelner Blobs.
Große Binärdateien gehören unabhängig von Partial Clone in ein dediziertes System wie Git LFS, weil Partial Clone die Blobs zwar verzögert lädt, sie beim tatsächlichen Zugriff aber weiterhin vollständig in die lokale Objektdatenbank überträgt und dort dauerhaft speichert.
9. Typische Fallstricke bei flachen und partiellen Klonen
Ein häufiger Fehler ist der Versuch, in einem Shallow Clone einen Branch zu pushen, der auf einem nicht vorhandenen Grenz Commit basiert, was Git mit einer Fehlermeldung über fehlende Vorfahren quittiert. Ebenso scheitern viele CI Tools, die Merge Base Berechnungen für Diff Ansichten benötigen, an zu flachen Klonen, weil der gemeinsame Vorfahre zweier Branches außerhalb der geladenen Tiefe liegt.
Bei Partial Clone ist die Falle subtiler: Wer offline arbeitet oder der Promisor Remote nicht mehr erreichbar ist, kann plötzlich auf einen Fehler stoßen, sobald ein noch nicht lokal vorhandenes Objekt benötigt wird. Vor längeren Offline Phasen empfiehlt sich deshalb ein gezieltes git backfill oder ein vollständiger --unshallow beziehungsweise Filter Reset.
| Strategie | Was wird begrenzt | Historie verfügbar | Typischer Einsatz |
|---|---|---|---|
| Shallow Clone --depth=1 | Anzahl der Commits | Nur letzter Commit pro Branch | Isolierte CI Build und Test Jobs |
| Partial Clone --filter=blob:none | Dateiinhalte, Blobs | Vollständig, Blobs on demand | Entwicklerarbeitsplätze, Diff Jobs |
| Partial Clone --filter=tree:0 | Dateiinhalte und Verzeichnisstruktur | Vollständig, Bäume on demand | Kombination mit Sparse Checkout |
| Vollständiger Clone | Nichts | Vollständig, sofort lokal | Langfristige Offline Arbeit, Archivierung |
Mironsoft
Git-Workflows, Branching-Strategien und CI-Hooks
Chaotische Git-Historie und unklare Branching-Regeln im Team?
Wir richten saubere Git-Workflows ein, klären Branching-Strategien fürs Team und automatisieren Qualitätschecks über Git-Hooks und CI-Pipelines, damit die Historie nachvollziehbar bleibt.
Workflow-Audit
Bestehende Branching-Strategie und Merge-Praxis auf Schwachstellen prüfen.
Hook-Automatisierung
Pre-Commit- und Pre-Push-Hooks für Linting, Tests und Commit-Konventionen einrichten.
Team-Schulung
Rebase, Cherry-Pick und Konfliktauflösung im Team praxisnah vermitteln.
10. Zusammenfassung
Partial und Shallow Clone
Shallow Clone
Begrenzt Commit Anzahl, Historie unvollständig
Partial Clone
Historie vollständig, Blobs werden on demand geladen
Kernbefehl
git clone --filter=blob:none
CI Faustregel
depth=1 ohne Historienbedarf, sonst Partial Clone