Behebung von Performance-Problemen durch große Dateien in Git

Kämpfen Sie mit langsamen Git-Operationen aufgrund großer Dateien? Dieser umfassende Leitfaden erklärt, warum binäre Assets Ihr Repository aufblähen und wie Sie dies mithilfe von Git LFS verhindern können. Erfahren Sie Schritt für Schritt, wie Sie Git LFS für neue Projekte einrichten und vor allem, wie Sie bestehende Performance-Engpässe beheben, indem Sie historische große Dateien mit `git lfs migrate` migrieren. Entdecken Sie Best Practices, praktische Beispiele und unverzichtbare Tipps, um ein schlankes, performantes Git-Repository zu pflegen und so eine reibungslose Zusammenarbeit und schnellere Workflows zu gewährleisten.

47 Aufrufe

Fehlerbehebung bei Leistungsproblemen durch große Dateien in Git

Git ist ein unglaublich leistungsstarkes verteiltes Versionskontrollsystem, das sich hervorragend zur Nachverfolgung von Änderungen in textbasiertem Code eignet. Seine dezentrale Natur, bei der jeder Klon eine vollständige Kopie der Repository-Historie erhält, stellt jedoch eine erhebliche Herausforderung dar, wenn große Binärdateien wie Bilder, Audio, Video oder kompilierte Assets verarbeitet werden müssen. Das Einchecken dieser Dateien direkt in Ihre Git-Historie kann zu erheblichen Leistungseinbußen führen und gängige Operationen wie Klonen, Abrufen (fetching) und Pushen quälend langsam machen.

Dieser Artikel befasst sich mit den Ursachen von Leistungsproblemen, die durch große Dateien in Git verursacht werden. Wir werden proaktive Strategien mit Git Large File Storage (LFS) untersuchen, um diese Probleme von vornherein zu verhindern, und eine klare, umsetzbare Anleitung bereitstellen, wie bestehende Probleme mit großen Dateien im Repository-Verlauf behoben werden können. Am Ende verfügen Sie über das Wissen und die Werkzeuge, um Ihre Git-Repositories effizient zu verwalten, unabhängig von ihrem Inhalt.

Das Problem mit großen Dateien in Git

Gits Designphilosophie konzentriert sich auf Effizienz für Quellcode. Es speichert Dateiinhalte als "Blobs" und verfolgt Änderungen zwischen Versionen als Snapshots, wobei hochentwickelte Delta-Kompression eingesetzt wird, um die Repository-Größe für Textdateien überschaubar zu halten. Dieser Ansatz ist jedoch für große Binärdateien ungeeignet:

  • Schlechte Kompression: Binärdateien lassen sich mit Gits Delta-Kompression nicht gut komprimieren, da ihre Änderungen nicht einfach zu vergleichen sind. Selbst eine kleine Änderung an einer großen Binärdatei kann dazu führen, dass Git einen völlig neuen, großen Blob speichert.
  • Repository-Aufblähung: Jede Version einer großen Binärdatei, die in die Repository-Historie eingecheckt wird, trägt erheblich zu deren Gesamtgröße bei. Da Git verteilt ist, lädt jeder Mitarbeiter, der ein Repository klont oder Updates abruft, die gesamte Historie herunter.
  • Langsame Operationen: Große Repository-Größen führen direkt zu langsamen Git-Operationen:
    • git clone: Kann extrem lange dauern und verbraucht riesige Mengen an Bandbreite und Speicherplatz.
    • git fetch/git pull: Das Abrufen von Updates wird träge.
    • git push: Das Senden neuer Commits mit großen Dateien ist langsam.
    • git checkout: Das Wechseln von Branches oder Wiederherstellen älterer Versionen kann langsam sein, da Git das Dateisystem neu zusammenstellt.

Letztendlich führt dies zu Frustration, verringerter Produktivität und entmutigt effektive Versionskontrollpraktiken bei Teams, die mit grafischen Assets, Dateien für die Spieleentwicklung oder großen Datensätzen arbeiten.

Verhinderung von Problemen mit großen Dateien: Git LFS implementieren

