Dateitypen, die sich nicht effizient in Git-Repositories nutzen lassen, sind Binärdateien. Also genau die Dateien, die man nicht mit einem gängigen Texteditor öffnen kann. Mit Git LFS kann man Binärdateien effizienter verwalten, dabei ist Git LFS eine Erweiterung für den Git-Client, ein entsprechendes Gegenstück wird aber auch auf dem Server benötigt.

Doch bevor man sich Git LFS anschaut, sollte man verstehen, wie Git Dateien intern abspeichert, um nachvollziehen zu können, warum man eine Lösung wie Git LFS braucht.

Git Interna

Diejenigen, die wissen wie Git intern die Dateien verwaltet, können diesen Abschnitt getrost überspringen.

Git ist ein verteiltes Versionskontrollprogramm, dementsprechend müssen alle Änderungen, die im Repository getätigt wurden, auch lokal vorliegen. Git speichert dazu jede neue oder veränderte Datei einmal komplett im Repository ab. Aus Geschwindigkeitsgründen werden nicht anwendbare Diffs speichert, sondern eben die kompletten Dateien.

Konkret heißt es, dass wenn in einem neuen und leeren Repository eine neue Datei in einem Commit hinzugefügt wird, dann komprimiert Git die Datei und schiebt es einfach gesagt irgendwo in den .git Ordner. Wenn reine Textdateien vorhanden sind, was bei Software-Quellcode durchaus der Fall ist, dann funktioniert das ganz gut, da so wenig Speicherplatz belegt wird. Wenn die besagte Textdatei verändert wird und die Änderung in das Repository committed wird, dann speichert Git die Datei ebenfalls komplett neu ab. Beim Auschecken des Commits davor, muss Git nur die andere Datei wieder dekomprimieren und in das Arbeitsverzeichnis schieben. Das geht gewöhnlich recht schnell.

Jetzt sollte man erkennen, warum man ohne Git LFS Binärdateien nicht verwenden sollte: Git speichert auch Binärdateien bei jeder Änderung neu im Repository ab. Da sich Binärdateien meist nicht so effizient komprimieren lassen, wie es bei Textdateien der Fall ist, ist die Komprimierung nahezu nutzlos. Bei einer Binärdatei die 50mb groß ist und 10 Mal verändert wurde (jeweils mit Commits), dann ist ein Repository schon mit etwa 500mb belegt. Je häufiger man also Binärdateien verändert, desto größer wird das Repository, was demnach auch viel Platz auf dem Datenträger belegt.

Und genau hier kommt Git LFS ins Spiel.

Git LFS

LFS steht für „Large File Storage“ und ist eine Erweiterung von Git, das betrifft sowohl den Client als auch den Server. Leider befinden sich für Git LFS keine Pakete in den Paket-Repositorys der gängigen Linux-Distributionen, weshalb man sich Git LFS via packagecloud.io installieren muss.

Nachdem man sich die Git LFS installiert hat, kann es in den Repositorys genutzt werden. Wie zuvor erwähnt, braucht der Server auf der Gegenseite ebenfalls Unterstützung für Git LFS. Das gute ist, dass es die gängigen und bekannten Git-Hosting-Dienste anbieten. Das betrifft insbesondere GitHub, GitLab, Bitbucket und Gogs/Gitea.

Der Einsatz von Git LFS muss in jedem Repository einmal konfiguriert werden. Dies geht ganz einfach:

$ git lfs install

An dieser Stelle ist noch nicht viel passiert, denn es muss noch konfiguriert werden, welche Dateien von Git LFS beachtet werden sollen. Wenn man häufiger mit Bildern hantiert, dann sind es zum Beispiel *.jpg Dateien. Alternativ können natürlich auch einzelne Dateinamen angegeben werden.

$ git lfs track "*.jpg"

Git LFS legt dabei die Datei .gitattributes im Arbeitsverzeichnis ab, die man auf jeden Fall mit in das Repository schieben muss. Der Inhalt der Datei sieht in diesem Beispiel so aus:

*.jpg filter=lfs diff=lfs merge=lfs -text

Anschließend kann man noch ein Remote-Repository anlegen, was Git LFS unterstützt, um anschließend JPG-Dateien zu versionieren. Das ganze lässt sich dann auch einfach testen: Einfach ein (größeres) Bild mit nehmen, es Committen und Pushen und anschließend die Dateigröße vom .git Verzeichnis anschauen. Das ganze sollte man wiederholen und dabei das Bild häufiger anpassen, um mehrere Versionen zu erzeugen. Wenn man dies tut, dann sieht man recht schnell, dass die Größe des Repositorys nicht wesentlich zunimmt. In meinen Tests ergab sich aber auch, dass das lokale Repository manchmal trotzdem größer geworden ist, allerdings werden bei einem frischen Klon oder beim Pullen nicht alle Versionen der Binärdatei heruntergeladen.

Git LFS funktioniert somit recht einfach, man muss nur die Dateien bzw Dateitypen angeben, die von Git LFS getrackt werden sollen. Anschließend kann man wie gehabt Commits tätigen und Pushen und im Hintergrund arbeitet Git LFS vor sich hin. Kompliziert ist das ganze dann nicht.

Funktionsweise

Bisher haben wir zwar die Probleme von Binärdateien in Git-Repositorys dargelegt und gezeigt wie man Git LFS nutzt. Allerdings wurde noch nicht gezeigt, wie das nun intern im Groben funktioniert. Statt die Binärdatei selbst im Repository abzuspeichern, speichert Git LFS nur einen Pointer auf die große Datei ab, die auf den LFS-Server zeigt. Diese Pointer sind dabei recht klein, da es eben nicht die ganze Binärdatei ist. Bei einem Push werden dann die Binärdateien zum LFS-Server hochgeladen und das reine Repository vom normalen Git-Server. Beim Auschecken eines Branches oder eines bestimmten Commits, werden die Versionen dann im Hintergrund vom LFS-Server geladen und im Arbeitsverzeichnis ersetzt. Somit werden nur die Binärdateien geladen, wie man zu dem Zeitpunkt wirklich braucht.

Durch den Einsatz von Git LFS kann man so recht einfach auch Binärdateien verwalten, verliert dadurch aber auch die Möglichkeit auf alle Revisionen einer Binärdatei offline zuzugreifen. Da man häufig sowieso online ist, dürfte das meistens kein allzu großes Problem sein. Nichtsdestotrotz sollte man sich bewusst sein, wann man Git LFS einsetzt und für welche Dateien bzw. Dateitypen. Idealerweise verwaltet man nämlich weiterhin in Software-Projekten nur reinen Quellcode. Für große Fotos oder anderen Binärdateien kann Git LFS aber eine gute Alternative sein.