Git Internals & The Conceptual Model
Deconstructing Git as a content-addressable filesystem and a Directed Acyclic Graph (DAG).
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:
- Blobs (Binary Large Objects): Represents the raw content of a file. It contains no metadata—not even the file name.
- Trees: Represents a directory structure. A tree object contains pointers to blobs and other trees, mapping file names to their respective blob hashes.
- Commits: A snapshot of the top-level tree. It contains metadata (author, timestamp, commit message) and, crucially, a pointer to its parent commit(s).
- References (Refs): Human-readable pointers to specific commit hashes (e.g., branches, tags, and
HEAD).
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:
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.