Grosse Dateien sinnvoll versionieren
Wer PSD-Dateien, Videos oder Archive direkt in Git committet, bläht die Repository-Grösse und die Clone-Zeit für das ganze Team unnötig auf, weil Gits Delta-Kompression bei Binärdaten kaum greift. Git LFS ersetzt diese Dateien durch schlanke Pointer und lagert die eigentlichen Inhalte extern, ohne dass sich am gewohnten Commit- und Push-Workflow etwas ändert.
Inhaltsverzeichnis
- 1. Warum Git bei grossen Binärdateien an seine Grenzen stösst
- 2. Wie Git LFS technisch funktioniert: Pointer-Dateien und Smudge/Clean-Filter
- 3. Installation und Ersteinrichtung von Git LFS
- 4. Dateitypen tracken mit git lfs track und .gitattributes
- 5. Der Workflow im Alltag: Commit, Push, Clone mit LFS
- 6. Bestehende grosse Dateien nachträglich migrieren mit git lfs migrate
- 7. Grenzen und Stolperfallen von Git LFS
- 8. Alternativen und Ergänzungen zu Git LFS
- 9. Git LFS im Vergleich: Patterns richtig vs. falsch angewendet
- 10. Zusammenfassung
- 11. FAQ
1. Warum Git bei grossen Binärdateien an seine Grenzen stösst
Gits Speichermodell ist für Quelltext optimiert. Bei jedem Commit berechnet Git intern Deltas zwischen Textzeilen und speichert Objekte hochkomprimiert, weil sich Textänderungen zeilenweise gut vergleichen lassen. Bei einer PSD-Datei, einem Video oder einem ZIP-Archiv funktioniert diese Diff-Logik praktisch nicht: Schon eine einzelne geänderte Pixelzeile oder ein neu berechneter Kompressions-Header führt dazu, dass die komplette Binärdatei als neues, vollständiges Objekt in die Historie geschrieben wird. Es gibt keine sinnvolle Zeilenstruktur, an der Git ansetzen könnte.
Die Folge summiert sich schnell: Fünfzig Versionen einer 100-Megabyte-Design-Datei bedeuten fünf Gigabyte reine Historiendaten, selbst wenn im Arbeitsverzeichnis nur die aktuelle Version sichtbar ist. Da Git-Historie standardmässig unveränderlich ist, bleibt jede jemals committete Version für immer im Repository, auch nach dem Löschen der Datei im aktuellen Stand. Jeder git clone lädt diese gesamte Historie herunter, was Onboarding neuer Teammitglieder, CI-Pipelines und einfache Backups spürbar verlangsamt und den verfügbaren Speicherplatz auf Git-Hosting-Plattformen unnötig belastet.
2. Wie Git LFS technisch funktioniert: Pointer-Dateien und Smudge/Clean-Filter
Git LFS (Large File Storage) löst dieses Problem, indem es den eigentlichen Binärinhalt nicht mehr im Git-Objektspeicher ablegt, sondern durch eine winzige Pointer-Datei ersetzt. Diese Textdatei landet an derselben Stelle in der Git-Historie wie zuvor die Binärdatei, ist aber nur wenige Bytes gross und enthält lediglich Versionsangabe, den SHA-256-Hash des Inhalts (oid) und dessen Dateigrösse. Der tatsächliche Binärinhalt wird stattdessen auf einem separaten LFS-Server gespeichert, den GitHub, GitLab oder eine selbst betriebene Instanz bereitstellen.
Damit dieser Austausch transparent bleibt, registriert Git LFS zwei Git-Filter: den clean filter, der beim git add/git commit die Binärdatei durch ihre Pointer-Repräsentation ersetzt und den Inhalt in einen lokalen LFS-Cache sowie beim Push zum Server hochlädt, und den smudge filter, der beim Checkout die umgekehrte Richtung übernimmt und die Pointer-Datei automatisch wieder durch den echten Binärinhalt ersetzt. Für Entwickler ist dieser Mechanismus unsichtbar: Im Arbeitsverzeichnis erscheint immer die vollständige Datei, während Git selbst nur die schlanke Pointer-Version verwaltet.
# What actually gets stored in the Git history instead of the binary blob:
cat assets/hero-banner.psd
# version https://git-lfs.github.com/spec/v1
# oid sha256:4d7a2c8e9f1b3a6d5c8e0f2a1b4c7d9e6f3a2b5c8d1e4f7a0b3c6d9e2f5a8b1c
# size 157286400
# Locally, "git lfs" resolves the pointer back into the real file
git lfs pointer --file=assets/hero-banner.psd
3. Installation und Ersteinrichtung von Git LFS
Git LFS ist kein Bestandteil von Git selbst, sondern ein separates Client-Tool, das zusätzlich installiert werden muss, etwa über apt install git-lfs, brew install git-lfs oder das offizielle Installationspaket. Nach der Installation aktiviert git lfs install die notwendigen Git-Filter global im Nutzerprofil, sodass jedes neu geklonte oder initialisierte Repository auf dieser Maschine die filter=lfs-Direktiven aus .gitattributes automatisch erkennt und anwendet. Dieser Schritt muss pro Maschine nur einmal ausgeführt werden, nicht pro Repository.
Für Fälle, in denen die globalen Filter bewusst nicht gesetzt werden sollen, etwa auf einem CI-Runner mit eingeschränkten Rechten, existiert git lfs install --local, das die Filter nur in der lokalen .git/config des aktuellen Repositories registriert. git lfs version bestätigt, dass sowohl die LFS-Erweiterung als auch die zugrunde liegende Git-Version kompatibel sind, was insbesondere bei älteren CI-Images regelmässig zu Fehlern führt, wenn die Version stillschweigend fehlt.
# Install the git-lfs client (once per operating system / package manager)
sudo apt-get install git-lfs # Debian/Ubuntu
brew install git-lfs # macOS
# Register the Git filters globally for this user account, once per machine
git lfs install
# Register the filters only for the current repository (e.g. restricted CI runner)
git lfs install --local
# Verify the installed client and Git compatibility
git lfs version
4. Dateitypen tracken mit git lfs track und .gitattributes
Welche Dateien über LFS verwaltet werden, legt git lfs track fest. Der Befehl git lfs track "*.psd" schreibt eine entsprechende Zeile mit den Attributen filter=lfs diff=lfs merge=lfs -text in die Datei .gitattributes im Repository-Root. Diese Attribute weisen Git an, für passende Dateien die LFS-Filter zu verwenden und sie als Binärdaten zu behandeln, ohne Zeilenenden zu normalisieren. Patterns lassen sich beliebig kombinieren, etwa für ganze Verzeichnisse mit assets/videos/**/*.mp4 oder für mehrere Dateitypen gleichzeitig in separaten track-Aufrufen.
Der entscheidende, oft übersehene Schritt: Die .gitattributes-Datei selbst muss ganz normal mit git add .gitattributes und git commit versioniert werden. Nur so greifen dieselben Tracking-Regeln bei jedem Teammitglied, das das Repository klont. Wird die Datei vergessen, legt zwar der ursprüngliche Autor seine Dateien korrekt über LFS ab, jeder andere Klon behandelt neue Binärdateien desselben Typs aber wieder als gewöhnliche, direkt in der Historie gespeicherte Blobs.
# .gitattributes - generated and extended via "git lfs track"
*.psd filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text
assets/videos/**/*.mov filter=lfs diff=lfs merge=lfs -text
# List every pattern currently tracked by Git LFS in this repository
# git lfs track
5. Der Workflow im Alltag: Commit, Push, Clone mit LFS
Nach der Ersteinrichtung ändert sich am gewohnten Ablauf mit git add, git commit und git push nichts sichtbar. Im Hintergrund erkennt Git anhand der .gitattributes-Regeln automatisch, welche Dateien über LFS laufen, ersetzt sie beim Commit durch Pointer und lädt die eigentlichen Inhalte beim Push separat zum LFS-Endpunkt hoch. git lfs ls-files zeigt zuverlässig, welche Dateien im aktuellen Commit tatsächlich als LFS-Objekte verwaltet werden, während git lfs status zusätzlich anzeigt, ob lokale LFS-Dateien bereits hochgeladen wurden oder noch ausstehen.
Beim Klonen lädt Git standardmässig nur die Pointer-Dateien sofort mit herunter; die zugehörigen Binärinhalte werden erst beim Checkout über den Smudge-Filter nachgezogen, was den initialen git clone spürbar beschleunigt. Wichtig für die Praxis: GitHub und GitLab begrenzen LFS-Speicher und -Bandbreite getrennt vom regulären Repository-Kontingent, mit vergleichsweise kleinen kostenlosen Freikontingenten, die bei aktiven Design- oder Video-Repositories schnell ausgeschöpft sind und dann kostenpflichtige Erweiterungen erfordern.
# Clone downloads pointers immediately, binary content follows on checkout
git clone https://git.example.com/team/shop.git
# List which files in the current commit are actually managed as LFS objects
git lfs ls-files
# 4d7a2c8e * assets/hero-banner.psd
# 9b3f1e0a * assets/videos/teaser.mp4
# Show which LFS files are staged, modified, or still pending upload
git lfs status
6. Bestehende grosse Dateien nachträglich migrieren mit git lfs migrate
Tracking-Regeln über git lfs track wirken nur auf künftige Commits. Binärdateien, die bereits vor der LFS-Einführung in die Historie eingecheckt wurden, bleiben davon unberührt und blähen das Repository weiterhin auf. Für diesen Fall existiert git lfs migrate import, das die gesamte Commit-Historie durchläuft, alle passenden Blobs extrahiert, sie durch Pointer-Dateien ersetzt und die betroffenen Commits neu schreibt. Mit --include="*.psd" --everything lässt sich die Migration gezielt auf bestimmte Dateitypen über alle Branches hinweg anwenden.
Weil dabei jeder betroffene Commit eine neue Prüfsumme erhält, ändert sich effektiv die gesamte nachfolgende Historie, und ein einfaches git push reicht danach nicht mehr aus, sondern erfordert git push --force-with-lease. Vor einer solchen Migration ist ein vollständiges Backup des Repositories Pflicht, da der Vorgang destruktiv ist und sich nicht ohne Weiteres rückgängig machen lässt. Genauso wichtig ist die Koordination im Team: Alle Mitarbeitenden müssen nach dem Force-Push ihre lokalen Kopien neu klonen oder ihre Branches gezielt auf den neuen Verlauf umbasieren, sonst entstehen doppelte, widersprüchliche Historien.
# Always create a full backup/mirror before rewriting history
git clone --mirror https://git.example.com/team/shop.git shop-backup.git
# Rewrite history: replace already-committed .psd files with LFS pointers
git lfs migrate import --include="*.psd" --everything
# Push the rewritten history; regular push is rejected due to changed hashes
git push --force-with-lease origin --all
git push --force-with-lease origin --tags
# Every teammate must re-clone or reset onto the rewritten history
# git fetch origin && git reset --hard origin/main
7. Grenzen und Stolperfallen von Git LFS
Git LFS verschiebt das Speicherproblem, statt es vollständig aufzulösen: Auf gängigen Hosting-Plattformen wird LFS-Speicher und -Bandbreite separat abgerechnet und ist bereits im Basis-Plan oft knapp bemessen. Bei grossen Asset-Bibliotheken mit häufigen Änderungen können diese Kosten schnell steigen, insbesondere weil jede neue Version einer Binärdatei als vollständig neues LFS-Objekt gespeichert wird und keine Delta-Kompression zwischen Versionen stattfindet. Ausserdem hilft LFS nur dort, wo es aktiv eingerichtet wurde: Ohne eine nachträgliche Migration bleiben historisch bereits committete Binärdateien unverändert im normalen Git-Objektspeicher liegen.
Wer LFS nicht bei einem grossen Hosting-Anbieter, sondern selbst betreiben möchte, kann auf einen eigenen LFS-Server setzen; viele selbstgehostete Git-Plattformen wie GitLab CE oder Gitea bringen LFS-Unterstützung bereits eingebaut mit. Als leichtgewichtige Ergänzung, wenn eine vollständige LFS-Infrastruktur nicht gewünscht ist, eignet sich ausserdem Partial Clone (git clone --filter=blob:none), das grosse Blobs erst bei tatsächlichem Zugriff nachlädt, ohne dass dafür ein separater LFS-Server nötig wäre.
8. Alternativen und Ergänzungen zu Git LFS
git-annex verfolgt einen ähnlichen Grundgedanken wie Git LFS, ist aber deutlich flexibler und komplexer: Es unterstützt beliebige Speicher-Backends, verschlüsselte Remotes und feingranulare Kontrolle darüber, welche Dateien lokal tatsächlich vorliegen. Für Teams, die primär ein einfaches, weit verbreitetes Tool suchen, ist der zusätzliche Lernaufwand meist nicht gerechtfertigt. Eine andere Ergänzung sind Git-Submodule, mit denen grosse Asset-Sammlungen in ein eigenes Repository ausgelagert und nur bei Bedarf eingebunden werden, sowie DVC (Data Version Control), das speziell für ML-Datensätze und -Pipelines entwickelt wurde und Versionierung mit Experiment-Tracking kombiniert.
Ebenso wichtig ist die Frage, wann LFS die falsche Antwort ist. Generierte oder importierte Medien, etwa Magento-Produktbilder in pub/media/, gehören grundsätzlich gar nicht in ein Git-Repository, unabhängig davon, ob mit oder ohne LFS. Solche Assets werden über Datenbank-Importe, S3-Buckets oder CDN-Deployments verwaltet, während Git für Quellcode und klar abgegrenzte, versionierungswürdige Design-Assets reserviert bleibt. Git LFS ist ein Werkzeug für Dateien, die tatsächlich Teil der Entwicklungshistorie sein sollen, nicht ein generischer Ersatz für Asset-Storage.
9. Git LFS im Vergleich: Patterns richtig vs. falsch angewendet
Die meisten Probleme mit Git LFS lassen sich auf wenige wiederkehrende Szenarien zurückführen, die sich durch den richtigen Ansatz jeweils vollständig vermeiden lassen. Die folgende Übersicht stellt typische Fehlentscheidungen der empfohlenen Strategie gegenüber.
| Aufgabe | Falsch | Richtiges Pattern | Vorteil |
|---|---|---|---|
| Binärdateien einbinden, die schon committet sind | Nur git lfs track ausführen |
git lfs migrate import --everything |
Historie wird tatsächlich verkleinert |
| Tracking-Regeln teamweit teilen | .gitattributes lokal belassen | .gitattributes committen und pushen | Gleiche Regeln bei jedem Klon |
| Historie nach Migration verteilen | Normaler git push |
git push --force-with-lease + Team-Ankündigung |
Keine widersprüchlichen Historien |
| Gemischte Assets im selben Repo | Manche PSDs getrackt, andere nicht | Ein Pattern pro Dateityp, konsequent | Vorhersagbares Repository-Verhalten |
| Speicher- und Bandbreitenkosten planen | Quotas erst bei Fehlermeldung prüfen | LFS-Nutzung vorab im Hosting-Dashboard abschätzen | Keine blockierten Pushes im Sprint |
Die Tabelle zeigt ein durchgängiges Muster: Git LFS funktioniert zuverlässig, sobald Tracking-Regeln, Historie und Team-Kommunikation konsequent zusammenpassen. Die meisten Probleme entstehen nicht durch das Werkzeug selbst, sondern durch halb durchgeführte Einrichtung, etwa vergessene .gitattributes-Commits oder eine Migration ohne vorherige Abstimmung im Team.
Mironsoft
Git-Workflows, Repository-Hygiene und Deployment-Setup für PHP- und Magento-Teams
Repository durch grosse Binärdateien überlastet?
Wir richten Git LFS für euer Team ein, migrieren bestehende Binärdateien sicher aus der Historie und koordinieren den Force-Push, ohne dass Mitarbeitende ihre laufende Arbeit verlieren.
LFS-Einrichtung
Tracking-Regeln, .gitattributes und Team-Onboarding sauber aufsetzen
Historie-Migration
Sichere Migration bestehender Binärdateien mit Backup und Rollout-Plan
Kosten-Check
LFS-Speicher- und Bandbreitenbedarf realistisch einschätzen
10. Zusammenfassung
Git LFS löst ein konkretes strukturelles Problem: Binärdateien passen nicht zu Gits zeilenbasierter Delta-Kompression und blähen Repository und Clone-Zeit unnötig auf. Pointer-Dateien mit Versionsangabe, SHA-256-Hash und Dateigrösse ersetzen die eigentlichen Inhalte in der Git-Historie, während Smudge- und Clean-Filter den Austausch beim Checkout und Commit transparent im Hintergrund erledigen. git lfs track plus eine committete .gitattributes legen fest, welche Dateitypen betroffen sind, und der gewohnte Commit-Push-Workflow bleibt für Entwickler unverändert.
Für bereits bestehende Repositories ist git lfs migrate import der einzige Weg, historische Binärdateien tatsächlich aus der Vergangenheit zu entfernen, allerdings nur mit vollständigem Backup und abgestimmtem Force-Push im gesamten Team. Wer diese Schritte konsequent umsetzt und gleichzeitig weiss, wann Assets gar nicht erst ins Repository gehören, etwa generierte Magento-Medien, hält das Repository dauerhaft schlank und performant.
Git LFS: Grosse Dateien sinnvoll versionieren - Das Wichtigste auf einen Blick
Das Grundproblem
Gits Delta-Kompression funktioniert bei Text, nicht bei Binärdaten. Jede Version einer grossen Datei bläht die Historie dauerhaft auf.
Pointer + Filter
Eine kleine Pointer-Datei ersetzt den Binärinhalt in Git. Smudge- und Clean-Filter tauschen sie transparent beim Checkout/Commit aus.
Tracking einrichten
git lfs track "*.psd" plus committete .gitattributes, damit alle Teammitglieder dieselben Regeln nutzen.
Migration bestehender Dateien
git lfs migrate import --everything rewrites die Historie. Backup vorher, --force-with-lease danach, Team informieren.