Preview Git Changes

Learn to preview changes with git diff and git difftool — check modifications, stage diffs, and compare branches before committing.

Focus: preview changes with git diff and git difftool

Sponsored

You've made a few edits, saved the file, and now you're about to commit — but are you sure you're committing exactly what you intended? Rushed commits are a leading source of git headaches: accidental debugging lines, missed whitespace, or staging the wrong file. The git diff and git difftool commands are your safeguard, giving you a precise, staged-forward preview of every change before it becomes part of your history. In this lesson, you'll learn to use these commands to inspect working directory changes, review staged changes, and compare branches — turning guesswork into confident, deliberate commits.

The problem this lesson solves

Picture this: you've been working on a feature for an hour. You type git add ., then git commit -m "feat: update user profile" — done, right? But later you discover the commit included a debug console.log, accidentally removed a blank line that broke a style guide, or even staged a file you meant to leave alone. Without previewing, every commit is a small gamble.

Commits are your project's history — the story you and your team will read later. A commit with unintended changes makes that story confusing and occasionally breaks the build. The solution isn't more discipline; it's a better review step. git diff and git difftool let you inspect changes in detail before you commit, so you can catch errors, verify intent, and keep your history clean.

By the end of this lesson, you'll be able to preview changes with git diff and git difftool — checking what's modified, what's staged, and how branches differ — and you'll have a mental model that makes these commands second nature.

Core concept / mental model

Think of your working copy, the index (staging area), and your last commit as three layers of a stack. git diff is a lens that shows you exactly what differs between two layers. It doesn't change anything — it only reports.

  • git diff (no arguments): shows unstaged changes — differences between your working directory and the index (staged snapshot). This is your "what have I changed but not staged yet" view.
  • git diff --staged (or --cached): shows staged changes — differences between the index and the HEAD (last commit). This is your "what will go into the next commit" view.
  • git diff <branch1> <branch2>: shows differences between two branches — a way to compare entire lines of history.
  • git difftool: launches an external visual diff tool (like VS Code, Meld, or KDiff3) for a side-by-side or word-level comparison, which can be easier for large or complex changes.

The key idea: always preview before you commit. A quick git diff takes seconds but saves minutes of cleanup and avoids polluting history.

How it works step by step

1. Check the status first

Always start with git status to see which files are modified, staged, or untracked. This gives you a high-level map, and then you know which diff commands to run.

$ git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
        modified:   app.js

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        test.txt

2. Preview unstaged changes

Run git diff to see exactly what's different in your working directory compared to the index. This shows added lines (prefixed with +) and removed lines (prefixed with -) in a unified diff format.

$ git diff
diff --git a/app.js b/app.js
index 2f2c1d1..9bf3a7e 100644
--- a/app.js
+++ b/app.js
@@ -10,7 +10,8 @@ function greet(name) {
   console.log(`Hello, ${name}!`);
 }

-// old comment
+// new comment about greeting
+// Added debug log
 console.log(greeting);

3. Preview staged changes

After you run git add, the file moves to the index. To see what's staged (what will actually be committed), use git diff --staged.

$ git add app.js
$ git diff --staged

Now the output shows only the staged changes — the ones that became part of the next commit. Unstaged changes are not shown.

4. Compare differences against a branch or commit

You can also diff against a specific branch, tag, or commit hash to see how your current state differs from another point in history. This is useful before merging or when investigating what a colleague changed.

$ git diff main feature/login
$ git diff HEAD~2 HEAD   # changes from two commits ago to the last commit
$ git diff v1.0.0..v1.1.0  # compare two tags

5. Launch a visual tool with git difftool

If the text diff is too dense, run git difftool to open your configured visual diff tool. First, set your preferred tool (this example uses VS Code):

$ git config --global diff.tool vscode
$ git config --global difftool.vscode.cmd 'code --wait --diff "$LOCAL" "$REMOTE"'

Then just run:

$ git difftool

Git will open your tool for each changed file, and you can review changes side-by-side, with syntax highlighting and easy navigation.

Hands-on walkthrough

Let's practice in a fresh repository so you can see the commands in action.

Setup a test repo

mkdir demo-diff && cd demo-diff
git init

echo "def add(a, b):" > calc.py
echo "    return a + b" >> calc.py
git add calc.py
git commit -m "initial commit"

Modify the file

# Make some edits
echo "def add(a, b):" > calc.py
echo "    # debug: print calculation" >> calc.py
echo "    return a + b" >> calc.py
echo "    # extra comment" >> calc.py

git diff

Expected output (abbreviated):

diff --git a/calc.py b/calc.py
index 1f3f4c3..d0f6b2a 100644
--- a/calc.py
+++ b/calc.py
@@ -1,3 +1,4 @@
 def add(a, b):
+    # debug: print calculation
     return a + b
+    # extra comment

The + lines show what you added. Notice the debug comment — you probably don't want that in production!

Stage and review staged diff

# Remove the debug line and stage the file
git checkout -- calc.py   # revert to HEAD (safe here, but careful — use git restore in real work)
# Add a legitimate feature: a sub function
echo "def add(a, b):" > calc.py
echo "    return a + b" >> calc.py
echo "" >> calc.py
echo "def multiply(a, b):" >> calc.py
echo "    return a * b" >> calc.py

