Aller au contenu

Comparing versions

git show displays the changes introduced by one commit. To compare any two versions of a file (the version you are editing, the staged version, or two past commits), use git diff.

git diff: differences between versions

Command Compares
git diff The working directory with the staging area, for all files
git diff report.md Same, for one file

When nothing is staged, the staging area contains the same thing as the last commit. In that case, git diff report.md shows what changed in report.md since the last commit.

Correction: git diff compares with the staging area

The course describes git diff as comparing unstaged files with the latest commit. Strictly speaking, git diff without options compares the working directory with the staging area (the index). It shows changes that are not yet staged. The two descriptions only give the same result when nothing is staged for that file. If you stage part of your changes, git diff no longer shows them. Use git diff --staged for those. Source: git diff documentation.

Comparing to an unstaged file

Suppose report.md was edited after the last commit, and not staged. git diff report.md produces:

$ git diff report.md
diff --git a/report.md b/report.md
index 6218b4e..066f447 100644
--- a/report.md
+++ b/report.md
@@ -1,5 +1,5 @@
 # Mental Health in Tech Survey
-TODO: write executive summary.
 TODO: include link to raw data.
 TODO: add references.
 TODO: add summary statistics.
+TODO: cite funding sources.

Reading the output

Line Meaning
diff --git a/report.md b/report.md The file being compared. Version a is the older one (here the last commit). Version b is the newest one (here the working directory).
index 6218b4e..066f447 100644 Short hashes of the two blobs (old..new), and the file mode (100644, a regular file)
--- a/report.md Lines from version a are marked with -
+++ b/report.md Lines from version b are marked with +
@@ -1,5 +1,5 @@ Hunk header: where the changes are. -1,5 means "starting at line 1, 5 lines of version a"; +1,5 means "starting at line 1, 5 lines of version b".
# Mental Health in Tech Survey A line starting with a space is unchanged (context)
-TODO: write executive summary. A line starting with - was removed (shown in red in a colour terminal)
+TODO: cite funding sources. A line starting with + was added (shown in green)

In this example, one line was removed and one was added, so both versions have 5 lines in the hunk. A modified line appears as one removed line followed by one added line.

Comparing to a staged file

After git add, the change is in the staging area, so plain git diff shows nothing. Use --staged to compare the staging area with the last commit:

git add report.md
git diff --staged report.md   # last commit vs staged version of report.md

The output format is identical; only the two versions compared change.

To compare all staged files with the last commit:

git diff --staged

This is a good check just before git commit: it shows exactly what the commit will record. --cached is a synonym of --staged.

Comparing two commits

  1. Find the commit hashes with git log.
  2. Pass both hashes to git diff:
git diff 35f4b4d 186398f

This shows what changed from the first commit to the second one. Put the older commit first and the most recent commit second, so that additions appear with +:

$ git diff 35f4b4d 186398f
diff --git a/report.md b/report.md
index 35f4b4d..186398f 100644
--- a/report.md
+++ b/report.md
@@ -1,3 +1,4 @@
 # Mental Health in Tech Survey
 TODO: write executive summary.
 TODO: include link to raw data.
+TODO: remember to cite funding sources!

The hunk header @@ -1,3 +1,4 @@ shows that the section went from 3 lines to 4: one line was added.

Note

This course example compares commits whose hashes look like the blob hashes in the index line. In a real repository, commit hashes and blob hashes are different objects with different values.

Using HEAD instead of hashes

HEAD refers to the latest commit of the current branch. Instead of looking up hashes, you can count back from it:

Reference Meaning
HEAD The most recent commit
HEAD~1 The commit before it (second most recent)
HEAD~2 Two commits before HEAD (third most recent)
git diff HEAD~1 HEAD   # changes introduced by the most recent commit

Order matters

The course summary lists git diff HEAD~1 HEAD~2. This command is valid, but it compares from the newer commit (HEAD~1) to the older one (HEAD~2). The result is "reversed": lines added in history appear with -, and removed lines appear with +. To see the changes in chronological order, write the older commit first: git diff HEAD~2 HEAD~1.

Summary

Command Function
git diff Changes in all files that are not staged (working directory vs staging area)
git diff report.md Same, for one file
git diff --staged Changes in all staged files compared with the latest commit
git diff --staged report.md Same, for one file
git diff 35f4b4d 186398f Changes between two commits, using hashes (older first)
git diff HEAD~1 HEAD Changes between two commits, using HEAD syntax

Challenge: compare versions at every stage

Objective: use git diff to compare the working directory, the staging area, and past commits, and interpret the output.

Prerequisites and initial state: Git installed. The setup creates ~/git-practice/diff with a report in three commits.

Setup:

mkdir -p ~/git-practice/diff && cd ~/git-practice/diff
git init -q -b main
git config user.name "Practice User"
git config user.email "[email protected]"
printf '# Mental Health in Tech Survey\nTODO: write executive summary.\n' > report.md
git add . && git commit -q -m "Create report"
echo "TODO: include link to raw data." >> report.md
git commit -q -am "Add raw data reminder"
echo "TODO: add references." >> report.md
git commit -q -am "Add references reminder"

Tip

git commit -am "..." stages every already-tracked modified file and commits in one step. It is used here only to build the history quickly; it does not add untracked files.

Tasks:

  1. Replace the line TODO: write executive summary. with TODO: cite funding sources. in report.md (with an editor or sed), without staging it. Show the change with git diff.
  2. Stage the file. What does git diff show now? Which command shows the staged change?
  3. Without using hashes, show the change introduced by the most recent commit.
  4. Show all changes between the first commit and the most recent commit, using HEAD references.
  5. Run git diff HEAD HEAD~2, then compare its +/- signs with those of task 4.

Expected result and verification:

  1. One line starting with -TODO: write executive summary. and one line starting with +TODO: cite funding sources..
  2. git diff prints nothing, while git diff --staged prints the same diff as in task 1.
  3. A single added line: +TODO: add references..
  4. Two added lines: the raw data and references reminders.
  5. The same two lines, but with - instead of +.
Solution
# 1. Unstaged change
sed -i 's/TODO: write executive summary./TODO: cite funding sources./' report.md
git diff                 # working directory vs staging area

# 2. Staged change
git add report.md
git diff                 # empty: nothing is left unstaged
git diff --staged        # staging area vs last commit

# 3. Changes introduced by the latest commit
git diff HEAD~1 HEAD

# 4. From the first commit to the latest one
git diff HEAD~2 HEAD

# 5. Reversed order
git diff HEAD HEAD~2
  • After git add, the change moves from "unstaged" to "staged". This is why plain git diff becomes empty and --staged is needed.
  • The repository has three commits, so the first one is HEAD~2.
  • Swapping the two references reverses the meaning of the diff: additions appear as deletions. Put the older version first.
  • Tasks 3 to 5 compare commits, so the staged change from task 2 does not appear in them.

Clean up when you are done: rm -rf ~/git-practice/diff.