Build the mental model
`git diff` answers one question in three different contexts: what exactly changed, and between which two points?
| Command | Compares |
|---|---|
| git diff | working directory vs staging area |
| git diff --staged | staging area vs last commit |
| git diff A...B | two commits/branches directly |
The output format is the same in every case. Each changed file gets a header, followed by hunks marked `@@ -a,b +c,d @@` that show which line ranges are involved.
- `-` lines — existed before and were removed
- `+` lines — newly added
- Unmarked lines — unchanged context
A `-` line right above a nearly identical `+` line usually means one word changed, not the whole line — look for the small difference between them.
THREE THINGS git diff CAN COMPARE
---------------------------------
THREE THINGS git diff CAN COMPARE
------------------------------------
git diff : working dir vs staging area
git diff --staged : staging area vs last commit
git diff main...feature : branch main vs branch featureConnect it to a real scenario
See the unstaged diff
Edit a file and run `git diff` — you'll see a header, `@@` hunk marker, and `-`/`+` lines.
See the staged diff
`git add` then `git diff --staged` — same content, just a different baseline.
Compare two branches
`git diff main...feature` shows what changed since the branches diverged.
Try the working example
git init -q -b main
git config user.name "Thuta Learner"
git config user.email "learner@example.com"
export GIT_AUTHOR_NAME="Thuta Learner"
export GIT_AUTHOR_EMAIL="learner@example.com"
export GIT_COMMITTER_NAME="Thuta Learner"
export GIT_COMMITTER_EMAIL="learner@example.com"
cat > greet.js <<'EOF'
function greet(name) {
console.log("Hello, " + name);
}
greet("world");
EOF
git add greet.js
GIT_AUTHOR_DATE="2026-01-07T09:00:00" GIT_COMMITTER_DATE="2026-01-07T09:00:00" \
git commit -m "Add greet function"
git branch -M main
cat > greet.js <<'EOF'
function greet(name) {
console.log("Hello, " + name + "!");
}
greet("world");
EOF
git diff
git add greet.js
git diff --staged
GIT_AUTHOR_DATE="2026-01-07T10:00:00" GIT_COMMITTER_DATE="2026-01-07T10:00:00" \
git commit -m "Add exclamation to greeting"
git checkout -b feature
cat > greet.js <<'EOF'
function greet(name) {
console.log("Hi there, " + name + "!");
}
greet("world");
EOF
git add greet.js
GIT_AUTHOR_DATE="2026-01-07T11:00:00" GIT_COMMITTER_DATE="2026-01-07T11:00:00" \
git commit -m "Change greeting wording on feature branch"
git diff main...feature$ git diff
diff --git a/greet.js b/greet.js
index c30f984..629b3db 100644
--- a/greet.js
+++ b/greet.js
@@ -1,4 +1,4 @@
function greet(name) {
- console.log("Hello, " + name);
+ console.log("Hello, " + name + "!");
}
greet("world");
$ git add greet.js
$ git diff --staged
diff --git a/greet.js b/greet.js
index c30f984..629b3db 100644
--- a/greet.js
+++ b/greet.js
@@ -1,4 +1,4 @@
function greet(name) {
- console.log("Hello, " + name);
+ console.log("Hello, " + name + "!");
}
greet("world");
$ git diff main...feature
diff --git a/greet.js b/greet.js
index 629b3db..54bea71 100644
--- a/greet.js
+++ b/greet.js
@@ -1,4 +1,4 @@
function greet(name) {
- console.log("Hello, " + name + "!");
+ console.log("Hi there, " + name + "!");
}
greet("world");5-minute try-it
Edit a tracked file and run `git diff` to see the unstaged change. Stage it and run `git diff --staged` to see the same change from a different baseline. Then create a second branch, make a different change there, and run `git diff main...yourbranch` from main to see exactly what the branch changed, independent of your working directory.
One important caution
Running `git diff` after staging a file shows nothing, because the change is now already reflected in the staging area — you need `git diff --staged` to see staged changes.
Two-dot (`git diff main..feature`) and three-dot (`git diff main...feature`) syntax compare different things — three-dot compares against the common ancestor, which is almost always what you want when reviewing a branch's changes.
Git Documentation: git-diff — Git & GitHub