web-dev-qa-db-ger.com

Große Binärdateien mit Git verwalten

Ich suche Meinungen zum Umgang mit großen Binärdateien, von denen mein Quellcode (Webanwendung) abhängig ist. Wir diskutieren derzeit mehrere Alternativen:

  1. Kopieren Sie die Binärdateien von Hand.
    • Pro: Ich bin mir nicht sicher.
    • Contra: Ich bin stark dagegen, da es die Wahrscheinlichkeit von Fehlern beim Einrichten einer neuen Site/beim Migrieren der alten Site erhöht. Baut eine weitere Hürde auf.
  2. Verwalte sie alle mit Git.
    • Pro: Entfernt die Möglichkeit, das Kopieren einer wichtigen Datei zu "vergessen"
    • Contra: Bläht das Repository auf und verringert die Flexibilität beim Verwalten der Codebasis, und das Auschecken, Klonen usw. wird einige Zeit in Anspruch nehmen.
  3. Separate Repositories.
    • Pro: Das Auschecken/Klonen des Quellcodes erfolgt wie immer schnell und die Bilder werden ordnungsgemäß in einem eigenen Repository archiviert.
    • Contra: Entfernt die Einfachheit, das einzige Git-Repository im Projekt zu haben. Es führt sicherlich einige andere Dinge ein, an die ich nicht gedacht habe.

Was sind deine Erfahrungen/Gedanken dazu?

Außerdem: Hat jemand Erfahrung mit mehreren Git-Repositorys und deren Verwaltung in einem Projekt?

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

514
pi.

Wenn das Programm ohne die Dateien nicht funktioniert, scheint es eine schlechte Idee zu sein, sie in ein separates Repo aufzuteilen. Wir haben große Testsuiten, die wir in ein separates Repo aufteilen, aber das sind wirklich "Hilfsdateien".

Möglicherweise können Sie die Dateien jedoch in einem separaten Repository verwalten und dann git-submodule um sie auf vernünftige Weise in Ihr Projekt zu ziehen. Sie hätten also immer noch den vollständigen Verlauf Ihrer gesamten Quelle, aber nach meinem Verständnis hätten Sie nur die eine relevante Revision Ihres Bildersubmoduls. Das git-submodule Die Funktion soll Ihnen helfen, die korrekte Version des Codes mit der korrekten Version der Bilder in Einklang zu bringen.

Hier ist eine gute Einführung in Submodule von Git Book.

177
Pat Notz

Ich habe git-annex kürzlich entdeckt, was ich großartig finde. Es wurde für die effiziente Verwaltung großer Dateien entwickelt. Ich benutze es für meine Foto/Musik (etc.) Sammlungen. Die Entwicklung von Git-Annex ist sehr aktiv. Der Inhalt der Dateien kann aus dem Git-Repository entfernt werden, nur die Baumhierarchie wird von Git verfolgt (über Symlinks). Um jedoch den Inhalt der Datei zu erhalten, ist nach dem Ziehen/Drücken ein zweiter Schritt erforderlich, z.

$ git annex add mybigfile
$ git commit -m'add mybigfile'
$ git Push myremote
$ git annex copy --to myremote mybigfile ## This command copies the actual content to myremote
$ git annex drop mybigfile ## Remove content from local repo
...
$ git annex get mybigfile ## Retrieve the content
## or to specify the remote from which to get:
$ git annex copy --from myremote mybigfile

Es gibt viele Befehle und eine großartige Dokumentation auf der Website. Ein Paket ist verfügbar unter Debian .

309
rafak

Eine andere Lösung ist seit April 2015 Git Large File Storage (LFS) (von GitHub).

Es verwendet git-lfs (siehe git-lfs.github .com) und mit einem Server getestet, der es unterstützt: lfs-test-server :
Sie können Metadaten nur im Git-Repo und die große Datei an anderer Stelle speichern.

https://cloud.githubusercontent.com/assets/1319791/7051226/c4570828-ddf4-11e4-87eb-8fc165e5ece4.gif

47
VonC

Schauen Sie sich git bup an, eine Git-Erweiterung zum intelligenten Speichern großer Binärdateien in einem Git-Repository.

Sie möchten es als Submodul haben, müssen sich aber keine Sorgen darüber machen, dass das Repository schwer zu handhaben ist. Einer ihrer Anwendungsbeispiele ist das Speichern von VM - Images in Git.

Ich habe eigentlich keine besseren Komprimierungsraten gesehen, aber meine Repositorys enthalten keine wirklich großen Binärdateien.

