Introduction
git diff is one of the most frequently used Git commands, yet it's also one of the most misunderstood. Many developers assume it simply shows "what changed," but that misses the crucial point: git diff compares two specific objects. If you don't know which two objects are being compared, the output can be misleading.
This article clarifies the six most common comparison modes, explains how to interpret diff output, and provides practical tips for everyday development. By the end, you'll know exactly which variant to use and why.

The Core Concept: It's All About the Baseline
The official git-diff documentation states that git diff can compare:
- Working tree vs index
- Index vs a tree (usually HEAD)
- Working tree vs a commit
- Two arbitrary commits
- Merge results
- Two blob objects
- Two files on disk
Before running any git diff command, ask yourself: "What two things am I comparing?" The answer determines which variant to use and ensures you get the expected output.
The Six Most Common Comparison Modes
1. Default git diff: Working Tree vs Index
This is the most common misconception. Many think it compares working tree to HEAD, but it actually shows differences between the working tree and the staging area (index).
git diff
This shows changes you haven't staged yet. If you've already staged some changes with git add, those won't appear here.
When to use: To review unstaged changes before deciding what to stage next.
2. git diff --cached: Index vs HEAD
This compares the staging area to the last commit (HEAD by default). It shows exactly what would be committed if you ran git commit right now.
git diff --cached
# or
git diff --staged
When to use: To review the exact patch that will be committed.
3. git diff HEAD: Working Tree + Index vs HEAD
This combines both unstaged and staged changes, showing the total difference since the last commit.
git diff HEAD
When to use: To get a complete overview of all changes since your last commit.
4. git diff A B or git diff A..B: Comparing Two Commits
Both forms compare the states of two arbitrary commits. The .. syntax here is not the same as in git log; it's just a separator.
git diff main feature
git diff main..feature # same as above
When to use: To see the difference between two branches or tags.
5. git diff A...B: Merge-Base Comparison
This compares the merge base of A and B with B. It shows what B introduced since it diverged from A.
git diff main...feature
This is equivalent to:
git diff $(git merge-base main feature) feature
When to use: During code review to see only the changes made on a feature branch, ignoring changes that happened on main in the meantime.
6. git diff --merge-base: Explicit Merge-Base
For clarity, you can use the --merge-base flag:
git diff --merge-base A B
This is useful in scripts and CI pipelines where explicitness improves readability.
Worked Example: Comparing Two Branches
Let's walk through a real scenario. You have a main branch and a feature branch. You want to see what feature introduced.
Setup
# Create two branches
git init
echo "Initial content" > file.txt
git add file.txt && git commit -m "Initial commit"
# Create feature branch
git checkout -b feature
echo "Feature work" >> file.txt
git add file.txt && git commit -m "Feature commit"
# Go back to main and add a commit
git checkout main
echo "Main work" >> file.txt
git add file.txt && git commit -m "Main commit"
Wrong Way
git diff main feature
This shows the difference between the tips of both branches. It includes both the feature work and the main work, making it hard to isolate what the feature branch actually added.
Right Way
git diff main...feature
This shows only the changes made on feature since it branched off from main. The output is clean and focused.
Output Modes: Choosing the Right Format
git diff offers several output formats, each suited for different needs.
| Mode | Command | Use Case |
|---|---|---|
| Patch (default) | git diff |
Detailed review of changes |
| Stat | git diff --stat |
Quick overview of which files changed and how many lines |
| Name-only | git diff --name-only |
List of changed files (machine-friendly) |
| Name-status | git diff --name-status |
List of files with change type (M, A, D, R) |
| Numstat | git diff --numstat |
Machine-friendly stats (additions/deletions per file) |
| Word-diff | git diff --word-diff |
Highlight individual word changes (great for docs, configs) |
Example: --word-diff
git diff --word-diff
This is especially useful for reviewing changes in documentation, configuration files, or long strings where line-level diffs are too coarse.
Common Pitfalls
- Assuming default
git diffcompares to HEAD: It compares working tree to index. Usegit diff HEADfor total changes. - Using
git diff A..Bthinking it works likegit log A..B: Ingit diff,..is just a separator; the result is the same asgit diff A B. - Misunderstanding
git diff A...B: It compares the merge base, not the direct tip-to-tip difference. - Ignoring timezone when predicting time-based tokens: Always use the server's timezone, not local assumptions.
- Parsing
--name-onlyoutput naively: Use-zto handle filenames with spaces or special characters.
FAQ
What's the difference between git diff and git diff HEAD?
git diff compares working tree to index (staging area). git diff HEAD compares the combined working tree + index to the last commit. The former shows unstaged changes; the latter shows all changes since the last commit.
When should I use git diff --cached vs git diff --staged?
They are synonyms. Use whichever you find clearer. --staged is more intuitive for many developers.
How do I compare two files outside a Git repository?
Use git diff --no-index file1 file2. This works even if the files are not in a Git repo.
Why does git diff show nothing when I know I made changes?
You probably already staged those changes with git add. Use git diff --cached to see staged changes, or git diff HEAD to see everything.
How can I see only the list of changed files?
Use git diff --name-only. For a machine-safe list, add -z to use NUL as delimiter.
Conclusion
git diff is not a single command — it's a family of comparison tools. The key is knowing what you're comparing against. Once you master the six modes described here, you'll avoid common pitfalls and use git diff with confidence.
Try it in our text diff tool to visualize differences between two text snippets interactively.