🔧 Git & GitHub FoundationTheory · Part 3 of 7

"Git doesn't store file versions — it stores a graph of snapshots linked by fingerprint. The magic is just maths."

The Filing Cabinet Inside .git

Every git add and git commit you've run wrote a file into .git/objects/. Open that folder after a commit and you'll find something like this:

.git/objects/
├── a3/
│   └── f7b21c9e4d5f8b1a2c3d4e5f6789012345678
├── 4b/
│   └── 825dc642cb6eb9a060e54bf8d69288fbee4904
└── f2/
    └── ba8f84ab5c1bce84a7b441cb1959cfc7093b7f

Each file is a Git object — data compressed and named by its SHA-1 hash. The first two characters become the directory; the remaining 38 become the filename. Git's entire history is a folder of compressed files, each named after a fingerprint of its own content.

Two consequences follow immediately:

  • Same content always produces the same hash. If two files contain identical bytes, they share one object in storage. Git never stores the same content twice.
  • You can't silently edit a past object. Change one byte and the hash changes. Anything referencing the old hash now points at nothing.

Three Object Types — and How They Chain

Git stores exactly three types of objects.

Blob — raw file content and nothing else. No filename. No timestamp. No permissions. Just bytes. The association between a blob and a filename lives in the tree, not the blob.

Tree — a directory listing. Each row maps a filename and permission mode to a blob or another tree hash:

100644 blob f2ba8f...   notes.txt

One tree per directory per commit. Nested directories produce nested trees.

Commit — the snapshot and its metadata: a pointer to the top-level tree, zero or more parent commit hashes (root commits have none), author, committer, and your message:

tree    4b825d...
parent  a3f7b2...   ← absent on the very first commit
author  Your Name <email> 1723027425 +0530
committer Your Name <email> 1723027425 +0530

Add initial notes file

The chain from any commit: commit → tree → blobs. Following those three pointers gives you the exact state of every file at that snapshot.

Reading Objects With git cat-file

You don't need a special tool to inspect this. Two flags cover everything:

git cat-file -t <hash>   # show the type:    commit / tree / blob
git cat-file -p <hash>   # show the content: pretty-printed for the type

You'll run both of these on your own Part 2 commit in Hands-On Part 3 — using the actual hash from your real git log output, not a placeholder.

Why the Chain Is the Guarantee

A commit's hash is computed from its content, its tree hash, and its parent hash. If anyone secretly edits commit a3f7b21 — changing the author, the message, even a single character in a tracked file — the hash changes. The child commit still references the old hash. The old hash no longer exists at that address. The chain breaks.

This is not encryption. It's arithmetic. A valid, unbroken chain of hashes is tamper-evidence baked into the data structure itself. It's why you can trust that a repository's history hasn't been quietly rewritten.

Key Takeaways

  • Git's object store is a folder of compressed files, each named by the SHA-1 hash of its own content
  • Three types: blob (file bytes), tree (directory listing), commit (metadata + tree pointer + optional parent)
  • The chain commit → tree → blobs gives you the complete snapshot at any point in history
  • Content-addressable storage means same content = same hash, and any edit changes the hash — making history tamper-evident
🛠
Hands-On Practice
Ready to practice what you just read?
Go to Tutorial →