554 Stimmen

Verwaltung großer Binärdateien mit Git

Ich bin auf der Suche nach Meinungen zum Umgang mit großen Binärdateien, von denen mein Quellcode (Webanwendung) abhängig ist. Wir erörtern derzeit mehrere Alternativen:

  1. Kopieren Sie die Binärdateien von Hand.
    • Pro: Nicht sicher.
    • Contra: Ich bin strikt dagegen, da dies die Wahrscheinlichkeit von Fehlern bei der Einrichtung einer neuen Website bzw. der Migration der alten Website erhöht. Es baut eine weitere Hürde auf, die es zu nehmen gilt.
  2. Verwalten Sie sie alle mit Git .
    • Pro: Die Möglichkeit, das Kopieren einer wichtigen Datei zu "vergessen", entfällt
    • Contra: Bläht das Repository auf und verringert die Flexibilität bei der Verwaltung der Code-Basis, und das Auschecken, Klonen usw. wird eine ganze Weile dauern.
  3. Getrennte Repositories.
    • Pro: Das Auschecken/Klonen des Quellcodes ist so schnell wie immer, und die Images werden ordnungsgemäß in einem eigenen Repository archiviert.
    • Contra: Entfernt die Einfachheit der der Einzige Git-Repository für das Projekt. Das bringt sicherlich noch einige andere Dinge mit sich, über die ich nicht nachgedacht habe.

Was sind Ihre Erfahrungen/Gedanken dazu?

Auch: Hat jemand Erfahrung mit mehreren Git-Repositories und deren Verwaltung in einem Projekt?

Die Dateien sind Bilder für ein Programm, das PDFs mit diesen Dateien erzeugt. Die Dateien werden sich nicht sehr oft ändern (wie in Jahren), aber sie sind sehr wichtig für ein Programm. Das Programm wird ohne die Dateien nicht funktionieren.

26voto

Daniel Fanjul Punkte 3453

Ich würde Submodule (wie Pat Notz) oder zwei verschiedene Repositories verwenden. Wenn Sie Ihre Binärdateien zu oft ändern, würde ich versuchen, die Auswirkungen der Bereinigung der Historie durch das große Repository zu minimieren:

Ich hatte vor einigen Monaten ein sehr ähnliches Problem: ~21 GB MP3-Dateien, nicht klassifiziert (schlechte Namen, schlechte id3s, ich weiß nicht, ob ich diese MP3-Datei mag oder nicht...), und auf drei Computern repliziert.

Ich habe eine externe Festplatte mit dem Haupt-Git-Repository verwendet und es auf jeden Computer geklont. Dann begann ich, sie auf die übliche Art und Weise zu klassifizieren (schieben, ziehen, zusammenführen... löschen und umbenennen viele Male).

Am Ende hatte ich nur ~6 GB an MP3-Dateien und ~83 GB im .git-Verzeichnis. Ich benutzte git-write-tree y git-commit-tree um einen neuen Commit ohne Commit-Vorfahren zu erstellen und einen neuen Zweig zu beginnen, der auf diesen Commit zeigt. Das "git log" für diesen Zweig zeigte nur einen Commit an.

Dann löschte ich den alten Zweig, behielt nur den neuen Zweig, löschte die ref-logs und führte "git prune" aus: danach wog mein .git-Ordner nur noch ~6 GB...

Sie könnten das große Repository von Zeit zu Zeit auf dieselbe Weise "bereinigen": Ihre "git clone"'s werden schneller sein.

15voto

Adam Kurkiewicz Punkte 1306

Die Lösung, die ich vorschlagen möchte, basiert auf verwaisten Zweigen und einem leichten Missbrauch des Tag-Mechanismus, im Folgenden als *Orphan Tags Binary Storage bezeichnet (OTABS)

TL;DR 12-01-2017 Wenn Sie das LFS von Github oder einem anderen Drittanbieter verwenden können, sollten Sie das auf jeden Fall tun. Wenn Sie das nicht können, dann lesen Sie weiter. Seien Sie gewarnt, diese Lösung ist ein Hack und sollte als solcher behandelt werden.

