Backend & Data
Git internals — commits, trees, and blobs
Most people learn Git as a list of spells: add, commit, push, and the dreaded rebase. Memorise the incantations and hope. But underneath, Git is startlingly simple — a content-addressed key-value store with just three object types. Learn those, and the commands stop being magic and start being obvious consequences of how the data is shaped.
Everything is an object, named by its hash
Git stores everything as objects in a database, and each object's name is the SHA hash of its contents. Same content → same hash → stored once. There are three kinds that matter:
- Blob — the raw contents of a file. Just bytes; no filename, no history.
- Tree — a directory listing: filenames mapped to blobs (and to other trees for subfolders). This is where names live.
- Commit — a snapshot: it points to one tree (the whole project state), plus metadata — author, message, and the hash of its parent commit.
History is a chain of snapshots
Here's the mental unlock: a commit is a full snapshot, not a diff. Each commit points to its parent, so the history is a chain (a branch is nothing more than a lightweight pointer to one commit). Git shows you diffs by comparing two snapshots on the fly, but it stores whole trees — deduplicated by hash, so an unchanged file across a thousand commits is stored once.
Git is a bag of objects named by their content hash. Blobs are file contents, trees are folder listings, commits are snapshots that point to a tree and to the previous commit. History is just commits linked parent-to-parent.
Why this makes commands click
- A branch is a 41-byte file holding one commit hash. That's why branching and switching are instant — nothing is copied.
- A merge makes a new commit with two parents; a rebase replays your commits onto a new base, creating fresh commit objects (new hashes — which is why you don't rebase shared history).
- HEAD is just a pointer to "where you are now." Detached HEAD simply means it points straight at a commit instead of a branch.
- "Lost" commits usually aren't — the objects linger in the database, findable via
reflog, until garbage collection reaps the unreachable ones.
Git isn't hard because it's complex; it's hard because it's usually taught as commands to memorise rather than a data model to understand. Once you can picture the objects — content-addressed blobs, trees, and a chain of commit snapshots — the scary operations become simple pointer manipulations, and the whole tool turns from a source of anxiety into something you can reason about.