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.