Ihr Kilometerstand kann variieren.

30
sehe

Sie können auch git-fat verwenden. Ich mag, dass es nur auf Lager ankommt Python und rsync . Es unterstützt auch den üblichen Git-Workflow mit den folgenden selbsterklärenden Befehlen:

git fat init
git fat Push
git fat pull

Außerdem müssen Sie eine .gitfat-Datei in Ihr Repository einchecken und Ihre .gitattributes ändern, um die Dateierweiterungen anzugeben, die Sie verwalten möchten git fat.

Sie fügen eine Binärdatei mit dem normalen git add Hinzu, der wiederum git fat Auf der Grundlage Ihrer Gitattributes-Regeln aufruft.

Schließlich hat es den Vorteil, dass der Speicherort, an dem Ihre Binärdateien tatsächlich gespeichert sind, für Repositorys und Benutzer freigegeben werden kann und alles unterstützt, was rsync tut.

UPDATE: Verwenden Sie kein Git-Fat, wenn Sie eine Git-SVN-Bridge verwenden. Am Ende werden die Binärdateien aus Ihrem Subversion-Repository entfernt. Wenn Sie jedoch ein reines Git-Repository verwenden, funktioniert es einwandfrei.

27
Carl

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

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

Ich habe ein externes Festplattenlaufwerk mit dem Haupt-Git-Repository verwendet und es in jeden Computer geklont. Dann fing ich an, sie wie gewöhnlich zu klassifizieren (mehrmals drücken, ziehen, zusammenführen ... löschen und umbenennen).

Am Ende hatte ich nur ~ 6 GB MP3-Dateien und ~ 83 GB im .git-Verzeichnis. Ich benutzte git-write-tree und git-commit-tree, um ein neues Commit ohne Commit-Vorfahren zu erstellen, und startete einen neuen Zweig, der auf dieses Commit verweist. Das "Git-Protokoll" für diesen Zweig zeigte nur ein Commit.

Dann habe ich den alten Zweig gelöscht, nur den neuen Zweig beibehalten, die Ref-Logs gelöscht und "git Prune" ausgeführt: Danach waren meine .git-Ordner nur noch ~ 6 GB schwer ...

Sie können das riesige Repository von Zeit zu Zeit auf die gleiche Weise "bereinigen": Ihre "Git-Klone" werden schneller sein.

25
Daniel Fanjul

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

Wenn Sie jedoch wie wir arbeiten und Ihre Binärdateien nicht häufig geändert werden, dauert das erste Klonen/Auschecken lange, danach sollte es jedoch so schnell sein, wie Sie möchten (wenn Ihre Benutzer weiterhin das erste geklonte Repository verwenden, das sie verwenden) hätten).

12
claf

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

TL; DR 12-01-2017 Wenn Sie Githubs LFS oder einen anderen Drittanbieter verwenden können, sollten Sie dies unbedingt tun. Wenn Sie nicht können, dann lesen Sie weiter. Seien Sie gewarnt, diese Lösung ist ein Hack und sollte als solche behandelt werden.

Wünschenswerte Eigenschaften von OTABS

  • es ist eine reine git und git nur lösung - es bekommt die Arbeit ohne Software von Drittanbietern (wie git-annex) oder Infrastruktur von Drittanbietern (wie githubs LFS).
  • es speichert die Binärdateien effizient , d. h. es bläht nicht den Verlauf Ihres Repositorys auf.
  • git pull Und git fetch, Einschließlich git fetch --all, Sind immer noch bandbreiteneffizient , dh nicht alle großen Binärdateien sind bandbreiteneffizient Standardmäßig von der Fernbedienung abgerufen.
  • es funktioniert unter Windows .
  • es speichert alles in einem einzigen Git-Repository .
  • es ermöglicht das Löschen von veralteten Binärdateien (im Gegensatz zu bup).

