gittreeblobrestoremanpage

Git Index has files without using `add`


The git index allows us to specify the files that go into a new tree object - such a tree object is what any newly created commit object will point to.

I'm aware that using git add <filename> puts a file into the index so that a tree can be generated.

However, the index seems to store files even before they have been added to the index. After running the following command, even a "clean" directory will display all the same files as the commit pointed to by HEAD.

git ls-files --stage

(I assume that this displays the files in the index because stage is synonymous with index)

Why would git store "un-added" files in the index? Aren't these files available by looking at HEAD? This seems redundant.


The distinction between HEAD, index, and working tree gets even murkier when reading certain man pages. For example, this is from man git-restore.

By default, if --staged is given, the contents are restored from HEAD, otherwise from the index


Solution

  • Don't use git ls-files --stage to check your staged files, use git status.


    When a human talks to another human about git, she/he generally uses "the index" to refer to the changes you have staged in your repo.

    But from the point of view git internals: "the index" is actually the content of the current HEAD commit plus the changes you have staged.

    To give a simple illustration: when you run git diff --cached, which compares the index with the current HEAD commit, files that haven't been modified are not reported as "missing" from the index.

    git ls-files --stage just reports the content of the index (the git internal one). There are some specific cases when one may be interested in that information, but generally users are looking for git status.


    Regarding git restore: I think there is a confusion between the --staged option for git restore and the --cached option for git diff.

    ([edit] I will also say that it is pretty misleading, on the git team part, to have a command which happily combines -s,-S,--source and --staged, and I also had a few headaches before I figured out what was what with that command. The use cases make sense though, imho.)

    Note that the meaning of --staged for git restore is very different : it specifies where you want to write your files, as in "in git storage, in the index" versus "on disk, in the worktree" (my "versus" is also misleading: you can actually ask for both with git restore -SW).

    quoting the doc:

    -W, --worktree
    -S, --staged

    Specify the restore location. If neither option is specified, by default the working tree is restored. Specifying --staged will only restore the index. Specifying both restores both.

    The documentation you quote is the one for -s|--source : if -S|--staged is specified, then the default value for --source is not the same.

    So : if a file b.txt has no staged modifications, this means that the index content for that file is the same as HEAD's content, and, as you correctly observed, git restore --staged -- b.txt is a no-op.

    The uses of --staged are the other cases: