Topic 8.1
The Object Model: Blobs, Trees, Commits & Refs
In one line
Everything Git stores is one of four object types, named by the hash of its content. Branches and tags are just small files pointing at commits. Seeing this with plumbing commands makes Git fully explainable.
Think of it like this
A library that files every page by a fingerprint of its text. Identical pages are stored once, any change produces a new fingerprint, and a 'book' (commit) is just a list of fingerprints plus a note saying which book came before it. A bookmark (branch) is a sticky note naming one book.
Key ideas
- 01
BLOB: the contents of a file (no name, no permissions). TREE: a directory listing mapping names and modes to blobs and sub-trees. COMMIT: a pointer to one root tree, zero or more parent commits, author/committer, and message. Annotated TAG: a named, signed-able pointer to an object. Each object's ID is the hash of its content (SHA-1 today, SHA-256 supported), so identical content is stored once and history can't be altered silently.
- 02
REFS are files (or entries in
packed-refs) containing a commit hash:refs/heads/main,refs/tags/v1.2.0,refs/remotes/origin/main.HEADusually containsref: refs/heads/main(a symbolic ref); a 'detached HEAD' contains a hash directly. Creating a branch is writing a 41-byte file, which is why branches are cheap. - 03
A commit snapshots the whole tree, not a diff; diffs are computed when you ask. Unchanged files point to the same blobs, so snapshots are cheap. Packfiles (Topic 8.2) compress similar objects as deltas on disk.
- 04
PLUMBING commands expose this:
git cat-file -p <hash>(print an object),git ls-tree,git rev-parse main,git hash-object,git write-tree,git commit-tree. You won't use them daily, but they make everything else make sense.
Code & diagrams
git rev-parse HEAD # b7e1c0…
git cat-file -t HEAD # commit
git cat-file -p HEAD # tree 9c4d… parent a3f0… author … message
git cat-file -p 'HEAD^{tree}' # 100644 blob 5e1a… README.md / 040000 tree … src
cat .git/HEAD # ref: refs/heads/main
cat .git/refs/heads/main # b7e1c0… (or see .git/packed-refs)Explain it without notes
Why are Git branches so cheap to create?
Why does changing one byte of an old commit change the IDs of every later commit?
Practice
Using only plumbing commands, show the content of README.md as it was three commits ago.
Done when you can
I can explain blobs, trees, commits, tags, and refs
I can inspect objects with cat-file and ls-tree