Lesson 1 of 30
Git isn't a list of diffs — it's a content-addressable store of snapshots. Once that clicks, every command stops being magic.
15 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
Most people learn Git as a sequence of memorized commands and quietly assume it's storing a diff per commit — a record of "what changed" — the way older tools like SVN did. It isn't. Git stores a full snapshot of your entire project at every commit, and it's smart enough to reuse any file that didn't change between snapshots so the storage stays cheap.
Underneath, Git is a simple key-value store. Every piece of content — a file's contents, a directory listing, a commit — gets hashed (SHA-1, or SHA-256 on newer repos) and saved under that hash as its key. This is called content-addressable storage: the name of a piece of data is a fingerprint of its content. Change one byte, and you get a completely different hash — the old object is untouched, and a new one is written alongside it.
There are three object types you'll actually deal with:
git log able to walk history backward.This isn't theoretical — you can open the store directly.
$ mkdir demo && cd demo && git init
Initialized empty Git repository in demo/.git/
$ echo "hello" > file.txt
$ git add file.txt
$ git commit -m "add file"
[master (root-commit) a1b2c3d] add file
1 file changed, 1 insertion(+)
Now look at what actually got written to .git/objects:
$ git cat-file -t a1b2c3d
commit
$ git cat-file -p a1b2c3d
tree 9daeafb9864cf43055ae93beb0afd6c7d144bfa4
author Adesh <adesh@example.com> 1710000000 +0530
committer Adesh <adesh@example.com> 1710000000 +0530
add file
That tree line is a real object, hashed and stored right next to the commit. Follow it:
$ git cat-file -p 9daeafb9864cf43055ae93beb0afd6c7d144bfa4
100644 blob ce013625030ba8dba906f756967f9e9ca394464 file.txt
And follow that hash to get the actual file content back, byte for byte:
$ git cat-file -p ce013625030ba8dba906f756967f9e9ca394464
hello
That's the whole model: a commit points to a tree, a tree points to blobs (and other trees, for subdirectories), and a blob is just content. a1b2c3d isn't an id Git made up and tracked in a table somewhere — it's the SHA-1 hash of the commit object's own contents (tree hash + parent + author + message). If any of that changes, the hash changes, and it becomes a different commit.
git diff, git log -p) by comparing two trees. The diff view is a convenience, not the storage format.file.txt in ten different commits without editing it, all ten trees point at the exact same blob hash — Git doesn't duplicate it.main is a 41-byte file in .git/refs/heads/main holding a single hash. Branching is cheap precisely because it never copies any snapshot data.The content-addressable store here is the same idea behind any hash-based cache or deduplication system: content in, hash out, and identical content always collapses to the same key. Once you see Git as "a hash table of immutable snapshots plus a chain of pointers," commands like checkout, branch, and merge stop being separate tricks to memorize — they're all just operations on pointers into that same object graph.