Curious Pandas

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.

15 min+40 XP for finishing

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.

Visual guideWhat one commit points at
What one commit points atA commit points at a tree and at its parent commit. The tree lists file names, each pointing at a blob of contents. Two files with identical contents point at the same blob.commitHEADtreethe folder listingblobstored onceblobdifferent bytesparent commitHEAD~1treea.txt, b.txtnotes.txtparentWhat one commit points atA commit points at a tree and at its parent commit. The tree lists file names, each pointing at a blob of contents. Two files with identical contents point at the same blob.commitHEADtreethe folder listingblobstored onceblobdifferent bytesparent commitHEAD~1treea.txt, b.txtnotes.txtparent
  1. Start at HEAD: a commit. It holds an author, a time, a message - and two hashes.
  2. The first hash names a tree: the folder listing. Names live here, never in the files themselves.
  3. Each name points at a blob of bytes. Two files with identical contents point at the same blob, so it is stored once.
  4. 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.

Plumbingreal git hashes
Working tree
    Staging area
      Last commit
        Commit graph

        No commits yet.

        Check yourself+10 XP

        Where does git store a file's name?

        Check yourself+10 XP

        Someone edits a commit from last month and force-pushes. Why does everyone's later history now look different?

        Do it for real · your machine+50 XP bonus

        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 | head

        Git is moving from SHA-1 to SHA-256 (git init --object-format=sha256). Same design, longer names.

        Self-reported. We can't see your machine, and we don't want to. This is a bonus, never required.

        Sources

        Finished reading?

        Missions and quizzes above earn their own XP. This marks the lesson done.