GitViewing Differences (git diff)

Viewing Differences (git diff)

git diff shows the changes between two versions of your code. It is the way you answer questions like “what did I change since the last commit?”, “what is staged for the next commit?”, or “what is different between these two branches?”. Without git diff, every commit would be a leap of faith — with it, you always know exactly what you are about to ship.

The four most useful diff invocations

Daily diffs

Bash
git diff                  # working dir vs staging area
git diff --staged         # staging area vs last commit
git diff HEAD             # working dir + staging vs last commit
git diff main..feature    # one branch vs another
Reading diff output

Typical diff output

Text
diff --git a/src/app.js b/src/app.js
index 1a2b3c4..5d6e7f8 100644
--- a/src/app.js
+++ b/src/app.js
@@ -10,7 +10,9 @@ function greet(name) {
   if (!name) {
     return "Hello, world!";
   }
-  return "Hi " + name;
+  return `Hello, ${name}!`;
 }

+// New helper
+const farewell = (n) => `Goodbye, ${n}`;
  • diff --git a/src/app.js b/src/app.js — the file being compared.

  • index 1a2b...5d6e... 100644 — old and new blob hashes plus file mode.

  • --- a/src/app.js / +++ b/src/app.js — old and new versions.

  • @@ -10,7 +10,9 @@ — “hunk header”: starting at line 10 of the old file (7 lines), line 10 of the new file (9 lines).

  • Lines starting with - are removals; + are additions; a space is unchanged context.

Compare specific files

Bash
git diff src/app.js                  # one file
git diff src/                        # a folder
git diff -- "*.js"                   # by pattern
git diff HEAD~3 HEAD -- src/app.js   # one file across commits
Word-level and character-level diffs

Bash
# Show changes word-by-word
git diff --word-diff

# Even finer — character-by-character (useful for prose)
git diff --word-diff=color --word-diff-regex='.'
Stat summaries

Just count the changes

Bash
git diff --stat
# src/app.js | 5 +++--
# src/util.js | 12 +++++++++++-
# 2 files changed, 14 insertions(+), 3 deletions(-)

git diff --shortstat
# 2 files changed, 14 insertions(+), 3 deletions(-)

git diff --numstat
# 3   2   src/app.js
# 11  1   src/util.js

# Just the file names that changed
git diff --name-only
# src/app.js
# src/util.js
Comparing branches and commits

Branches and commits

Bash
git diff main feature              # what does feature have that main doesn't
git diff main..feature             # same — two-dot is exclusive on each side
git diff main...feature            # three-dot: changes on feature since it forked
git diff HEAD~3 HEAD               # changes in the last 3 commits
git diff v1.0..v1.1                # changes between two tags
Two dots vs three dots
`A..B` = commits in B that are not in A. `A...B` = changes relative to the *merge base* of A and B — the answer to “what did B add since it diverged from A?”. The three-dot version is what you usually want for code review.
Diffs in colour and side-by-side

Bash
# Force colour even when piped
git diff --color=always | less -R

# Side-by-side with delta, diff-so-fancy, or a GUI tool
git config --global core.pager delta
git config --global delta.side-by-side true

# Or use a built-in difftool
git difftool main..feature
Useful flags
  • --cached / --staged — diff between staging and last commit.

  • --name-status — show only file names + a one-letter status (A/M/D/R).

  • -w / --ignore-all-space — hide whitespace-only changes.

  • -b / --ignore-space-change — ignore changes in amount of whitespace.

  • --no-color — plain output, no terminal codes.

  • -U10 — show 10 lines of context around each hunk (default is 3).

  • --patience / --minimal / --histogram — different diff algorithms; histogram is often best.

Inspect a single past commit

Bash
# What did commit abc1234 change?
git show abc1234
git diff abc1234^ abc1234     # equivalent: parent to commit
Ignoring whitespace

Don't get distracted by reformatting

Bash
git diff -w main..feature      # ignore all whitespace differences
git diff --ignore-blank-lines  # ignore added/removed empty lines
Using external diff tools

Configure a GUI diff tool once

Bash
# VS Code
git config --global diff.tool vscode
git config --global difftool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'

# Beyond Compare
git config --global diff.tool bc4

# Then:
git difftool                  # opens GUI
git difftool main..feature
Practical patterns
  • Before every commitgit diff --staged to confirm what you are about to commit.

  • Before every pushgit log origin/main..HEAD --stat then git diff origin/main..HEAD to see exactly what is going to the remote.

  • During code reviewgit diff main...feature for the three-dot view that PR tools show.

  • Debugging a regressiongit diff v1.0..HEAD -- path/to/file to see how a file evolved across a range.

Tip
If `git diff` looks unreadable, try git diff --color | less -R for paged colour output, or install a prettifier like delta to make diffs look like a modern review UI in the terminal.