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
b.txt
is edited but not added to the index (i.e. git status
shows red letters), then the version of b.txt
in the index
is the same as in HEAD
. However, git restore --staged -- b.txt
does nothing whereas git restore -- b.txt
restores the working tree to the version in the HEAD
commit.stage
is synonymous with index
then why would --staged
refer to HEAD
in this man
page?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, --stagedSpecify 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:
git restore --staged -- b.txt
would unstage staged changes if there were anygit restore -s that/other/commit --staged -- b.txt
will put in the index the content of b.txt
coming from that/other/commit
, without changing the worktree