The Staging Area & git diff
Reviewed & published by Brayan K
The staging area is the feature that makes Git commits so clean. By the end of this lesson you'll know how to choose exactly which changes go into each commit, read git status at a glance, and use git diff to see precisely what you're about to commit.
Part of the free Git course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
What You'll Learn
- What the staging area (the index) is and why Git has it
- Read git status and git status -s like a dashboard
- Stage changes with git add, including whole-directory git add .
- Stage parts of a file interactively with git add -p
- Tell git diff (unstaged) from git diff --staged (what you'll commit)
- Unstage a mistake with git restore --staged
1️⃣ git status — Your Dashboard
git status tells you, at any moment, which changes are staged (ready to commit), which are unstaged, and which files are untracked. Run it constantly — it's the cheapest, safest command in Git. The short form git status -s uses two columns of one-letter codes: column 1 is the staged state, column 2 is the working-tree state.
# git status is your dashboard — run it constantly. It tells you which
# changes are STAGED (ready to commit) and which are still UNSTAGED.
# The full, friendly version
git status
# The short version — two columns of one-letter codes
git status -s
# X in column 1 = staged change (will go in the next commit)
# Y in column 2 = unstaged change (still only in your working tree)
# ?? = untracked file (Git isn't following it yet)2️⃣ Staging with git add
The staging area is a waiting room. git add copies the current state of a change into it, and your next commit snapshots exactly what's waiting there. In git status -s, a staged change shows its letter in the first column (e.g. M app.js), while an unstaged change shows it in the second ( M styles.css).
# The staging area (a.k.a. the "index") is a waiting room. You decide
# EXACTLY which changes board the next commit by adding them.
# Stage one file
git add app.js
# Stage several files at once
git add app.js styles.css
# Stage EVERYTHING that changed (new, modified — careful, it's broad)
git add .
# After staging, status shows the file under "Changes to be committed"
git status -s3️⃣ git diff vs git diff --staged
These two diffs answer two different questions. git diff compares your working directory to the index — "what have I changed but not staged yet?" git diff --staged (also written --cached) compares the index to your last commit — "what will my next commit actually contain?" A handy consequence: once you git add a file, plain git diff shows nothing for it, because the change has moved into the index.
# Two diffs, two questions:
# git diff -> "What have I changed but NOT staged yet?"
# (working directory vs the index)
# git diff --staged -> "What will my next commit contain?"
# (the index vs the last commit)
# What's still unstaged
git diff
# What's already staged and ready to commit (--cached is a synonym)
git diff --stagedYour turn. Make a change, look at it unstaged, stage it, then confirm what your next commit will contain. Fill in the three blanks.
# 🎯 YOUR TURN — replace each ___ then run it in your terminal.
# Goal: see the difference between staged and unstaged changes.
echo "new line" >> app.js
# 1) See the change you just made (it is NOT staged yet)
git ___ # 👉 the diff that shows UNSTAGED changes
# 2) Stage the file
git ___ app.js # 👉 the command that stages a file
# 3) Confirm what your next commit will contain
git diff ___ # 👉 the flag that shows STAGED changes
# ✅ Expected: step 1 shows the "+new line" diff, step 3 shows the same
# diff now that it's staged, and plain "git diff" is empty after step 2.4️⃣ git add -p — Stage Part of a File
Sometimes one file holds two unrelated changes. git add -p (patch mode) breaks the file into hunks and asks about each: press y to stage it, n to skip it, s to split a big hunk into smaller pieces. It's the cleanest way to keep each commit focused on a single idea.
# git add -p (patch mode) is a superpower: it splits a file into "hunks"
# and asks you about each one. Stage the bug fix now, leave the unrelated
# debug print for later — two clean commits instead of one messy blob.
git add -p app.js
# For each hunk Git asks "Stage this hunk [y,n,q,a,d,s,e,?]?"
# y = yes, stage it n = no, skip it
# s = split into smaller hunks q = quit
# ? = show help for every optionCommon Errors (and the fix)
- "nothing to commit, working tree clean" but you edited a file: you probably forgot to git add it — or you're in the wrong directory. Run git status to see the truth.
- git diff shows nothing after you edited a file: you already staged it. Use git diff --staged to see the change in the index.
- Accidentally staged the wrong file: unstage it with git restore --staged file.txt. Your edits stay safe; only the staging is undone.
- git add . swept in junk: a stray build artifact got staged. Unstage with git restore --staged and consider adding it to .gitignore.
Pro Tips
- 💡 Diff before you commit: always run git diff --staged right before committing — it's a free last look at exactly what you're saving.
- 💡 One idea per commit: use git add -p to keep unrelated changes in separate commits.
- 💡 Learn the short codes: git status -s is faster once you read the two columns fluently.
- 💡 Stage by patch, not by panic: if git add . ever feels risky, switch to -p and curate.
📋 Quick Reference
| Command | Purpose |
|---|---|
| git status | Show staged, unstaged, and untracked changes |
| git status -s | Short two-column status |
| git add file | Stage a file for the next commit |
| git add -p | Stage selected hunks interactively |
| git diff | Show unstaged changes (working vs index) |
| git diff --staged | Show staged changes (index vs last commit) |
| git restore --staged file | Unstage a file (keeps your edits) |
Mini-Challenge: One Clean Commit
No commands given this time — just the plan. Curate a single focused commit out of a messy working tree, then check your diffs against the expected result in the comments.
# 🎯 MINI-CHALLENGE: build one clean commit from a messy working tree.
# No commands given — just the plan. Run each step in your terminal.
#
# 1. Make two unrelated edits in the same file (e.g. a fix and a typo)
# 2. Run "git status -s" and read the two-column codes
# 3. Use "git add -p" to stage ONLY the fix hunk (answer y), skip the typo (n)
# 4. Run "git diff" and "git diff --staged" — confirm they show different things
# 5. Commit just the staged fix, leaving the typo edit for a second commit
#
# ✅ Expected: "git diff --staged" shows only the fix, and after committing,
# "git status -s" still lists the typo edit as unstaged ( M).
# your commands here🎉 Lesson Complete!
- ✅ The staging area (index) is a waiting room for your next commit
- ✅ git add moves changes in; git add -p stages hunk by hunk
- ✅ git diff = unstaged; git diff --staged = what you'll commit
- ✅ git status -s shows staged (col 1) vs unstaged (col 2)
- ✅ git restore --staged safely unstages a mistake
Practice quiz
What is the staging area (also called the index)?
- A backup of your last commit
- A waiting room where you choose exactly which changes go into the next commit
- A remote copy of your repo
- A list of your branches
Answer: A waiting room where you choose exactly which changes go into the next commit. The staging area holds the precise set of changes that your next git commit will snapshot.
Which command moves a modified file into the staging area?
- git stage file.txt
- git commit file.txt
- git add file.txt
- git push file.txt
Answer: git add file.txt. git add copies the current state of the file into the staging area (index).
By default, what does plain `git diff` show?
- Staged changes only
- Changes between two commits
- Unstaged changes — working directory vs the index
- Nothing, it needs a file argument
Answer: Unstaged changes — working directory vs the index. git diff with no flags compares your working directory to what is already staged.
Which command shows what is STAGED, i.e. what will go into the next commit?
- git diff
- git diff --staged
- git diff HEAD~1
- git status -s
Answer: git diff --staged. git diff --staged (a.k.a. --cached) compares the index against the last commit.
What does `git add -p` let you do?
- Add every file at once
- Add files matching a pattern
- Interactively stage individual hunks (parts) of a file
- Preview the commit message
Answer: Interactively stage individual hunks (parts) of a file. The -p (patch) flag walks you through each change hunk so you can stage some and skip others.
In `git status -s`, what does ' M file.txt' (space then M) mean?
- The file is staged
- The file has unstaged modifications in the working tree
- The file is untracked
- The file was deleted
Answer: The file has unstaged modifications in the working tree. The second column M means modified-but-not-staged; the leading space means nothing is staged yet.
In `git status -s`, what does 'M file.txt' (M then two spaces) mean?
- Unstaged change
- The modification is staged, ready for the next commit
- Merge conflict
- Untracked file
Answer: The modification is staged, ready for the next commit. M in the first column means the change is staged in the index.
What do '??' marks indicate in `git status -s`?
- A merge conflict
- A staged deletion
- An untracked file Git is not following yet
- A renamed file
Answer: An untracked file Git is not following yet. ?? marks a file Git has never been told about — run git add to start tracking it.
After you `git add` a file, what does plain `git diff` show for it?
- The same diff as before
- Nothing — there are no unstaged changes left
- The whole file
- An error
Answer: Nothing — there are no unstaged changes left. Once staged, the change lives in the index, so git diff (working vs index) shows nothing for it.
Why is the staging area useful for crafting clean commits?
- It compresses files
- It lets you group only related changes into one focused commit
- It speeds up pushes
- It prevents merge conflicts
Answer: It lets you group only related changes into one focused commit. Staging selectively means each commit can contain one logical change instead of a messy grab-bag.
Continue this course
- Previous: Git Workflows and Best Practices
- Next: Undoing Changes: restore, reset & revert — Safely undo mistakes — restore files, reset commits, or revert in public history
- Quick reference: Git cheat sheet › Staging & Committing
Frequently asked questions
What exactly is the staging area?
The staging area — also called the index — is a holding space between your working directory and your repository history. When you run git add, Git copies the current state of those changes into the index. Your next git commit snapshots exactly what's in the index, nothing more, nothing less. This two-step design lets you craft a focused commit instead of being forced to commit every change at once.
What's the difference between git diff and git diff --staged?
Plain git diff compares your working directory against the index, so it answers 'what have I changed but not staged yet?'. git diff --staged (also written --cached) compares the index against your last commit, answering 'what will my next commit actually contain?'. If you've already added a file, plain git diff shows nothing for it because the change now lives in the index.
Should I just use git add . every time?
git add . is convenient but blunt — it stages every change in the current directory, which can sweep in debug prints, unrelated edits, or files you didn't mean to commit. For tidy history, prefer naming files explicitly or using git add -p to stage changes hunk by hunk, so each commit contains one logical change.
What does git add -p do?
The -p (patch) flag puts git add into interactive mode. It breaks each file into 'hunks' of nearby changes and asks you about each one: y to stage it, n to skip it, s to split a big hunk into smaller pieces. It's the cleanest way to stage some changes from a file while leaving others for a later commit.
How do I unstage a file I added by mistake?
Run git restore --staged file.txt. That removes the file from the index (the staging area) but leaves your actual edits untouched in the working directory, so nothing is lost — the change simply goes back to being unstaged. Older guides show git reset HEAD file.txt, which does the same thing.