Unerwünschte Eigenschaften von OTABS

  • es macht git clone möglicherweise ineffizient (aber nicht unbedingt, abhängig von Ihrer Verwendung). Wenn Sie diese Lösung bereitstellen, müssen Sie möglicherweise Ihren Kollegen raten, git clone -b master --single-branch <url> Anstelle von git clone Zu verwenden. Dies liegt daran, dass git clone standardmäßig das gesamte Repository klont , einschließlich Dingen, für die Sie normalerweise keine Bandbreite verschwenden möchten, wie z. B. nicht referenzierte Commits. Entnommen aus SO 4811434 .
  • es macht die Bandbreite von git fetch <remote> --tags ineffizient, aber nicht unbedingt die Speicherung ineffizient. Sie können Ihren Kollegen jederzeit raten, es nicht zu verwenden.
  • sie müssen regelmäßig einen git gc - Trick anwenden, um Ihr Repository von allen Dateien zu säubern, die Sie nicht mehr benötigen.
  • es ist nicht so effizient wie bup oder git-bigfiles . Aber es eignet sich eher für das, was Sie tun wollen, als für das, was Sie von der Stange haben. Es ist wahrscheinlich, dass Sie Probleme mit Hunderttausenden kleiner Dateien oder mit Dateien im Gigabyte-Bereich haben, aber lesen Sie weiter, um dieses Problem zu umgehen.

Hinzufügen der Binärdateien

Bevor Sie beginnen, stellen Sie sicher, dass Sie alle Änderungen festgeschrieben haben, dass Ihr Arbeitsbaum auf dem neuesten Stand ist und Ihr Index keine nicht festgeschriebenen Änderungen enthält. Es könnte eine gute Idee sein, alle Ihre lokalen Niederlassungen auf Ihre Fernbedienung (Github usw.) zu übertragen, falls eine Katastrophe eintreten sollte.

  1. Erstellen Sie einen neuen Orphan Branch. git checkout --Orphan binaryStuff Erledigt den Trick. Dadurch wird ein Zweig erstellt, der von keinem anderen Zweig vollständig getrennt ist, und der erste Festschreibungsvorgang, den Sie in diesem Zweig ausführen, hat keinen übergeordneten Zweig. Dies macht ihn zu einem Root-Festschreibungsvorgang.
  2. Bereinigen Sie Ihren Index mit git rm --cached * .gitignore.
  3. Atmen Sie tief ein und löschen Sie den gesamten Arbeitsbaum mit rm -fr * .gitignore. Das interne .git - Verzeichnis bleibt unberührt, da der Platzhalter * Nicht damit übereinstimmt.
  4. Kopieren Sie in Ihrem VeryBigBinary.exe oder Ihrem VeryHeavyDirectory /.
  5. Fügen Sie es hinzu und bestätigen Sie es.
  6. Jetzt wird es schwierig - wenn Sie es als Zweig in die Fernbedienung schieben, werden alle Ihre Entwickler es herunterladen, wenn sie das nächste Mal git fetch Aufrufen, um ihre Verbindung zu blockieren. Sie können dies vermeiden, indem Sie ein Tag anstelle einer Verzweigung drücken. Dies kann sich immer noch auf die Bandbreite und den Dateisystemspeicher Ihres Kollegen auswirken, wenn er die Angewohnheit hat, git fetch <remote> --tags Einzugeben. Lesen Sie jedoch weiter, um dieses Problem zu umgehen. Mach weiter und git tag 1.0.0bin
  7. Schieben Sie Ihren Orphan-Tag git Push <remote> 1.0.0bin.
  8. Damit Sie Ihren Binärzweig nicht versehentlich verschieben, können Sie ihn löschen git branch -D binaryStuff. Ihr Commit wird nicht für die Garbage Collection markiert, da ein darauf verweisendes Orphan-Tag 1.0.0bin Ausreicht, um es am Leben zu erhalten.

Auschecken der Binärdatei

  1. Wie kann ich (oder meine Kollegen) die VeryBigBinary.exe in den aktuellen Arbeitsbaum auschecken lassen? Wenn Ihr aktueller Arbeitszweig zum Beispiel Master ist, können Sie einfach git checkout 1.0.0bin -- VeryBigBinary.exe.
  2. Dies schlägt fehl, wenn Sie das Orphan-Tag 1.0.0bin Nicht heruntergeladen haben. In diesem Fall müssen Sie vorher git fetch <remote> 1.0.0bin.
  3. Sie können den VeryBigBinary.exe In den .gitignore Ihres Masters einfügen, damit niemand in Ihrem Team versehentlich die Hauptgeschichte des Projekts mit der Binärdatei verschmutzt.

Vollständiges Löschen der Binärdatei

