- Um die interne Struktur eines Versionsverwaltungssystems zu verstehen, wurde direkt ein Git-ähnliches System implementiert
- SHA-256-Hashing und zstd-Komprimierung ersetzen Git's SHA-1 und zlib; das Repository ist in einer
.tvc-Verzeichnisstruktur organisiert
- Geschrieben in Rust, mit schrittweiser Implementierung von Datei-Hashing, Komprimierung, Commit und Checkout
- Commit-Objekte enthalten Tree-Hash, Parent-Commit, Autor und Nachricht; identische Dateien werden dank Hash-Deduplizierung nicht erneut gespeichert
- Dabei wird unmittelbar erfahrbar, dass Git ein inhaltsadressierter Dateispeicher ist, und die Bedeutung strukturierter Datenformate wird hervorgehoben
Hashing und Komprimierung
- Git identifiziert alle Objekte über SHA-1-Hashes, in diesem Projekt wird jedoch SHA-256 verwendet
- SHA-1 ist alt und sicherheitstechnisch anfällig, aber in diesem Projekt dient es nur zur Identifikation von Dateiinhalten, daher ist Sicherheit nicht entscheidend
- Anstelle von Gits zlib kommt die zstd-Komprimierungsbibliothek von Facebook zum Einsatz
- zstd wurde als effizienter eingeschätzt, Git-Kompatibilität war kein Ziel
- Der Projektname lautet „tvc (Tony’s Version Control)”;
.tvc und .tvcignore übernehmen die entsprechenden Rollen von Git
Implementierungsschritte
- Die Umsetzung erfolgte in der Reihenfolge Kommandozeilenargumente lesen → Ignore-Regeln lesen → Dateiliste ausgeben → Hashing und Komprimierung → Tree- und Commit-Erzeugung → HEAD-Verwaltung → Commit-Checkout
- Das Projekt ist in Rust geschrieben; der
ls-Befehl durchsucht rekursiv alle nicht ignorierten Dateien unter Anwendung der .tvcignore-Regeln und gibt für jede Datei den SHA-256-Hash aus
- Mit der zstd-Bibliothek wurden Funktionen zum Komprimieren und Dekomprimieren von Dateien einfach umgesetzt
Commit-Struktur
- Ein Commit-Objekt enthält folgende Informationen
- Objekttyp („commit”)
- Den Zustand des Dateisystems zu diesem Zeitpunkt (Tree-Hash)
- Den vorherigen Commit (HEAD)
- Den Autor (
author)
- Die Commit-Nachricht
- Anders als bei Git wird nicht zwischen Autor und Committer unterschieden, Merge- oder Rebase-Funktionen wurden nicht implementiert
- Beim Erzeugen eines Commits werden Tree-Objekte erstellt, gehasht, komprimiert und in
.tvc/objects/ gespeichert; anschließend wird die HEAD-Datei aktualisiert
- Identische Dateien werden bei gleichem Hash nicht erneut gespeichert, wodurch Doppelspeicherung vermieden wird
Tree-Objekte und Checkout
- Die Funktion
generate_tree() durchläuft Verzeichnisse, hasht, komprimiert und speichert jede Datei und setzt Dateinamen und Hashes zu Strings zusammen
- Unterverzeichnisse werden rekursiv verarbeitet und so eine Tree-Struktur aufgebaut
- Commit- und Tree-Objekte werden in Strukturen (
Commit, Tree) geparst, damit sie im Speicher leichter verarbeitet werden können
- Die Funktion
generate_fs() rekonstruiert auf Basis der Tree-Struktur das Dateisystem und führt den Checkout in den angegebenen Pfad aus
Erkenntnisse aus dem Projekt
- Git lässt sich direkt als inhaltsadressierter (Key-Value-)Dateispeicher erfahren
- Der schwierigste Teil war das Parsen des Objektformats; beim nächsten Mal sollen klarere Formate wie YAML oder JSON verwendet werden
- Der vollständige Code ist im GitHub-Repository (tonystr/t-version-control) öffentlich verfügbar
Noch keine Kommentare.