Really Big Data – Git, der Speicher und Shallow Clones

Git ist schnell.. das steht ausser Frage. Und man weiß das vor allem dann zu schätzen, wenn man sich bereits mit anderen Systemen herumschlagen musste (genau Subversion, ich rede mit dir!).

Machen wir einige Experimente.

Eine voller clone mit Git für meinen Fork des das Apache Wicket – Repositories dauert mehr als 2 Min.

Cloning into '~/development/git/playground/test-full-wicket-clone.git'...
remote: Counting objects: 298876, done.
remote: Compressing objects: 100% (76833/76833), done.
remote: Total 298876 (delta 177768), reused 298612 (delta 177572)
Receiving objects: 100% (298876/298876), 77.15 MiB | 689.00 KiB/s, done.
Resolving deltas: 100% (177768/177768), done.
Checking connectivity... done.

real	2m4.785s
user	0m10.535s
sys	0m9.090s

Dasselbe dauert mit einem Shallow-Clone nur 11 Sekunden, wenn wir uns nur den HEAD holen.

git clone --depth 1 http://github.com/dilgerma/wicket.git ~/development/git/playground/test-shallow-wicket.git
Cloning into '~/development/git/playground/test-shallow-wicket-clone.git'...
remote: Counting objects: 5946, done.
remote: Compressing objects: 100% (4821/4821), done.
remote: Total 5946 (delta 2319), reused 2463 (delta 647)
Receiving objects: 100% (5946/5946), 5.14 MiB | 669.00 KiB/s, done.
Resolving deltas: 100% (2319/2319), done.
Checking connectivity... done.

real	0m11.547s
user	0m0.693s
sys	0m0.923s

Im Full-Clone haben wir 18253 Commits, im Shallow-Clone wie erwartet 1.

 git log --pretty=oneline | wc -l

Speicher

Der Full-Clone benötigt 116 MB, der Shallow-Clone 36 MB. Interessanterweise immerhin nicht ganz ein Drittel.

Von den 36 MB nimmt im Shallow-Clone 30 MB der Workspace ein und 6 MB die restliche Historie und Meta-Daten.
Der Workspace belegt also ca. 16 %.

Von den 116 MB nimmt im Full-Clone der Workspace 30 MB ein, 86 MB die restliche Historie mit Meta-Daten.
Der Workspace belegt hier also ca. 34 %.

Betrachten wir die Datenstruktur im Shallow-Clone.

git cat-file -p HEAD
tree 909fcce737320515dc35455ffedd1c36eab9f9c4
parent 1d64d4ccfa9d1114986594ffd8f68cb6e41c09bc

...

Im Shallow-Clone ist die parent-Referenz auf den Commit 1d64d4ccfa9d1114986594ffd8f68cb6e41c09bc gesetzt.

Betrachten wir diesen Commit.

git cat-file -p 1d64d4ccfa9d1114986594ffd8f68cb6e41c09bc
fatal: Not a valid object name 1d64d4ccfa9d1114986594ffd8f68cb6e41c09bc

Das Objekt ist wie erwartet nicht vorhanden, da wir uns nur den HEAD geholt haben während derselbe Befehl im Full-Clone problemlos funktioniert.

git cat-file -p 1d64d4ccfa9d1114986594ffd8f68cb6e41c09bc
tree 0535a7a9e83b068ed24e16ba93bd8e7508628b32
parent 9716f2a7e799133fdf3f7927d0093e6dfe16f529

Ein FileCheck im Shallow-Clone untersucht 5968 Objekte und meldet, dass alles in Ordnung ist.

git fsck
Checking object directories: 100% (256/256), done.
Checking objects: 100% (5968/5968), done.

Derselbe FileCheck im Full-Clone untersucht 298876 Objekte.

git fsck
Checking object directories: 100% (256/256), done.
Checking objects: 100% (298876/298876), done.

Git hat die ganze Repository-Struktur bereits gepackt geladen in einem Pack-File.
Entpacken wir das Pack-File und betrachten, wie sich der Speicherverbrauch ändert. Um
das Pack-File entpacken zu können müssen wir es aus dem Repository entfernen – Git ist so klug und entpackt die Datei gar nicht erst, wenn
das Pack-File schon vorhanden ist.

ls .git/objects/
info	pack

# das pack-file und das index-file
ls .git/objects/pack/
pack-9d45af9c3e410ebf3328dbe303c99389fc1fe899.idx	pack-9d45af9c3e410ebf3328dbe303c99389fc1fe899.pack

mv .git/objects/pack/pack-9d45af9c3e410ebf3328dbe303c99389fc1fe899.pack /tmp/shallow.pack
time git unpack-objects < /tmp/shallow.pack 
Unpacking objects: 100% (5946/5946), done.

