<aside> 🔀

Module 3 — How Git Stores Your Work (objects, refs, git cat-file). This is the shortest module and the highest-leverage one. Branches, merges, resets, and recovery all stop being magic once you have seen what a commit physically is. One hour here saves ten hours of confusion later — and it is where interviews separate command-memorizers from engineers.

🧠 concept → 🧩 analogy → 🧪 exercise → ✅ expected result (hidden) → 🎯 interview questions (hidden)

</aside>

<aside> 🚦

Before you start. You need Module 1 (Git configured) and Module 2 — this module reads the actual kitchen repository you built there, so have it on disk. If you skipped ahead, do Module 2's exercises first; the object IDs below depend on them.

</aside>

<aside> 🖼️

This page contains Mermaid diagram blocks. Notion shows them as code by default — click the block and switch it to Preview to see the diagram. You only need to do this once per block.

</aside>

Part A — The object database

A1. Plumbing and porcelain

<aside> 📖

Official docs: Git Book §10.1 — Plumbing and Porcelain

</aside>

Git is two layers. The commands you have used so far — add, commit, status — are porcelain: the polished, human-facing layer (the term is bathroom humor: porcelain is the fixture you touch). Underneath is plumbing: low-level commands that operate directly on Git's storage, one small job each. Porcelain commands are combinations of plumbing calls. In this module you will use two plumbing commands — git hash-object (compute an object's ID) and git cat-file (read an object back) — not because daily work needs them, but because they let you watch the machine run. Everyday Git never requires plumbing; understanding Git deeply requires having used it once.

Where does plumbing operate? Inside the .git directory from Module 2. Look at its layout — every name in it will mean something by the end of this page:

🧪 Exercise 3.1 — the filing room's floor plan

cd ~/git-course/kitchen
ls .git

A2. Blobs — content under its own fingerprint

<aside> 📖

Official docs: Git Book §10.2 — Git Objects · git-hash-object manual

</aside>

Git's database stores objects. The simplest kind is the blob: a file's content, nothing else. Not its filename, not its timestamp, not who wrote it — bytes only. Every object is stored under a name that Git computes from the content itself: the SHA-1 hash, 40 hexadecimal characters. Feed identical bytes to the hash, get the identical name, on any machine, any year. Change one character and the name changes completely. This scheme is called content-addressed storage, and it is the single design decision that everything else in Git falls out of.

Two consequences arrive immediately. Deduplication: if two files (or two commits' versions of one file) have identical content, they hash to the same name — so the database physically stores that content once. Integrity: the name is a checksum. If a disk error flips a bit inside an object, its content no longer matches its name, and Git notices the moment it reads the object.

🧪 Exercise 3.2 — hash content and see determinism

cd ~/git-course/kitchen
echo "flour, water, salt" | git hash-object --stdin   # hash these bytes
echo "flour, water, salt" | git hash-object --stdin   # ...again
echo "flour, water, salt!" | git hash-object --stdin  # one character added

<aside> 🧠

Counter-intuitive: blobs have no filenames. recipe.txt is nowhere inside the blob 0fd697a… — the blob is the bytes flour, water, salt and nothing more. Filenames live one level up, in tree objects (B2). This is why Git's rename detection (Module 2, C2) is inference: a rename never gets recorded anywhere — the same blob simply appears under a different name in the next tree, and Git spots the reuse. It is also why ten identically-configured files across a repo cost one blob, not ten.

</aside>