Der effektivste Weg, Probleme mit großen Dateien zu verhindern, ist die Implementierung von Git Large File Storage (LFS) von Anfang an. Git LFS ist eine Open-Source-Erweiterung für Git, die große Dateien in Ihrem Repository durch winzige Zeigerdateien ersetzt, während der eigentliche Dateiinhalt auf einem entfernten LFS-Server gespeichert wird (der neben Ihrem Git-Repository auf Plattformen wie GitHub, GitLab oder Bitbucket gehostet werden kann).

Wie Git LFS funktioniert

Wenn Sie einen Dateityp mit Git LFS verfolgen:

  1. Commit: Anstelle der tatsächlichen großen Datei committet Git eine kleine Zeigerdatei in Ihr Repository. Diese Zeigerdatei enthält Informationen über die große Datei, wie z. B. ihre OID (eine eindeutige Kennung basierend auf dem SHA-256-Hash ihres Inhalts) und ihre Größe.
  2. Push: Wenn Sie git push ausführen, wird der eigentliche Inhalt der großen Datei auf den LFS-Server hochgeladen, und die Zeigerdatei wird an das Standard-Git-Remote-Repository gesendet.
  3. Clone/Fetch: Wenn Sie git clone oder git fetch ausführen, lädt Git die Zeigerdateien herunter. Git LFS fängt diese Zeiger dann ab und lädt die tatsächlichen großen Dateien vom LFS-Server in Ihr Arbeitsverzeichnis herunter.

Dieser Mechanismus hält Ihr Haupt-Git-Repository schlank und schnell, da es nur die kleinen Zeigerdateien enthält.

Git LFS einrichten

Die Einrichtung von Git LFS ist unkompliziert:

1. Git LFS installieren

Zuerst müssen Sie die Git LFS-Kommandozeilen-Erweiterung installieren. Sie können sie von der offiziellen Git LFS-Website herunterladen oder Paketmanager verwenden:

# Unter macOS mit Homebrew
brew install git-lfs

# Unter Debian/Ubuntu
sudo apt-get install git-lfs

# Unter Fedora
sudo dnf install git-lfs

# Unter Windows (Chocolatey)
choco install git-lfs

Führen Sie nach der Installation einmalig den folgenden Befehl pro Benutzerkonto aus, um LFS zu initialisieren:

git lfs install

Dieser Befehl fügt die notwendigen Git-Hooks hinzu, um LFS-Dateien automatisch zu verarbeiten.

2. Dateien mit Git LFS verfolgen

Weisen Sie Git LFS nun an, welche Dateitypen oder spezifischen Dateien es verwalten soll. Dies geschieht mit git lfs track und durch Hinzufügen der Muster zu Ihrer .gitattributes-Datei.

Um beispielsweise alle PSD-Dateien und MP4-Videos zu verfolgen:

git lfs track "*.psd"
git lfs track "*.mp4"

Diese Befehle ändern oder erstellen eine .gitattributes-Datei in Ihrem Repository, die ungefähr so aussieht:

*.psd filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text

Wichtig: Committen Sie Ihre .gitattributes-Datei in das Repository. Dies stellt sicher, dass alle Mitarbeiter die gleichen LFS-Tracking-Regeln verwenden.

git add .gitattributes
git commit -m "Git LFS für PSD und MP4-Dateien konfigurieren"

3. LFS-verfolgte Dateien committen und pushen

Sobald git lfs track konfiguriert und committet ist, werden alle neuen Dateien (oder geänderte vorhandene Dateien), die den Mustern entsprechen, automatisch von LFS behandelt, wenn Sie sie committen und pushen. Ihr Workflow bleibt weitgehend derselbe:

git add my_design.psd
git commit -m "Neue Design-Datei hinzufügen (von LFS verfolgt)"
git push origin main

Beim Pushen lädt Git die Zeigerdateien in das Git-Remote-Repository hoch, und Git LFS kümmert sich um den Upload der tatsächlichen Datei my_design.psd auf den LFS-Server.

