Look inside .git
Blobs, trees and commits. Three kinds of object, each named by its own hash. Take a commit apart and find two files sharing one blob.
Git is a small database with three kinds of object in it, each one stored under the hash of its own contents:
| Object | Holds | Points to |
|---|---|---|
| blob | the bytes of one file, with no name attached | nothing |
| tree | a directory listing: names, modes, and the hashes of blobs and sub-trees | blobs and trees |
| commit | a tree, its parent commit(s), author, time and message | a tree and parents |
That’s all git stores. A filename lives in a tree, not in the blob. So two files with identical contents share one blob, however many folders they’re in.
There’s one more consequence. A commit names its tree and its parent by hash, and the parent names its parent, and so on. Change anything in history and every hash after it changes. That’s why nobody can quietly rewrite git history: the names would stop matching.
- Start at HEAD: a commit. It holds an author, a time, a message - and two hashes.
- The first hash names a tree: the folder listing. Names live here, never in the files themselves.
- Each name points at a blob of bytes. Two files with identical contents point at the same blob, so it is stored once.
- The second hash names the parent commit. Change anything older and every hash after it changes.
Take a commit apart
This repository has three files, and two of them have identical contents. git cat-file -p prints any object by hash. Start at HEAD and work down.
Where does git store a file's name?
Blobs are pure content. The name, and the mode (file or folder), live in the tree entry that points at the blob. That's why identical contents can share one blob under many names.
Someone edits a commit from last month and force-pushes. Why does everyone's later history now look different?
Hashes chain. A changed commit gets a new hash, so its child must record a different parent, which changes the child's hash, and so on to the tip. This chaining is the same idea behind other tamper-evident logs.
Everything above ran in your browser. Now do it on a real cluster withthe tilt platform. You need Docker, kind and Tilt, about 15 GB of free disk and 8 GB of spare RAM. Setup guide · Can my machine run it?
In any repository:
git cat-file -p HEAD
git cat-file -p HEAD^{tree}
ls .git/objects | headGit is moving from SHA-1 to SHA-256 (git init --object-format=sha256). Same design, longer names.
Sources
Missions and quizzes above earn their own XP. This marks the lesson done.