git add calc.py
git diff --staged

Expected output:

diff --git a/calc.py b/calc.py
index 1f3f4c3..b3e4c5d 100644
--- a/calc.py
+++ b/calc.py
@@ -1,3 +1,6 @@
 def add(a, b):
     return a + b
+
+def multiply(a, b):
+    return a * b

Now you see exactly what will be committed. If you had a stray debug line, you'd catch it here — just edit the file again and re-stage.

Use difftool (optional)

If you have a visual tool configured, try git difftool --staged to see the same changes with a GUI. Otherwise, the plain git diff is always reliable.

Compare options / when to choose what

Command / Option Shows Best For
git diff Unstaged changes (working vs index) Quick check before git add
git diff --staged Staged changes (index vs HEAD) Review before git commit
git diff HEAD Both staged and unstaged changes combined Full picture of uncommitted work
git diff <branch> Differences between current branch and another Preparing for merge
git difftool Same as above but in a visual tool Large/complex diffs, side-by-side review
git diff --word-diff Inline word-level changes Spotting small edits in long lines
git diff --stat Summary of files and line counts Quick overview

Pro tip: Use git diff --stat first to see a compact summary. If the file list matches your intent, drill into git diff for details. This saves you from drowning in large diffs when you only need a high-level check.

Troubleshooting & edge cases

  • git diff shows nothing but you know you changed a file — If the file is modified but git diff is empty, it's because the changes are already staged (you ran git add). Use git diff --staged to see them. Alternatively, git diff HEAD shows all changes, staged or not.
  • git diff shows changes you didn't expect — This often happens with line-ending differences (CRLF vs LF). Add a .gitattributes file or configure core.autocrlf to handle cross-platform consistency.
  • Binary files show as "Binary files differ" — For images, PDFs, or compiled files, a text diff isn't useful. Use git diff --stat to see that they changed, and consider using git difftool --tool=... to open them in an appropriate viewer.
  • git difftool prompts for each file and can interrupt flow — You can disable the prompt with git config --global difftool.prompt false. The --no-prompt flag also works.
  • You accidentally ran git checkout -- <file> and lost changes — This is a common mistake. If you haven't committed, there's no built-in undo. Use git stash or commit early to avoid data loss. git restore is the modern, more explicit alternative.
  • Large diffs are overwhelming — Use git diff -U0 to suppress context lines, or git diff --color-words to highlight only the changed words, which makes review faster.

What you learned & what's next

You now have the ability to preview changes with git diff and git difftool — you can inspect unstaged and staged changes, compare branches, and use a visual tool for complex diffs. You've also practiced the discipline of reviewing before committing, which is the foundation of clean history. This directly supports the next lesson where you'll likely merge branches or rewrite history with git rebase — with a clear view of what's changing, merge conflicts and rebase amends become much easier to handle.

Remember: git diff is your safety net. Run it, review, then commit. Your future self and your teammates will thank you.

Practice recap

Create a new repository, make a few edits, and practice the full preview workflow: git status, git diff, git add, then git diff --staged. Try comparing two branches with git diff <branch1> <branch2>. Bonus: configure git difftool with your favorite editor and run git difftool --staged to see the visual difference.

Common mistakes

  • Running git add first, then git diff — and seeing nothing because changes are already staged. Use git diff --staged to review staged changes, or git diff HEAD to see everything.
  • Assuming git diff shows all uncommitted changes — but untracked files are invisible. Run git status to see them and git add + git diff --staged to preview them.
  • Using git checkout -- <file> to discard changes without having a backup — you can lose work permanently. Prefer git stash (with a message) or commit first if there's any doubt.
  • Ignoring line-ending changes (CRLF vs LF) that clutter diffs — configure core.autocrlf or add a .gitattributes file to keep diffs clean.
  • Forgetting that git difftool only works if you've configured a tool — run git difftool --tool-help to see available options and set one up.

Variations

  1. Use git diff --cached as an alias for --staged — both work, so pick one and stay consistent.
  2. Use git difftool --dir-diff to open all changed files in a directory-level comparison, which is great for batch review.
  3. Integrate a modern IDE's built-in diff view (VS Code, PyCharm, etc.) — often more comfortable than a terminal diff, but you can still use the same underlying git diff commands.

Real-world use cases

  • Reviewing a pull request: run git diff main...feature to see exactly what will be merged, catching unintended changes before approval.
  • Debugging a regression: use git diff HEAD~5 HEAD -- app.js to inspect recent changes to a specific file and find the culprit commit.
  • Auditing before release: run git diff --staged (or git diff v1.0.0..v1.1.0) to verify the exact set of files and changes in a release commit, ensuring only intended changes ship.

Key takeaways

  • git diff shows unstaged changes; git diff --staged shows what will be committed — always preview both before committing.
  • git diff HEAD combines staged and unstaged changes — use it for a full picture of uncommitted work.
  • git diff <branch> or <commit1> <commit2> lets you compare different points in history, useful for merges and audits.
  • git difftool opens a visual diff tool for complex changes; configure it once to speed up reviews.
  • Always run git status first — it tells you which diff command to use and reveals untracked files that won't appear in diffs.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.