What is the difference between git diff HEAD vs. git diff --staged?

Git diff is a very useful command to show the difference between different states of the repository. In this article, we will explore the different options of the git diff command.

The git diff command has a lot of options and can be used to compare the working directory with the staging area (index), or the staging area with a commit, or a commit with the working directory.

That diagram is a TLDR for this article:

head HEAD dir working directory head--dir git diff HEAD index staging area (index) head--index git diff --staged index--dir git diff

Setup

To explore these different options, let’s create a repository with 4 commits.

The commit graph looks like this:

alina

86c453330fc9343ff9082d54ceffmainHEAD

diff between commits

You can use git diff commit1 commit2 to compare two commits.

alina

alina git:( main ) git diff 30fc93 86c453

diff --git a/README.md b/README.md

index b126713..a17ddff 100644

--- a/README.md

+++ b/README.md

@@ -1,3 +1,4 @@

 commit #1

 commit #2

 commit #3

+commit #4

alina git:( main )

You can also use the HEAD~n notation to refer to the n-th parent of the current commit.

alina

alina git:( main ) git diff HEAD^1 HEAD

diff --git a/README.md b/README.md

index b126713..a17ddff 100644

--- a/README.md

+++ b/README.md

@@ -1,3 +1,4 @@

 commit #1

 commit #2

 commit #3

+commit #4

alina git:( main )

file modified in working directory, not staged

Things get more interesting when you modify a file in the working directory.

We added a line to the README.md file, and now git status reports that the file is modified.

alina

alina git:( main ) git status

On branch main

Changes not staged for commit:

  (use "git add <file>..." to update what will be committed)

  (use "git restore <file>..." to discard changes in working directory)

        modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")

alina git:( main )

Technically, there are now 3 versions of the README.md file:

  • the one in the last commit
  • the one in the working directory
  • the one in the staging area

The git diff command can compare any two of these versions.

Here is a diagram showing the options for git diff and what they compare:

head HEAD dir working directory head--dir git diff HEAD index staging area (index) head--index git diff --staged index--dir git diff

git diff HEAD

Using git diff HEAD, we can see the changes made between your file in the working directory and the last commit.

alina

alina git:( main ) git diff HEAD

diff --git a/README.md b/README.md

index a17ddff..be9b03f 100644

--- a/README.md

+++ b/README.md

@@ -2,3 +2,4 @@ commit #1

 commit #2

 commit #3

 commit #4

+commit #5

alina git:( main )

git diff

The git diff command compares the working directory with the staging area.

alina

alina git:( main ) git diff

diff --git a/README.md b/README.md

index a17ddff..be9b03f 100644

--- a/README.md

+++ b/README.md

@@ -2,3 +2,4 @@ commit #1

 commit #2

 commit #3

 commit #4

+commit #5

alina git:( main )

git diff —staged

The git diff --staged command compares the staging area with the last commit.

alina

alina git:( main ) git diff --staged

alina git:( main )

No difference here because we haven’t added anything to the staging area yet.

git diff commit

Using git diff <commit>, you can also compare your working directory with any commit.

alina

alina git:( main ) git diff HEAD~1

diff --git a/README.md b/README.md

index b126713..be9b03f 100644

--- a/README.md

+++ b/README.md

@@ -1,3 +1,5 @@

 commit #1

 commit #2

 commit #3

+commit #4

+commit #5

alina git:( main )

file modified in working directory, and staged

Let’s stage the file:

alina

alina git:( main ) git add README.md

alina git:( main )

git diff

This time, the git diff command shows no difference between the working directory and the staging area.

alina

alina git:( main ) git diff

alina git:( main )

git diff —staged

The git diff --staged command shows the difference between the staging area and the last commit.

alina

alina git:( main ) git diff --staged

diff --git a/README.md b/README.md

index a17ddff..be9b03f 100644

--- a/README.md

+++ b/README.md

@@ -2,3 +2,4 @@ commit #1

 commit #2

 commit #3

 commit #4

+commit #5

alina git:( main )

git diff HEAD

The git diff HEAD command shows the difference between the working directory and the last commit.

alina

alina git:( main ) git diff HEAD

diff --git a/README.md b/README.md

index a17ddff..be9b03f 100644

--- a/README.md

+++ b/README.md

@@ -2,3 +2,4 @@ commit #1

 commit #2

 commit #3

 commit #4

+commit #5

alina git:( main )

commit the staging area

Let’s create a commit with the staging area:

alina

alina git:( main ) git commit -m 'commit #5'

[main 29455b1] commit #5

 1 file changed, 1 insertion(+)

alina git:( main )

The commit graph now looks like this:

alina

29455b186c453330fc9343ff9082d54ceffmainHEAD

git diff

The git diff command shows the differences between the working directory and the index.

There are no differences between the working directory and the index.

alina

alina git:( main ) git diff

alina git:( main )

git diff —staged

The git diff --staged command shows the differences between the index and the HEAD.

It is empty because we just committed the index.

alina

alina git:( main ) git diff --staged

alina git:( main )

git diff HEAD

The git diff HEAD command shows the differences between the working directory and the HEAD.

It is also empty because we just committed the index.

alina

alina git:( main ) git diff HEAD

alina git:( main )