Wünschenswerte Eigenschaften von OTABS

  • Es ist ein reiner Git y nur Git Lösung - sie erledigt die Aufgabe ohne Software von Drittanbietern (wie git-annex) oder Infrastruktur von Drittanbietern (wie github's LFS).
  • speichert er die Binärdateien effizient d.h. es bläht die Historie Ihres Repositorys nicht auf.
  • git pull y git fetch , einschließlich git fetch --all sind noch bandbreiteneffizient d.h. nicht alle großen Binärdateien werden standardmäßig von der Gegenstelle bezogen.
  • es funktioniert bei Windows .
  • es speichert alles in einem einzelnes Git-Repository .
  • Sie ermöglicht es Löschung von veralteten Binärdateien (im Gegensatz zu bup).

Unerwünschte Eigenschaften von OTABS

  • es macht git clone potenziell ineffizient (aber nicht unbedingt, je nach Nutzung). Wenn Sie diese Lösung einsetzen, müssen Sie Ihren Kollegen möglicherweise raten, Folgendes zu verwenden git clone -b master --single-branch <url> anstelle von git clone . Das liegt daran, dass git clone standardmäßig buchstäblich klont gesamte Repository, einschließlich der Dinge, für die man normalerweise keine Bandbreite verschwenden möchte, wie nicht referenzierte Commits. Entnommen aus SO 4811434 .
  • es macht git fetch <remote> --tags ineffiziente Bandbreite, aber nicht unbedingt ineffizienter Speicherplatz. Sie können Ihren Kollegen immer davon abraten, sie zu verwenden.
  • müssen Sie in regelmäßigen Abständen eine git gc Trick, um Ihr Repository von Dateien zu säubern, die Sie nicht mehr benötigen.
  • sie ist nicht so effizient wie bup o git-bigfiles . Aber es ist für das, was Sie vorhaben, besser geeignet und eher von der Stange. Bei Hunderttausenden von kleinen Dateien oder bei Dateien im Gigabyte-Bereich werden Sie wahrscheinlich auf Probleme stoßen, aber lesen Sie weiter, um Abhilfe zu schaffen.

Hinzufügen der Binärdateien

Bevor Sie beginnen, vergewissern Sie sich, dass Sie alle Änderungen übertragen haben, dass Ihr Arbeitsbaum auf dem neuesten Stand ist und dass Ihr Index keine nicht übertragenen Änderungen enthält. Es könnte eine gute Idee sein, alle Ihre lokalen Zweige auf Ihr Remote-System (Github usw.) zu übertragen, für den Fall, dass eine Katastrophe eintritt.

  1. Erstellen Sie einen neuen verwaisten Zweig. git checkout --orphan binaryStuff reicht aus. Dies erzeugt einen Zweig, der von allen anderen Zweigen völlig losgelöst ist, und die erste Übertragung, die Sie in diesem Zweig vornehmen, hat keine Eltern, was sie zu einer Root-Übertragung macht.
  2. Bereinigen Sie Ihren Index mit git rm --cached * .gitignore .
  3. Atmen Sie tief durch und löschen Sie den gesamten Arbeitsbaum mit rm -fr * .gitignore . Intern .git bleibt unangetastet, da das Verzeichnis * Platzhalter nicht übereinstimmt.
  4. Kopieren Sie Ihre VeryBigBinary.exe, oder Ihr VeryHeavyDirectory/.
  5. Hinzufügen && Übertragen.
  6. Jetzt wird es knifflig - wenn Sie es als Zweig in das Remote-System schieben, werden alle Ihre Entwickler es herunterladen, wenn sie das nächste Mal die git fetch die ihre Verbindung blockieren. Sie können dies vermeiden, indem Sie einen Tag statt einer Verzweigung pushen. Dies kann sich jedoch auf die Bandbreite und den Dateisystemspeicher Ihrer Kollegen auswirken, wenn diese die Angewohnheit haben, Folgendes einzugeben git fetch <remote> --tags aber lesen Sie weiter, um eine Lösung zu finden. Machen Sie weiter und git tag 1.0.0bin
  7. Schieben Sie Ihr verwaistes Tag git push <remote> 1.0.0bin .
  8. Damit Sie Ihren Binärzweig nicht aus Versehen verschieben, können Sie ihn löschen git branch -D binaryStuff . Ihr Commit wird nicht für die Garbage Collection markiert, weil ein verwaistes Tag darauf verweist 1.0.0bin reicht aus, um sie am Leben zu erhalten.

Auschecken der Binärdatei

  1. Wie kann ich (oder meine Kollegen) die VeryBigBinary.exe in den aktuellen Arbeitszweig auschecken? Wenn Ihr aktueller Arbeitszweig zum Beispiel master ist, können Sie einfach git checkout 1.0.0bin -- VeryBigBinary.exe .
  2. Dies wird fehlschlagen, wenn Sie nicht über das Orphan-Tag verfügen 1.0.0bin heruntergeladen, in diesem Fall müssen Sie git fetch <remote> 1.0.0bin im Vorfeld.
  3. Sie können die VeryBigBinary.exe in Ihr Masterstudium .gitignore damit niemand in Ihrem Team die Hauptgeschichte des Projekts versehentlich mit dem Binärcode verunreinigt.

Vollständige Löschung der Binärdatei

Wenn Sie VeryBigBinary.exe vollständig aus Ihrem lokalen Repository, Ihrem entfernten Repository und den Repositorys Ihrer Kollegen entfernen möchten, können Sie dies einfach tun:

  1. Löschen Sie das verwaiste Tag auf der Fernbedienung git push <remote> :refs/tags/1.0.0bin
  2. Das verwaiste Tag lokal löschen (löscht alle anderen nicht referenzierten Tags) git tag -l | xargs git tag -d && git fetch --tags . Entnommen aus SO 1841341 mit leichten Änderungen.
  3. Verwenden Sie einen git gc-Trick, um Ihren nicht mehr referenzierten Commit lokal zu löschen. git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 -c gc.rerereresolved=0 -c gc.rerereunresolved=0 -c gc.pruneExpire=now gc "$@" . Es werden auch alle anderen nicht referenzierten Commits gelöscht. Entnommen aus SO 1904860
  4. Wenn möglich, wiederholen Sie den Trick mit git gc auf der Gegenstelle. Dies ist möglich, wenn Sie Ihr Repository selbst hosten. Bei einigen Git-Anbietern wie Github oder in einigen Unternehmensumgebungen ist dies möglicherweise nicht möglich. Wenn Sie Ihr Repository bei einem Anbieter hosten, der Ihnen keinen ssh-Zugang zum Remote-Repository gewährt, lassen Sie es einfach bleiben. Es ist möglich, dass die Infrastruktur Ihres Providers Ihre nicht referenzierte Übergabe in ihrer eigenen Zeit bereinigt. Wenn Sie in einem Unternehmen arbeiten, können Sie Ihrer IT-Abteilung raten, einmal pro Woche einen Cron-Job auszuführen, der Ihre Remote-Daten abholt. Ob sie das tun oder nicht, hat keine Auswirkungen auf Ihr Team in Bezug auf Bandbreite und Speicherplatz, solange Sie Ihren Kollegen raten, immer git clone -b master --single-branch <url> anstelle von git clone .
  5. Alle Kolleginnen und Kollegen, die veraltete verwaiste Etiketten loswerden wollen, müssen nur die Schritte 2-3 ausführen.
  6. Sie können dann die Schritte 1-8 von Hinzufügen der Binärdateien um ein neues verwaistes Etikett zu erstellen 2.0.0bin . Wenn Sie sich Sorgen machen, dass Ihre Kollegen tippen git fetch <remote> --tags Sie können es tatsächlich wieder benennen 1.0.0bin . Dadurch wird sichergestellt, dass beim nächsten Abruf aller Tags die alten 1.0.0bin wird nicht referenziert und für eine spätere Garbage Collection markiert (mit Schritt 3). Wenn Sie versuchen, ein Tag auf der Gegenstelle zu überschreiben, müssen Sie -f wie diese: git push -f <remote> <tagname>

Nachwort

  • OTABS berührt weder Ihren Master- noch einen anderen Quellcode-/Entwicklungszweig. Die Commit-Hashes, die gesamte Historie und die geringe Größe dieser Zweige bleiben davon unberührt. Wenn Sie Ihre Quellcode-Historie bereits mit Binärdateien aufgebläht haben, müssen Sie diese in einem separaten Arbeitsschritt bereinigen. Dieses Skript nützlich sein könnte.

  • Bestätigt, dass es unter Windows mit git-bash funktioniert.

  • Es ist eine gute Idee, ein Satz von Standard-Triks um die Speicherung von Binärdateien effizienter zu gestalten. Häufiges Ausführen von git gc (ohne zusätzliche Argumente) sorgt dafür, dass Git die zugrunde liegende Speicherung Ihrer Dateien durch die Verwendung binärer Deltas optimiert. Wenn es jedoch unwahrscheinlich ist, dass Ihre Dateien von Commit zu Commit gleich bleiben, können Sie binäre Deltas ganz abschalten. Da es keinen Sinn macht, bereits komprimierte oder verschlüsselte Dateien wie .zip, .jpg oder .crypt zu komprimieren, können Sie die Komprimierung des zugrunde liegenden Speichers abschalten. Leider handelt es sich dabei um eine Alles-oder-Nichts-Einstellung, die auch Ihren Quellcode betrifft.

  • Vielleicht möchten Sie Teile von OTABS mit einem Skript versehen, um eine schnellere Nutzung zu ermöglichen. Insbesondere die Scripting-Schritte 2-3 von Vollständiges Löschen von Binärdateien in eine update git hook könnte git fetch eine zwingende, aber vielleicht gefährliche Semantik verleihen ("alles holen und löschen, was veraltet ist").

  • Sie können den Schritt 4 von Vollständiges Löschen von Binärdateien um eine vollständige Historie aller binären Änderungen auf dem entfernten Rechner zu erhalten, ohne dass das zentrale Repository aufgebläht wird. Lokale Repositories werden mit der Zeit schlank bleiben.

  • In der Java-Welt ist es möglich, diese Lösung zu kombinieren mit maven --offline um ein reproduzierbares Offline-Build zu erstellen, das vollständig in Ihrer Versionskontrolle gespeichert ist (mit Maven ist das einfacher als mit Gradle). In der Golang-Welt ist es möglich, auf diese Lösung zu bauen, um Ihren GOPATH zu verwalten, anstatt go get . In der Python-Welt ist es möglich, dies mit virtualenv zu kombinieren, um eine in sich geschlossene Entwicklungsumgebung zu schaffen, ohne für jeden Build von Grund auf auf PyPi-Server angewiesen zu sein.

  • Wenn sich Ihre Binärdateien sehr häufig ändern, wie z.B. Build-Artefakte, könnte es eine gute Idee sein, eine Lösung zu skripten, die die 5 aktuellsten Versionen der Artefakte in den Orphan-Tags speichert monday_bin , tuesday_bin , ..., friday_bin und auch ein Orphan-Tag für jede Veröffentlichung 1.7.8bin 2.0.0bin , usw. Sie können die weekday_bin und löschen Sie alte Binärdateien täglich. Auf diese Weise erhalten Sie das Beste aus zwei Welten: Sie behalten die gesamte Geschichte Ihres Quellcodes, sondern nur die . Historie Ihrer Binärabhängigkeiten. Es ist auch sehr einfach, die Binärdateien für ein bestimmtes Tag zu erhalten ohne den gesamten Quellcode mit seiner gesamten Historie zu erhalten: git init && git remote add <name> <url> && git fetch <name> <tag> sollte dies für Sie tun.

13voto

claf Punkte 8682

Meiner Meinung nach sollten Sie, wenn Sie diese großen Dateien häufig ändern oder wenn Sie vorhaben, viele git clone o git checkout dann sollten Sie ernsthaft in Erwägung ziehen, ein anderes Git-Repository zu verwenden (oder vielleicht eine andere Möglichkeit, auf diese Dateien zuzugreifen).

Aber wenn Sie so arbeiten wie wir und Ihre Binärdateien nicht oft geändert werden, dann wird das erste Klonen/Checkout lange dauern, aber danach sollte es so schnell gehen, wie Sie es wünschen (wenn man bedenkt, dass Ihre Benutzer das erste geklonte Repository, das sie hatten, weiter benutzen).

11voto

Tony Diep Punkte 181

SVN scheint binäre Deltas effizienter zu handhaben als Git.

Ich musste mich für ein Versionierungssystem für die Dokumentation entscheiden (JPEG-Dateien, PDF-Dateien und .odt-Dateien). Ich habe gerade getestet, wie man eine JPEG-Datei hinzufügt und sie viermal um 90 Grad dreht (um die Wirksamkeit der binären Deltas zu überprüfen). Das Repository von Git wuchs um 400 %. Das Repository von SVN wuchs nur um 11 %.

Es sieht also so aus, als ob SVN bei Binärdateien viel effizienter ist.

Meine Wahl fällt daher auf Git für den Quellcode und SVN für Binärdateien wie die Dokumentation.

6voto

git clone --filter von Git 2.19 + flache Klone

Diese neue Option könnte die endgültige Lösung für das Binärdateiproblem werden, wenn die Entwickler von Git und GitHub sie benutzerfreundlich genug gestalten (was sie wohl tun werden). noch nicht für Submodule erreicht haben zum Beispiel).

Sie ermöglicht es, tatsächlich nur die Dateien und Verzeichnisse zu holen, die Sie für den Server wünschen, und wurde zusammen mit einer Remote-Protokoll-Erweiterung eingeführt.

Damit könnten wir zunächst einen oberflächlichen Klon durchführen und dann automatisieren, welche Blobs mit dem Build-System für jede Art von Build geholt werden sollen.

Es gibt sogar schon eine --filter=blob:limit<size> die es ermöglicht, die maximale Größe des zu holenden Blob zu begrenzen.

Ich habe ein minimales, detailliertes Beispiel gegeben, wie die Funktion aussieht: Wie kann ich nur ein Unterverzeichnis eines Git-Repositorys klonen?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X