Best Practices für Git LFS

  • Frühzeitig verfolgen: Es ist am besten, LFS zu konfigurieren, bevor große Dateien direkt in Git eingecheckt werden. Dies verhindert spätere Änderungen des Verlaufs.
  • Spezifische Muster verwenden: Während *.png oder *.jpg üblich sind, überlegen Sie, ob alle Bilddateien LFS benötigen. Manchmal sind kleinere Bilder in Git in Ordnung, während größere LFS-getrackt werden sollten.
  • Tracking überprüfen: Verwenden Sie git lfs ls-files, um zu sehen, welche Dateien derzeit in Ihrem Arbeitsverzeichnis von LFS verfolgt werden.
  • Team schulen: Stellen Sie sicher, dass alle Teammitglieder verstehen, wie LFS funktioniert und dass sie es korrekt installiert und konfiguriert haben.
  • Speicherlimits beachten: LFS-Speicherplatz ist auf Hosting-Plattformen in der Regel kostenpflichtig. Überwachen Sie Ihre Nutzung.

Behebung bestehender Probleme mit großen Dateien (Verlauf umschreiben)

Wenn große Dateien bereits in Ihrer Git-Historie vorhanden sind, wird das einfache Aktivieren von Git LFS die Vergangenheit Ihres Repositorys nicht verkleinern. Um historische Aufblähungen zu bereinigen, müssen Sie den Verlauf Ihres Repositorys umschreiben und die tatsächlichen großen Dateien durch LFS-Zeiger ersetzen. Dies ist ein mächtiger, aber potenziell destruktiver Vorgang, gehen Sie daher vorsichtig vor.

Warnung: Das Umschreiben des Verlaufs ändert Commit-SHAs, was zu erheblichen Störungen für Mitarbeiter führen kann. Sichern Sie Ihr Repository immer, bevor Sie fortfahren, und kommunizieren Sie klar mit Ihrem Team.

git lfs migrate zum Konvertieren vorhandener Dateien verwenden

Der Befehl git lfs migrate wurde speziell für diesen Zweck entwickelt. Er kann die Historie Ihres Repositorys analysieren, große Dateien identifizieren, sie durch LFS-Zeiger ersetzen und dann den Verlauf entsprechend umschreiben.

1. Kandidatendateien identifizieren

Vor der Migration ist es hilfreich zu identifizieren, welche Dateien am meisten zum Speicherplatz Ihres Repositorys beitragen. git lfs migrate info ist ein ausgezeichnetes Werkzeug dafür:

git lfs migrate info
# Oder um Dateien über einer bestimmten Größe anzuzeigen
git lfs migrate info --everything --above=10MB

Dieser Befehl listet die größten Dateien nach Größe und den von ihnen belegten Gesamtspeicherplatz in Ihrer Historie auf, was Ihnen bei der Entscheidung hilft, welche Muster in die Migration einbezogen werden sollen.

2. Die Migration durchführen

Verwenden Sie git lfs migrate import, um den Verlauf umzuschreiben und angegebene Dateien in LFS zu konvertieren. Dieser Befehl erstellt die notwendigen .gitattributes-Einträge und konvertiert die historischen Blobs.

# Beispiel: Alle .psd und .mp4 Dateien in Ihrer gesamten Historie migrieren
git lfs migrate import --include="*.psd,*.mp4"

# Wenn Sie nur Dateien ab einer bestimmten Größe migrieren möchten (z. B. 5 MB)
git lfs migrate import --above=5MB

# Um Dateien zu migrieren, die nach einem bestimmten Datum hinzugefügt wurden (nützlich für aktuelle Aufblähungen)
git lfs migrate import --include="*.zip" --since="2023-01-01"

Erläuterung der Flags:
* --include: Gibt Dateimuster an, die migriert werden sollen (durch Kommas getrennt).
* --above: Migriert jede Datei, die größer als die angegebene Größe ist (z. B. 10MB, 500KB).
* --since/--everything: Steuert den zu scannenden Verlaufsbereich. --everything ist normalerweise sicher, wenn Sie den gesamten Verlauf bereinigen möchten. --since kann den Umfang begrenzen.

Nachdem Sie diesen Befehl ausgeführt haben, wird der Verlauf Ihres lokalen Repositorys umgeschrieben und die .gitattributes-Datei wird aktualisiert.

3. Migration überprüfen

Überprüfen Sie nach der Migration, ob die Dateien jetzt von LFS verfolgt werden und ob die Größe Ihres Repositorys abgenommen hat:

# Überprüfen Sie die .gitattributes-Datei
cat .gitattributes

# Überprüfen Sie die lokale Repository-Größe (z. B. mit 'du -sh .git' unter Linux/macOS)
du -sh .git