Wenn Sie VeryBigBinary.exe vollständig aus Ihrem lokalen Repository, Ihrem Remote-Repository und den Repositorys Ihrer Kollegen löschen möchten, haben Sie folgende Möglichkeiten:

  1. Löschen Sie das Orphan-Tag auf der Fernbedienung git Push <remote> :refs/tags/1.0.0bin
  2. Löschen Sie das Orphan-Tag lokal (löscht alle anderen nicht referenzierten Tags) git tag -l | xargs git tag -d && git fetch --tags. Entnommen aus SO 1841341 mit geringfügiger Änderung.
  3. Verwenden Sie einen git gc-Trick, um Ihr jetzt nicht referenziertes 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 "[email protected]". Es werden auch alle anderen nicht referenzierten Commits gelöscht. Entnommen aus SO 190486
  4. Wenn möglich, wiederholen Sie den git gc-Trick auf der Fernbedienung. Es ist möglich, dass Sie Ihr Repository selbst hosten und dies bei einigen Git-Anbietern, z. B. Github, oder in bestimmten Unternehmensumgebungen nicht möglich ist. Wenn Sie bei einem Provider hosten, der Ihnen keinen SSH-Zugriff auf die Fernbedienung gewährt, lassen Sie es einfach sein. Es ist möglich, dass die Infrastruktur Ihres Providers Ihr nicht referenziertes Commit in ihrer eigenen süßen Zeit bereinigt. Wenn Sie sich in einer Unternehmensumgebung befinden, können Sie Ihrer IT-Abteilung raten, etwa einmal pro Woche einen Cron-Job-Müll zu entsorgen, der Ihre Fernbedienung sammelt. Ob dies der Fall ist oder nicht, hat keine Auswirkungen auf die Bandbreite und den Speicher Ihres Teams, solange Sie Ihren Kollegen raten, immer git clone -b master --single-branch <url> Anstelle von git clone Zu verwenden.
  5. Alle Ihre Kollegen, die veraltete Orphan-Tags entfernen möchten, müssen nur die Schritte 2-3 ausführen.
  6. Sie können dann die Schritte 1-8 von Hinzufügen der Binärdateien wiederholen, um ein neues Orphan-Tag 2.0.0bin Zu erstellen. Wenn Sie besorgt sind, dass Ihre Kollegen git fetch <remote> --tags Eingeben, können Sie den Namen erneut eingeben 1.0.0bin. Dadurch wird sichergestellt, dass beim nächsten Abrufen aller Tags das alte 1.0.0bin Nicht referenziert und für die nachfolgende Garbage Collection markiert wird (mithilfe von Schritt 3). Wenn Sie versuchen, ein Tag auf der Fernbedienung zu überschreiben, müssen Sie -f Wie folgt verwenden: git Push -f <remote> <tagname>

Nachwort

  • OTABS berührt weder Ihren Master noch andere Quellcode- oder Entwicklungszweige. Die Commit-Hashes, der gesamte Verlauf und die geringe Größe dieser Zweige sind nicht betroffen. Wenn Sie Ihren Quellcode-Verlauf bereits mit Binärdateien aufgebläht haben, müssen Sie ihn als separate Arbeit bereinigen. Dieses Skript könnte nützlich sein.

  • Bestätigt, um unter Windows mit Git-Bash zu arbeiten.

  • Es ist eine gute Idee, ein Satz von Standardtrics anzuwenden, um die Speicherung von Binärdateien effizienter zu gestalten. Durch häufiges Ausführen von git gc (Ohne zusätzliche Argumente) optimiert git die zugrunde liegende Speicherung Ihrer Dateien mithilfe von Binärdeltas. Wenn es jedoch unwahrscheinlich ist, dass Ihre Dateien von Festschreiben zu Festschreiben ähnlich bleiben, können Sie Binärdeltas insgesamt ausschalten. Da es keinen Sinn macht, bereits komprimierte oder verschlüsselte Dateien wie .Zip, .jpg oder .crypt zu komprimieren, können Sie mit git die Komprimierung des zugrunde liegenden Speichers deaktivieren. Leider ist es eine Alles-oder-Nichts-Einstellung, die sich auch auf Ihren Quellcode auswirkt.

  • Möglicherweise möchten Sie Teile von OTABS mit Skripts versehen, um eine schnellere Verwendung zu ermöglichen. Insbesondere die Scripting-Schritte 2-3 von Vollständiges Löschen von Binärdateien in einem update Git-Hook könnten eine überzeugende, aber möglicherweise gefährliche Semantik für git fetch ("alles holen und löschen, was das ist ist nicht mehr aktuell").

  • Möglicherweise möchten Sie Schritt 4 von Vollständiges Löschen von Binärdateien überspringen, um einen vollständigen Verlauf aller binären Änderungen auf der Fernbedienung auf Kosten des zentralen Repositorys zu erhalten. Lokale Repositories bleiben im Laufe der Zeit mager.

  • In Java world ist es möglich, diese Lösung mit maven --offline Zu kombinieren, um einen reproduzierbaren Offline-Build zu erstellen, der vollständig in Ihrer Versionskontrolle gespeichert ist (mit maven ist es einfacher als mit gradle) Weltweit ist es möglich, auf dieser Lösung aufzubauen, um GOPATH anstelle von go get zu verwalten. In python Weltweit ist es möglich, dies mit virtualenv zu kombinieren, um eine eigenständige Entwicklungsumgebung zu erstellen ohne sich bei jedem Build von Grund auf auf PyPi-Server verlassen zu müssen.

  • Wenn sich Ihre Binärdateien sehr oft ändern, wie z. B. beim Erstellen von Artefakten, ist es möglicherweise eine gute Idee, ein Skript zu erstellen, in dem die fünf neuesten Versionen der Artefakte in den Orphan-Tags monday_bin, tuesday_bin, Gespeichert werden. .., friday_bin Und außerdem ein Orphan-Tag für jede Veröffentlichung 1.7.8bin2.0.0bin Usw. Sie können den weekday_bin Drehen und alte Binärdateien täglich löschen. Auf diese Weise erhalten Sie das Beste aus zwei Welten: Sie behalten den gesamten Verlauf Ihres Quellcodes bei, aber nur den relevanten Verlauf Ihrer binären Abhängigkeiten. Es ist auch sehr einfach, die Binärdateien für ein bestimmtes Tag abzurufen, ohne den gesamten Quellcode mit seiner gesamten Historie abzurufen: git init && git remote add <name> <url> && git fetch <name> <tag> Sollte reichen es für dich.

