Inspecting Changes with git diff
Before saving a commit, Git allows us to inspect exactly what changed.
To understand the diff commands, remember the three important states:
- Working Tree: The files we are currently editing.
- Staging Area (Index): The version being prepared for the next commit.
- HEAD: The latest commit in the current branch.
Git provides two related commands:
git diffand:
git diff --stagedThey display different comparisons.
The important comparison map
Section titled “The important comparison map”Working Tree
The files you are currently editing.
Staging Area
The version prepared for the next commit.
HEAD
The latest commit on the current branch.
| Command | Compares | Question it answers |
|---|---|---|
git diff |
Working Tree ↔ Staging Area | What have I changed but not staged yet? |
git diff --staged |
Staging Area ↔ HEAD | What have I staged for the next commit? |
What happens to the Staging Area after a commit?
Section titled “What happens to the Staging Area after a commit?”After creating a commit, the Staging Area does not become literally empty.
Normally, its contents match the new commit:
Working Tree = Staging Area = HEADWhen tools say that the Staging Area is “empty,” they mean:
There are no staged differences waiting to be committed.
They do not mean that the Index contains no information. The Index still
represents a complete proposed snapshot of the project, and immediately after a
commit that snapshot normally matches HEAD.
Because all three states match, neither command displays any changes:
git diffgit diff --stagedPractical example
Section titled “Practical example”Suppose the latest commit contains this version of auth.js:
console.log("Application started");console.log("User login");Immediately after the commit:
Working Tree = Staging Area = HEADStep 1: Edit the file
Section titled “Step 1: Edit the file”We change auth.js to:
console.log("Application started");console.log("User authenticated");The new change exists only in the Working Tree:
Working Tree ≠ Staging Area = HEADNow run:
git diffGit displays something similar to:
diff --git a/auth.js b/auth.jsindex d32428a..0e33c45 100644--- a/auth.js+++ b/auth.js@@ -1,2 +1,2 @@ console.log("Application started");-console.log("User login");+console.log("User authenticated");This output appears because git diff compares the Working Tree with the Staging
Area.
At this moment:
git diff --stagedshows nothing because we have not staged the new modification yet. The Staging
Area still matches HEAD.
How to read the diff
Section titled “How to read the diff”A line beginning with -
Section titled “A line beginning with -”console.log("User login");This line existed in the previous version but was removed or replaced.
The - sign is added by Git to explain the difference. It is not part of the
JavaScript code.
A line beginning with +
Section titled “A line beginning with +”console.log("User authenticated");This is the new line that was added.
The + sign is also a diff marker and is not part of the code.
A line without + or -
Section titled “A line without + or -”console.log("Application started");This line did not change. Git displays it as context to help us locate the modification.
The --- and +++ lines
Section titled “The --- and +++ lines”--- a/auth.js+++ b/auth.jsThese labels represent the old and new sides of the comparison.
The a/ and b/ prefixes are comparison labels. They do not mean that Git
created two physical folders.
The @@ line
Section titled “The @@ line”@@ -1,2 +1,2 @@This is a hunk header. It identifies where this group of changes appears in the compared versions.
Beginners do not need to memorize its numbers yet.
Step 2: Stage the change
Section titled “Step 2: Stage the change”Now run:
git add auth.jsgit add updates the Staging Area with the current version of auth.js.
The state becomes:
Working Tree = Staging Area ≠ HEADNow the default command:
git diffshows nothing.
This does not mean that the modification disappeared. It means there is no longer a difference between the Working Tree and the Staging Area.
To inspect what is staged for the next commit, run:
git diff --stagedGit displays:
diff --git a/auth.js b/auth.jsindex d32428a..0e33c45 100644--- a/auth.js+++ b/auth.js@@ -1,2 +1,2 @@ console.log("Application started");-console.log("User login");+console.log("User authenticated");The output may look similar, but the comparison is now different:
Staging Area ↔ HEADTherefore, git diff --staged answers:
What changes are currently prepared for the next commit?
--staged does not stage the files. It only displays changes that were already
staged using git add.
Step 3: Create the commit
Section titled “Step 3: Create the commit”After reviewing the staged changes, we can create the commit:
git commit -m "Update authentication message"The commit records the staged snapshot in the repository history.
After the commit, the states normally match again:
Working Tree = Staging Area = HEADTherefore:
git diffgit diff --stagedboth display nothing.
Why do we need commits if the Staging Area contains a snapshot?
Section titled “Why do we need commits if the Staging Area contains a snapshot?”The Staging Area is only a temporary preparation area for the next commit. It is not a permanent historical checkpoint.
Its contents can be changed whenever we run git add again.
A commit, however, creates a recorded point in the project history. It includes:
- The project snapshot.
- A commit ID.
- A commit message.
- Author information.
- Date and time.
- A link to its parent commit.
The Staging Area prepares the next snapshot, while the commit permanently records that snapshot in the project history.
A useful analogy is:
The Staging Area is the preview before taking a photograph. The commit is the photograph saved in the album.
Important second-edit example
Section titled “Important second-edit example”Suppose we stage auth.js:
git add auth.jsThen we edit the same file again without running git add a second time.
The file now has two relevant versions:
- The first modification is in the Staging Area.
- The second modification exists only in the Working Tree.
In that situation:
git diffshows the new unstaged modification.
While:
git diff --stagedshows the earlier modification already prepared for the next commit.
This demonstrates that git add stages the file’s contents as they exist at the
moment the command is executed. Later edits are not staged automatically.
Important note about untracked files
Section titled “Important note about untracked files”The default git diff normally does not display the contents of a completely
untracked file because Git does not yet have an earlier tracked version to
compare it with.
English summary
Section titled “English summary”git diffWorking Tree ↔ Staging AreaShows unstaged changes.
git diff --stagedStaging Area ↔ HEADShows staged changes prepared for the next commit.