MW

How-To · Version Control

`git diff` — Every Command Variant with Examples (2026)

`git diff` is the universal change-inspection tool. Same command, ten different scopes: working tree, staged, two commits, two branches, a single file, ignoring whitespace. Here's every variant.

Jan 24, 2025 6 min read Any platform beginner
Advertisement

git diff is the single tool you reach for whenever you need to ask “what changed?”. The command is the same; the args control the scope.

Terminal — the most common form
$ git diff
diff --git a/README.md b/README.md index e4a8c1f..7b9d2c4 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # my-project + +Updated 2026-05-13 — added empire-shells integration. A monorepo for...

This guide walks every scope: working tree, staged, between commits, between branches, a single file, plus the most-used flags (--name-only, --stat, exclude paths, ignore whitespace).

Basic usage — three scopes

The three forms you’ll use 95% of the time:

Terminal — three core variants
$ git diff
(unstaged changes — working tree vs last commit)
$ git diff --staged
(staged changes — what your next commit will save)
$ git diff HEAD
(EVERYTHING since last commit — staged + unstaged combined)

Mental model:

  • Working tree → what’s on disk now
  • Index / staged → what you’ve git add-ed but not yet committed
  • HEAD → last commit

git diff (no args) compares working tree to index. --staged (or --cached — same thing) compares index to HEAD. HEAD skips the index and compares working tree directly to last commit.

Between commits

Terminal — commit-to-commit diffs
$ git diff abc123 def456
(all changes from commit abc123 to def456)
$ git diff abc123..def456
(same as above — .. notation)
$ git diff HEAD~3 HEAD
(last 3 commits combined diff)
$ git diff HEAD~1
(everything since the previous commit — common shortcut)

Between branches

Terminal — branch-to-branch diffs
$ git diff main feature-branch
(what feature-branch adds vs main)
$ git diff main..feature-branch
(same as above)
$ git diff main...feature-branch
(three dots = symmetric — common ancestor base)

Single file or path

Append a path to scope the diff:

Terminal — path-scoped diffs
$ git diff README.md
(only changes to README.md)
$ git diff -- src/
(only changes under src/ — the -- separates paths from refs)
$ git diff HEAD~3 -- package.json
(package.json changes over the last 3 commits)

Useful flags

--name-only — list changed files

Terminal — file list only
$ git diff --name-only
README.md src/App.tsx src/lib/utils.ts
$ git diff --name-only HEAD~5 HEAD
(every file changed in last 5 commits)

--stat — summary with line counts

Terminal — diffstat
$ git diff --stat
README.md | 12 ++++++++---- src/App.tsx | 38 ++++++++++++++++++++++++++++++++++---- src/lib/utils.ts | 5 ++++- 3 files changed, 47 insertions(+), 8 deletions(-)

--word-diff — word-level, not line-level

Useful for prose/docs:

Terminal — word-level diff
$ git diff --word-diff README.md
A [-quick-]{+complete+} reference for git diff variants.

Ignore whitespace

Terminal — ignore whitespace
$ git diff -w
(short for --ignore-all-space)
$ git diff --ignore-space-change
(ignore amount of whitespace changes, but flag added/removed whitespace)
$ git diff --ignore-blank-lines
(ignore added/removed blank lines)

Exclude paths

For when package-lock.json and node_modules drown out the real diff:

Terminal — exclude noise
$ git diff -- '.' ':!package-lock.json' ':!node_modules/**'
(everything except those paths)

See the dedicated guide for excluding files from git diff — covers :!, .gitattributes, and custom drivers.

Output to a file (patch format)

Terminal — save as patch
$ git diff > changes.patch
(save the diff as a unified patch file)
$ git apply changes.patch
(apply the patch elsewhere)

Visual / GUI diffs

CLI is fastest, but for big diffs a GUI tool reads easier:

Terminal — open diff in a tool
$ git difftool
(opens your configured diff tool — VS Code, Beyond Compare, etc.)
$ git config --global diff.tool vscode
$ git config --global difftool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'
(configure VS Code as the diff tool — one-time setup)

Common scenarios

”What did I change since I started this branch?”

git diff $(git merge-base main HEAD)

Or simpler with the three-dot syntax:

git diff main...HEAD

“What’s in my last commit?”

git diff HEAD~1 HEAD

Or:

git show HEAD

(Same diff, plus the commit message.)

”What’s the smallest possible diff between these two branches?”

Use three-dot + ignore whitespace:

git diff -w main...feature-branch

“Show me only files in src/ that changed”

git diff --name-only -- src/

Quick reference

GoalCommand
Unstaged changesgit diff
Staged changesgit diff --staged
All uncommitted changesgit diff HEAD
Between two commitsgit diff abc..def
Between branches (full)git diff main feature
Between branches (since fork)git diff main...feature
Single filegit diff path/to/file
File list onlygit diff --name-only
Summary statsgit diff --stat
Word-levelgit diff --word-diff
Ignore whitespacegit diff -w
Exclude pathsgit diff -- '.' ':!package-lock.json'
Save as patchgit diff > changes.patch
GUI toolgit difftool

Conclusion

git diff is one command with many scopes — the args dictate what you’re comparing. Memorize three forms:

  • git diff — unstaged
  • git diff --staged — staged
  • git diff main...HEAD — since branching

The rest is variations on the same theme. When the output is overwhelming, reach for --stat for a summary or exclude noise with ':!path'.

Git Diff Version Control Development Command Line
Advertisement

Get weekly notes in your inbox

Practical tips, tutorials and resources. No spam.