Logan Lee
Logan Lee

Reputation: 987

git ls-files --stage shows files even after committing

I'm after git command that shows all files currently residing inside staging area (is it the same as index?).

First I removed all files from index:

$ git rm --cached *
rm 'newfile'
rm 'os-list.txt'
rm 'remote_stuff'
rm 'removethis'

Now I check files in index:

$ git ls-files --stage
100644 07e6e472cc75fafa944e2a6d4b0f101bc476c060 0       .gitignore

You can see only .gitignore file is left.

We then change the content of newfile. Then we add newfile to index.

$ git add newfile

Check the status:

$ git status -s
M  newfile
D  os-list.txt
D  remote_stuff
D  removethis
?? os-list.txt
?? remote_stuff
?? removethis

We can see newfile is now in index.

Now we expect staging area to be empty when we commit the files.

$ git commit -m "TEST333"
[master 0adab53] TEST333
 4 files changed, 1 insertion(+), 13 deletions(-)
 delete mode 100644 os-list.txt
 delete mode 100644 remote_stuff
 delete mode 100644 removethis

But even after commit we see newfile is still in staging area:

$ git ls-files --stage
100644 07e6e472cc75fafa944e2a6d4b0f101bc476c060 0       .gitignore
100644 76abab2928bdd7dfe157109666023bb0c5e4c465 0       newfile

But if we check status we see there's nothing in staging area:

$ git status -s
?? os-list.txt
?? remote_stuff
?? removethis

Well, what I'm after is the command to show all files in staging area. The command git ls-files --stage is returning output that I don't understand.

Thanks!

Upvotes: 3

Views: 1500

Answers (1)

torek
torek

Reputation: 487993

Now we expect staging area to be empty when we commit the files.

That's your error. Don't expect this!

... if we check status we see there's nothing in staging area

git status does not show you what is in the index / staging-area. Instead, for each file, it compares what's in the index / staging-area to:

  • what's in the HEAD commit: if different, the file is "staged for commit"; and
  • what's in the work-tree: if different, the file is "not staged for commit"

—which is why a file can be both "staged for commit" and "not staged for commit". That just means that the index copy, the one you see with git ls-files --stage, differs from both of the other two copies.

Every file has three active copies.1 When all three are the same, git status says nothing. When some of the copies of file F differ, git status tells you about file F. That's all there really is to it, here.

The index / staging-area holds, at all times,2 what you plan (or Git plans) to put in your next commit. That's why you have to update it after changing the work-tree copy: so that what Git plans to put in the next commit will match the work-tree copy.


1Technically, it's up to three copies, since you can have one or two copies missing. A file is tracked if and only if there is a copy of it in the index (even if it's in the HEAD commit, it's only tracked if it's also in the index). A work-tree file is untracked if it exists and is not in the index. (Hence, after git rm --cached, a file that is in HEAD and in the work-tree is both about-to-be-deleted, and untracked, at the same time.)

2See footnote 1, and then see the conflicted merge case. During a conflicted merge, the index holds up to three copies of each file: the merge base copy, the --ours copy, and the --theirs copy. If you add in the HEAD copy and the work-tree copy, this means that during conflicted merges, there are up to five active copies of any one file.

Upvotes: 5

Related Questions