real	0m1.984s
user	0m0.624s
sys	0m1.317s

#die Objekte sind jetzt entpackt
ls .git/objects/
00	0c	18	24	30	3c	48	54	60	6c	78	84	90	9c	a8	b4	c0	cc	d8	e4	
#...

Das entpackte Archiv im Shallow-Clone hat eine Größe von 57 MB. Immerhin hat zusätzliche Packen in das Pack-File 21 MB zusätzlich gespart. Immerhin  knapp  36 %.

Versuchen wir das Ganze mit dem Full-Clone, was immerhin 2 Minuten und 21 Sekunden dauert.

time git unpack-objects < /tmp/full.pack
Unpacking objects: 100% (298876/298876), done.

real	2m21.436s
user	0m30.239s
sys	1m12.420s

Das Repository hat jetzt eine Dateigröße von 1,3 GB im Vergleich zu den 105 MB zuvor. Das zusätzliche Packen im Pack-File hat also nochmal zusätzlich 92% Speicherplatz eingespart.

Ein entpackter Workspace nimmt dadurch aber allein lediglich 2% des kompletten Repositories im Full-Clone ein.

TIPP:

Übrigens ist es seit Git 1.9 problemlos möglich, auch mit Shallow-Clones zu arbeiten.

#hack something
git commit -m "just a test commit"

git push origin master
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 316 bytes | 0 bytes/s, done.
Total 3 (delta 2), reused 0 (delta 0)
To http://github.com/dilgerma/wicket.git
   db5be6a..81cecb7  master -> master

Die Historie sieht genauso aus wie erwartet.

git log
Commit:  81cecb7d4f84b3c9671826953a21e79e8e49051a
Author:  dilgerm <martin@effectivetrainings.de>
Date:    (2 minutes ago) 2014-10-21 20:14:35 +0200
Subject: just a test commit


Commit:  db5be6ab05545e1bb95f566c3aeb23e05cf93437
Author:  
Date:    (7 hours ago) 2014-10-21 12:47:38 +0200
Subject: WICKET-5730 Dequeue auto component can't resolve components if they are nested in child markup

Entscheiden wir uns jetzt, unseren Shallow-Clone zu einem echten Git-Repository zu machen.

 git pull --unshallow

remote: Counting objects: 292930, done.
remote: Compressing objects: 100% (75907/75907), done.
remote: Total 292930 (delta 175484), reused 290333 (delta 173030)
Receiving objects: 100% (292930/292930), 72.10 MiB | 681.00 KiB/s, done.
Resolving deltas: 100% (175484/175484), completed with 1564 local objects.
Current branch master is up to date.

Use Cases – Shallow Clone

Gibt es also Use-Cases für Shallow-Clones?

Selbstverständlich.

CI-Server

Es gibt überhaupt keinen Grund, dass ein CI-Server einen Full-Clone eines Repositories macht. Hier reicht ein Shallow-Clone mit einer Tiefe von 1. Wir sehen schon, in einem mittelgroßen Projekt bringt dies eine Zeitersparnis von  92% beim Clone.

Und mein Build ist schon mal zwei Minuten schneller ohne dass ich eine Änderung am Projekt vornehmen muss.  Zwei Minuten sind eine Ewigkeit.

Zusätzlich sparen wir uns knapp 60% Speicher. Bei vielen Projekten kann das durchaus ausschlaggebend sein. Ich kann gar nicht zählen wie oft mir schon in Projekten die Platte des Jenkins vollgelaufen ist.

Quick Fixes

Für die normale Arbeit im Projekt würde ich persönlich nicht auf Shallow-Clones zurückgreifen, denn hier spielt die Zeit für den Clone und Speicher eine untergeorndete Rolle. Ist dies nicht der Fall ist Ihr Projekt entweder VIEL ZU GROSS oder Ihr Rechner VIEL ZU KLEIN.

Um aber einen schnellen Blick in den Source-Code eines Projektes zu werfen sind Shallow-Clones durchaus interessant.

Möchten Sie noch mehr über die Internals von Git erfahren kann ich Ihnen mein Buch Daily Git empfehlen.

Natürlich können Sie mich auch für ein Git Training buchen. Rufen Sie mich gerne einfach an.

Effective Trainings & Consulting - Martin Dilger



Hat Ihnen dieser Blog-Eintrag gefallen? Ich stelle in diesem Blog Informationen über Tools, Frameworks und Werkzeuge zur Verfügung, die mich produktiver machen. Vielleicht kann ich auch Ihnen helfen, produktiver zu werden.


Ich unterstütze Sie als freier Mitarbeiter bei der Entwicklung von Software-Projekten, Agiler Arbeit sowie Schulungen / Fortbildungen.


Jeden Tag ein bisschen produktiver - ab heute