11
Adam Kurkiewicz

SVN scheint mit binären Deltas effizienter umzugehen als Git.

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

Es sieht also so aus, als wäre SVN mit Binärdateien viel effizienter.

Ich wähle Git für den Quellcode und SVN für Binärdateien wie Dokumentation.

9
Tony Diep

git clone --filter ab Git 2.19 + flache Klone

Diese neue Option könnte schließlich die endgültige Lösung des Problems mit Binärdateien werden, wenn die Entwickler von Git und GitHub es benutzerfreundlich genug machen (was sie wohl für Submodule immer noch nicht erreicht haben zum Beispiel).

Es erlaubt eigentlich nur das Abrufen von Dateien und Verzeichnissen, die Sie für den Server benötigen, und wurde zusammen mit einer Remote-Protokollerweiterung eingeführt.

Damit können wir zuerst einen flachen Klon erstellen und dann automatisieren, welche Blobs mit dem Build-System für jeden Build-Typ abgerufen werden sollen.

Es gibt sogar schon ein --filter=blob:limit<size>, mit dem die maximale Größe der abzurufenden Blobs begrenzt werden kann.

Ich habe ein minimales detailliertes Beispiel für das Aussehen der Funktion angegeben: Wie klone ich nur ein Unterverzeichnis eines Git-Repositorys?

Ich suche Meinungen zum Umgang mit großen Binärdateien, von denen mein Quellcode (Webanwendung) abhängig ist. Was sind deine Erfahrungen/Gedanken dazu?

Ich persönlich bin mit einigen meiner Cloud-Hosts auf Synchronisationsfehler mit Git gestoßen, nachdem die Binärdaten meiner Webanwendungen über der Marke von 3 GB eingekerbt wurden. Ich dachte damals an BFT Repo Cleaner , aber es fühlte sich wie ein Hack an. Seitdem habe ich angefangen, Dateien nur außerhalb von Git zu behalten, stattdessen speziell entwickelte Tools wie Amazon S3 für die Verwaltung von Dateien, die Versionsverwaltung und die Sicherung zu verwenden.

Hat jemand Erfahrung mit mehreren Git-Repositorys und deren Verwaltung in einem Projekt?

Ja. Hugo-Themen werden hauptsächlich auf diese Weise verwaltet. Es ist ein wenig kitschig, aber es erledigt die Arbeit.


Mein Vorschlag ist, das richtige Werkzeug für den Job zu wählen. Wenn es für ein Unternehmen ist und Sie Ihre Codeline auf GitHub verwalten, zahlen Sie das Geld und verwenden Sie Git-LFS. Andernfalls könnten Sie kreativere Optionen wie dezentrales, verschlüsseltes Dateispeicherung mit Blockchain ausprobieren.

Zusätzliche zu berücksichtigende Optionen sind Minio und s3cmd .

2
Josh Habdas