Grit

A modular version control system with unique architecture.

Repositories: 🐙 grit

Context & Motivation

Context: Grit is a from-scratch Git implementation in Rust, providing both low-level plumbing commands (hash-object, cat-file, write-tree, read-tree, update-ref) and high-level porcelain commands (init, add, commit, log, status, diff, branch, checkout, reset). The architecture follows Git’s own layered design where porcelain is composed entirely from plumbing primitives.

Motivation: We often take Git for granted, yet its ubiquity often obscures the elegance of its underlying content-addressable storage model. Building a Git implementation from scratch is a deep systems challenge—requiring a rigorous understanding of object models (blobs, trees, commits), storage formats (SHA-1, zlib), and the index structure. This project aims to achieve full format compatibility while optimizing for performance and structural clarity.

The Local Implementation

  • Current Logic: The architecture mirrors Git’s canonical layered design. The object model implements blobs, trees, and commits as typed Rust structs, utilizing SHA-1 hashing and zlib compression via flate2. Items persist in .grit/objects/ using standard loose object formatting. The index (staging area) maintains a sorted entry list, guaranteeing binary compatibility with Git’s DIRC v2 format.
  • Plumbing/Porcelain Split & CLI Tooling:
    • Plumbing Primitives: hash-object, cat-file, write-tree, read-tree, and update-ref expose direct object and ref manipulations for scripts and internal commands.
    • Porcelain Workflows: Porcelain commands compose plumbing operations without direct filesystem manipulation of .grit/objects/. Recent additions include grit branch (listing, creation, -d deletion), grit checkout (branch switching, branch creation -b, detached HEAD detection), grit reset (supporting --soft, --mixed, and --hard), grit log (with -n / --max-count capping and --oneline), and grit diff (arbitrary commit revision comparisons, --staged/--cached index inspection, and --stat summaries).
  • Ignore Engine & Working Tree Traversal: A native .gritignore pattern matcher parses gitignore-compliant glob patterns, automatically excluding build directories (target/), caches, and temporary files during both grit add staging and grit status tree inspection.
  • LRU Caching & Concurrency Discipline: An in-memory LRU cache (lru crate, default 1,024 entries) initialized via std::sync::LazyLock accelerates repeated object lookups. Tree objects are cached independently to avoid redundant $O(\text{depth} \times \text{files})$ traversals during status and diff calls. Working tree scans yield cache hit rates above 80% on stable trees.
  • Comprehensive Criterion Benchmark Suites: Performance is profiled through three dedicated Criterion benchmark suites with profile-guided compiler flags (opt-level = 3, lto = true, codegen-units = 1):
    • Command Comparison: Micro-benchmarks against native git demonstrate 3–4× speedups for small repositories (init ~2.1ms at 4.1×, add ~4.1ms at 3.4×, status ~5.4ms at 3.3×, commit ~6.0ms at 4.2×).
    • Index Operations: Profiles DIRC v2 binary serialization, tracking read/write throughput and latency across indices scaling from 100 to 10,000 entries.
    • Diff Operations: Profiles Myers diff computation over line deltas and tree comparisons, ensuring low latency during large refactor sweeps.
  • Bottleneck: Performance scaling for very large repositories (100k+ objects) depends on efficient packfile support, which is not yet implemented—all objects are stored as loose zlib-compressed files.

Comparison to Industry Standards

  • My Project: High-performance, educational Git implementation emphasizing the plumbing/porcelain architecture, LRU caching for read performance, modular integration testing, and property-based correctness.
  • Industry: Git itself is backed by decades of optimization—packfile deltification, reachability bitmaps, and multi-pack indices (MIDX). libgit2 provides ubiquitous C bindings, and gitoxide offers a modular, high-concurrency Rust ecosystem.
  • Gap Analysis: With .gritignore, branch, checkout, reset, and revision diffing fully operational, the remaining architectural gaps include packfile support (delta compression and .idx pack-index parsing), three-way merge algorithms (merge and rebase), and network transport protocols (smart HTTP / SSH for fetch and push).

Risks & Mitigations

  • Compatibility issues: strict adherence to Git’s object and index formats with byte-level tests. Run grit operations on repositories created by Git and verify with git fsck that no corruption is introduced.
  • Performance regressions: Criterion benchmarks run in CI with statistical comparison. Alert on P95 regressions exceeding 5%. Monitor cache hit rates—a sudden drop indicates a code change is bypassing the cache.
  • Large repo degradation: without packfiles, storage grows linearly with object count. Document the current limitation and recommend grit for repositories under 10k objects.
  • Index corruption: validate index invariants (sorted entries, no duplicates, valid modes) on every read and write. Fail fast with a clear error rather than silently producing a malformed index that Git can’t read.