0

I read from the man page for git diff that it should return "changes in the working tree not yet staged for the next commit". If I understood what the working tree is (it should be your local git repo working folder) when I add a new file to the my working directory I should see it returned by git diff and yet it return nothing. What I'm not getting?

whatever
  • 2,492
  • 6
  • 30
  • 42
  • 2
    Did you add that new file to git? *Does* it contains any changes? – jonrsharpe Jun 16 '20 at 20:15
  • Well done @jonrsharpe the files I added to the working tree were indeed all empty, once they have any content they are correctly returned by `git diff` – whatever Jun 16 '20 at 20:22

2 Answers2

1

Once you add a file (as in, I add it to index, which is what we normally mean when we say we add stuff in relation to git), it goes into the staged for next commit status and so it will go away from git diff by default. It will still be visible if you try git diff HEAD, though.

eftshift0
  • 26,375
  • 3
  • 36
  • 60
1

This has nothing to do with size. It has to do with how git "sees", and what you are asking for a difference between.

  • First, there are three places: the HEAD (the most recent commit), the index (what you add to), and the worktree. So there are two "simple diff" commands:

    • git diff asks about differences between index and worktree.
    • git diff --cached asks about differences between HEAD and index.
  • Second, what's not in the HEAD or the index does not exist as far as git is concerned; it is "untracked".

If a file is tracked (it's in the index or the HEAD), then changes in the worktree but not in the index are unstaged. But if a file is not tracked, then changes in the worktree are untracked; they have not yet reached the level of being unstaged, and they will not be in either kind of diff.

Okay. So when you first create a file, whether it has size or not, it is not yet in git's purview at all (it is untracked), so it is not part of any diff:

$ touch Z # this one has no size
$ echo testing > ZZ # this one has size
$ git diff # (crickets...)
$ git diff --cached # (crickets...)

Then when you add that file, now git knows about it (it is tracked). There is still no diff between the index and the workspace, because the index is identical to the workspace; you just copied those files from the latter to the former! But now a difference between HEAD and the index does exist:

$ git add .
$ git diff # (crickets...)
$ git diff --cached
diff --git a/Z b/Z
new file mode 100644
diff --git a/ZZ b/ZZ
new file mode 100644

Okay, so now those files are under git's supervision, because they are in the index. So now if we make a change in one of them (in the worktree), there is a difference (unstaged) between the index and worktree:

$ echo testing2 >> ZZ
$ git diff
diff --git a/ZZ b/ZZ
--- a/ZZ
+++ b/ZZ
@@ -1 +1,2 @@
 testing
+testing2

The same thing is true in reverse. To show what I mean, I'll add and commit everything; now there is no simple diff, as expected:

$ git add .
$ git commit -m'xxxx'
$ git diff # (crickets...)
$ git diff --cached # (crickets...)

Now I'll remove ZZ from the index, with rm, and from the HEAD, with commit:

$ git rm --cache ZZ
rm 'ZZ'
$ git commit -m'removed'

Now, once again, there is no difference between index and worktree, even though the file ZZ is still in the worktree:

$ git diff # (crickets...)
$ ls
Z   ZZ

That's because, since ZZ is no longer in HEAD or worktree, it is once again untracked; it is once again not part of git's purview.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • files did not show up because they were 0 bytes files. As soon as their got a size > 0 they started getting returned by a `git diff` – whatever Jun 17 '20 at 08:42
  • No, that’s a red herring idea. It’s not the size. It’s whether you’ve ever added the file. My example works the same even if you replace `touch Z` with `echo testing > Z`. And note that in the second part of my example, there is a diff even with no size. – matt Jun 17 '20 at 11:44
  • @whatever I've revised my answer to prove that it has to do with `git add`, nothing to do with "size". – matt Jun 17 '20 at 12:27
  • I'm getting lost. Shouldn't git diff show what has changed (in the working tree) but hasn't been added to the index yet via git add ? – whatever Jun 17 '20 at 12:34
  • 1
    In the third example, yes. But that is because a copy of the _file itself_ is already in the index. Do you see? If the file is not in the HEAD and not in the index, it is untracked and `git diff` doesn't see it. `git status` reports it, but it's not in git's control so it's not in a `git diff`. – matt Jun 17 '20 at 12:36
  • Added still another example, so that you see how ZZ becomes part of the diff when it is tracked and then stops being part of it if it becomes untracked again. – matt Jun 17 '20 at 12:45
  • Also your title is misleading. Distinguish between un _staged_ changes and un _tracked_ changes. I added more about that too. – matt Jun 17 '20 at 12:52
  • Someone edited my title.....this thing is sometimes pretty annoying. Thank you @wjandrea ;) – whatever Jun 18 '20 at 10:02
  • I suppose what mislead me is documentation that states $ git diff returns "Changes in the working tree not yet staged for the next commit". As I understand it, something needs to be only on your file system and not in your index to be returned. – whatever Jun 18 '20 at 10:12
  • And I’ve just shown you the _right_ way to understand it instead. – matt Jun 18 '20 at 10:38