dangerChihuahua007
dangerChihuahua007

Reputation: 20875

Why can't I see a file in git diff if I reset it?

I am aware that git reset myFile.txt untracks myFile.txt.

If I make a file myFile.txt in a git repo, and then call git diff, I can see myFile.txt listed as a difference. I can't see myFile.txt as a difference after I add it. This is expected since I am now tracking the file.

However, if I use git reset myFile.txt to untrack myFile.txt, I can't see myFile.txt listed in git diff. Why is that? Isn't git diff supposed to show me my untracked changes?

Upvotes: 3

Views: 1553

Answers (2)

Code-Apprentice
Code-Apprentice

Reputation: 83517

git diff runs a diff against the files in the repo's index. If the file is not yet tracked, it is not in the index, so you will not see it listed in the output of git diff.

When you run git add, git adds the file to the index. This means that a subsequent git diff will show the file in the output.

To see files that are untracked, run git status instead.

Upvotes: 1

John Szakmeister
John Szakmeister

Reputation: 46992

git reset doesn't always untrack the file. It only does that if it wasn't being tracked before. git diff only shows you unstaged changes. If the file is untracked, git ignores it except in status output, where it let's you know that there's a file that you may want to track. Let's start off with a clean repository:

$ git init practice
$ cd practice

Now, let's add a file:

$ echo "Hello World" > hello.txt

At this point, git status says the file is untracked:

$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   hello.txt
nothing added to commit but untracked files present (use "git add" to track)

So doing a git diff here will show us nothing, since git is essentially ignoring the file right now:

$ git diff

Now, let's add hello.txt to the index:

$ git add hello.txt
$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#   new file:   hello.txt
#

git diff still shows us nothing:

$ git diff

The reason for this is because git diff will tell you the difference between the index and the working tree. Now that we've added hello.txt to the index, the working tree matches, so there's nothing for git diff to show.

If you'd like to see what is staged for commit, try git diff --cached:

$ git diff --cached
diff --git a/hello.txt b/hello.txt
new file mode 100644
index 0000000..557db03
--- /dev/null
+++ b/hello.txt
@@ -0,0 +1 @@
+Hello World

Just for reference, here is the help from the --cached command line option:

This form is to view the changes you staged for the next commit relative to the named <commit>. Typically you would want comparison with the latest commit, so if you do not give <commit>, it defaults to HEAD. If HEAD does not exist (e.g. unborned branches) and <commit> is not given, it shows all staged changes. --staged is a synonym of --cached.

When you do a reset at this point, you're not simply unstaging the contents of the file, git goes back to seeing the file as untracked:

$ git reset hello.txt
$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   hello.txt
nothing added to commit but untracked files present (use "git add" to track)

As a result, git diff won't show you anything. Even if you did a git commit -a, the file wouldn't get committed because it is untracked.

Once the file is tracked, the story changes. So let's add it, and commit it:

$ git add hello.txt
$ git commit -m "Initial commit."
[master (root-commit) 67cb14e] Initial commit.
 1 file changed, 1 insertion(+)
 create mode 100644 hello.txt
$ git status
# On branch master
nothing to commit, working directory clean

Now, let's add more text:

$ echo "Hello again" >> hello.txt
$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   hello.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

The output of git status has changed. We now see hello.txt as modified, whereas before it was untracked. Now git diff works because the file exists in the index and is being tracked. The index version is whatever you have staged, or it matches the last commit (HEAD), if you haven't staged anything:

$ git diff
diff --git a/hello.txt b/hello.txt
index 557db03..49e9db5 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1 +1,2 @@
 Hello World
+Hello again

Let's stage it and look at the diff:

$ git add hello.txt
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   hello.txt
#
$ git diff

Now we're back to seeing no difference because what's in the index matches the working tree. Let's reset: $ git reset hello.txt Unstaged changes after reset: M hello.txt

Now we can see the changes again:

$ git diff
diff --git a/hello.txt b/hello.txt
index 557db03..49e9db5 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1 +1,2 @@
 Hello World
+Hello again

Git didn't untrack the file here, it just reset the content of the index. The file is still being tracked. Let's add hello.txt to the index and make a change just to demonstrate one last part about comparing to the index:

$ git add hello.txt
$ echo "One final change" >> hello.txt
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   hello.txt
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   hello.txt
#

So now we see that hello.txt has some changes staged for commit, and some that are not:

$ git diff
diff --git a/hello.txt b/hello.txt
index 49e9db5..97849b8 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1,2 +1,3 @@
 Hello World
 Hello again
+One final change

Notice it only shows the "One final change" line as being added. That's because git diff is comparing the working tree against the index, and we added the "Hello again" line into the index when we did the last git add. This does not show what changes are staged for commit though. For that, we go back to git diff --cached:

$ git diff --cached
diff --git a/hello.txt b/hello.txt
index 557db03..49e9db5 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1 +1,2 @@
 Hello World
+Hello again

At this point, let's reset and restore the index to the version in HEAD:

$ git reset hello.txt

Since we no longer have any changes staged, git diff --cached comes back clean:

$ git diff --cached

And git diff will show both changes:

$ git diff
diff --git a/hello.txt b/hello.txt
index 557db03..97849b8 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1 +1,3 @@
 Hello World
+Hello again
+One final change

Hopefully, that helps you to see how changes are transferred back and forth between the working tree and the index, that untracked files are essentially ignored, and how to see changes that have been staged. The best visualization I've seen of this is NDP Software's Git Cheatsheet which shows you how commands move content between the various stages in git.

Upvotes: 6

Related Questions