The Hook (The "Byte-Sized" Intro)
Git doesn't store diffs. It stores snapshots. Each commit is a complete picture of every file. So how does git diff work? Git computes diffs on the fly by comparing two tree objects — walking them side by side, comparing blob SHAs, and producing the output you see. This means any two commits can be diffed, in any order, instantly.
📖 What is How Git Diffs Work?
Git computes diffs dynamically by comparing tree and blob objects between two snapshots. It doesn't store diffs — it generates them on demand.
Conceptual Clarity
Diff computation:
- Compare two tree objects (e.g., commit A's tree vs commit B's tree)
- Walk entries side by side
- Same blob SHA? → unchanged (skip)
- Different blob SHA? → compute line-level diff
- Missing entry? → added or deleted
- Same blob SHA, different name? → rename detected
Diff contexts:
| Command | Compares |
|---|---|
git diff | Working tree ↔ Staging area |
git diff --staged | Staging area ↔ HEAD |
git diff HEAD | Working tree ↔ HEAD |
git diff A..B | Commit A ↔ Commit B |
git diff A...B | Common ancestor ↔ Commit B |
Rename detection: Git doesn't track renames explicitly. It detects them heuristically by comparing blob SHAs across trees. If a blob appears in the old tree under name A and in the new tree under name B, Git reports it as a rename.
Real-Life Analogy
Git stores photos, not movies. A diff is like holding up two photos side by side and circling the differences. You can compare ANY two photos — not just consecutive ones. The comparison is computed on the spot, not pre-recorded.
Visual Architecture
Why It Matters
- Flexibility: Compare any two commits, not just adjacent ones.
- Speed: Identical blob SHAs are skipped — only changed files are diffed.
- Rename tracking: Git detects renames without explicit tracking.
- Foundation: Understanding diff contexts prevents confusion between
diff,diff --staged, anddiff HEAD.
Code
# ─── Diff working tree vs staging ───
git diff
# Shows unstaged changes
# ─── Diff staging vs HEAD ───
git diff --staged
# Shows what will be committed
# ─── Diff between two commits ───
git diff abc123..def456
# ─── Diff with stats (summary) ───
git diff --stat HEAD~5..HEAD
# ─── Detect renames ───
git diff -M HEAD~1..HEAD
# -M enables rename detection
# Shows: renamed: old_name.js -> new_name.js
# ─── Word-level diff ───
git diff --word-diff
# ─── Diff specific file ───
git diff HEAD -- src/app.jsKey Takeaways
- Git stores snapshots, not diffs — diffs are computed on demand.
- Different
diffcommands compare different pairs of states. - Rename detection works by comparing blob SHAs across trees.
--statgives a quick summary;-p(default) shows line-level changes.
Interview Prep
-
Q: Does Git store diffs or snapshots? A: Snapshots. Each commit points to a tree object representing the complete state of the project. Diffs are computed on the fly by comparing two tree objects. This is why you can diff any two commits instantly, not just consecutive ones.
-
Q: How does Git detect file renames? A: Heuristically. Git compares blob SHAs between old and new trees. If a blob exists in the old tree under name A and the new tree under name B, Git infers a rename. The
-Mflag controls the similarity threshold (default 50%). -
Q: What is the difference between
git diffandgit diff --staged? A:git diffcompares the working tree against the staging area (shows unstaged changes).git diff --stagedcompares the staging area against HEAD (shows what will be in the next commit).