Git Internals & The Conceptual Model

Deconstructing Git as a content-addressable filesystem and a Directed Acyclic Graph (DAG).

v1.0.0 Updated: August 26, 2026

The Content-Addressable Filesystem

The most common misconception among early engineers is that Git tracks changes or diffs between files. It does not. Git is fundamentally a content-addressable filesystem.

Instead of tracking the delta between two states, Git takes a complete snapshot of your entire project at a given moment. If a file has not changed, Git does not store a second copy; it simply stores a link to the previous identical file. Every object in this filesystem is addressed by the SHA-1 cryptographic hash of its contents.

The Four Core Objects

Under the hood (inside the .git/objects directory), Git relies on just four internal data structures to model the entire history of a repository:

  1. Blobs (Binary Large Objects): Represents the raw content of a file. It contains no metadata—not even the file name.
  2. Trees: Represents a directory structure. A tree object contains pointers to blobs and other trees, mapping file names to their respective blob hashes.
  3. Commits: A snapshot of the top-level tree. It contains metadata (author, timestamp, commit message) and, crucially, a pointer to its parent commit(s).
  4. References (Refs): Human-readable pointers to specific commit hashes (e.g., branches, tags, and HEAD).
💡
Architectural Note: Because branches are merely 40-character text files containing a commit hash, creating a branch in Git is an $O(1)$ time complexity operation. It costs virtually zero memory or computation.

System Visualization: The Directed Acyclic Graph (DAG)

Because each commit points to its predecessor, the commit history forms a specific mathematical structure: a Directed Acyclic Graph (DAG). Time flows strictly in one direction, and a node (commit) can never loop back to point at a future state.

Here is how Git visualizes a merge physically in the graph:

graph LR C1((Commit 1)) --> C2((Commit 2)) C2 --> C3((Commit 3: Main)) C2 --> F1((Feature A)) F1 --> F2((Feature B)) C3 --> M((Merge Commit)) F2 --> M style M fill:#dbeafe,stroke:#3b82f6,stroke-width:2px style C3 fill:#f8fafc,stroke:#cbd5e1 style F2 fill:#f8fafc,stroke:#cbd5e1

When you execute a merge, Git is simply creating a new node in the graph (the Merge Commit) that possesses exactly two parent pointers.

The Avalanche Effect of Cryptographic Hashing

Because a commit object contains the hash of its parent, altering historical data in Git is mathematically destructive.

If you attempt to modify the timestamp or the file contents of Commit 1 from a year ago, its SHA-1 hash will change. Because Commit 2 points to the hash of Commit 1, modifying Commit 1 invalidates Commit 2, forcing Commit 2 to generate a new hash. This cascade alters every subsequent commit all the way to HEAD, entirely rewriting the repository’s history.

Test Your Understanding

Q:If two separate engineers on completely isolated machines write the exact same python script (identical characters and line breaks), and they both commit it to their local Git repositories, what will be true about the blob hashes? Reveal ▾
The blob hashes will be mathematically identical. Because Git is a content-addressable system utilizing SHA-1 hashing, identical content will invariably produce the identical 40-character hash, regardless of the repository, operating system, or commit author.

Further Exploration

← Previous
The Shift to Engineering Discipline
Next →
Branching as Architectural Design