# Optional, inspizieren Sie eine bestimmte große Datei in Ihrem Arbeitsverzeichnis.
# 'git lfs ls-files' sollte sie als LFS-Datei anzeigen.

4. Zum Remote erzwingen (Force Push)

Da Sie den Verlauf umgeschrieben haben, wird ein normaler git push abgelehnt. Sie müssen einen Force Push durchführen, um das Remote-Repository zu aktualisieren. Hier ist die Kommunikation mit Ihrem Team entscheidend.

git push --force origin main # Oder der Name Ihres Haupt-Branches

# Wenn Sie mehrere Branches bereinigen müssen, müssen Sie diese ebenfalls mit Force Push aktualisieren.
# Erwägen Sie force-with-lease für sichereres Force Pushing
git push --force-with-lease origin main

Warnung: Ein Force Push überschreibt den Remote-Verlauf. Stellen Sie sicher, dass alle Mitarbeiter die neuesten Änderungen abgerufen haben, bevor Sie einen Force Push durchführen, oder besser noch, stellen Sie sicher, dass sie informiert sind und ihre Arbeit auf Ihrem neuen Verlauf neu aufsetzen können. Es ist oft am besten, dies während eines Wartungsfensters zu tun oder wenn niemand aktiv am Repository arbeitet.

5. Alte Referenzen bereinigen (Optional, aber empfohlen)

Selbst nach einem Force Push können die alten großen Objekte noch eine Zeit lang auf dem Remote-Server vorhanden sein (oft in einem "Reflog" oder "alte Objekte"-Speicher). Um Speicherplatz vollständig wiederzugewinnen, müssen Sie möglicherweise serverseitig ein git gc ausführen, oder Ihr Git-Hosting-Anbieter hat möglicherweise einen speziellen Bereinigungsprozess.

Lokal können Sie alte, nicht erreichbare Objekte bereinigen:

git reflog expire --expire=now --all
git gc --prune=now

Tipps und Warnungen

  • Zuerst sichern: Erstellen Sie immer eine vollständige Sicherung Ihres Repositorys (z. B. git clone --mirror), bevor Sie eine Operation zum Umschreiben des Verlaufs durchführen.
  • Mit dem Team kommunizieren: Das Umschreiben des Verlaufs betrifft alle. Koordinieren Sie sich im Voraus mit Ihrem Team und geben Sie klare Anweisungen zum Aktualisieren ihrer lokalen Klone (sie müssen wahrscheinlich neu klonen oder spezifische Rebase/Reset-Operationen durchführen).
  • Gründlich testen: Wenn möglich, führen Sie die Migration zuerst in einem Test-Repository durch, um die Auswirkungen zu verstehen.
  • filter-repo-Alternative: Für komplexere Szenarien des Verlaufs-Umschreibens (z. B. das vollständige Entfernen einer Datei aus dem Verlauf, nicht nur die Konvertierung in LFS) ist git filter-repo die moderne, schnellere und flexiblere Alternative zum veralteten git filter-branch oder dem BFG Repo-Cleaner. Für die LFS-Konvertierung ist git lfs migrate import jedoch im Allgemeinen einfacher und zweckgebunden.
  • Repository-Größe überwachen: Überprüfen Sie regelmäßig die Größe Ihres Repositorys und die LFS-Nutzung, um neue Probleme frühzeitig zu erkennen.

Fazit

Große Binärdateien können eine erhebliche Leistungseinbuße für Git-Repositories darstellen, was zu langsamen Operationen und Frustration bei Entwicklern führt. Durch die proaktive Implementierung von Git LFS für neue Dateien und die Nutzung von git lfs migrate import zur Behebung historischer Aufblähungen können Sie ein schlankes, effizientes und leistungsstarkes Versionskontrollsystem aufrechterhalten. Denken Sie an die kritischen Schritte: Installieren Sie Git LFS, verfolgen Sie Ihre großen Dateien und schreiben Sie bei Bedarf sorgfältig Ihren Verlauf mit git lfs migrate um, wobei Sie stets die Kommunikation und Backups mit Ihrem Team priorisieren. Ein gut verwaltetes Git-Repository sorgt für eine reibungslosere Zusammenarbeit und einen produktiveren Entwicklungs-Workflow für alle Beteiligten.