how can git commit -a work after i remove a file from index

276 views Asked by At

Suppose I have tracked file empty.txt. Now I remove file from working directory using rm empty.txt . Now I am removing file from index using git rm empty.txt and now file should be untracked since I have removed it from index. After this I used git commit -a -m "remove empty.txt" but how it is working as -a parameter is used to skip explicitly adding tracked file to staging area but I already removed file from index? It should be untracked.

2

There are 2 answers

1
matt On BEST ANSWER

You have two possible misconceptions:

  • This has nothing to do with "tracking".

  • A git commit is not about changes. It is a snapshot, a photograph, of your entire set of files, as reflected in the index, which is itself a complete copy of your entire set of files.

If you take a photograph of a dog standing among two trees, the photograph contains a dog and two trees. That is a commit.

If the dog walks away and you take another photograph, the photograph contains the two trees but not the dog. It wasn't there when you took that photograph. That is another commit.

There is no "removal" action involved in the creation of the second commit. It isn't a modification of the first photograph. It's just a photograph of what is.

In the case of a git commit that you create, "what is" is the index, plain and simple (by default; there are ways around this, by saying git commit someFile, but ignore that for our purposes).


Okay, so, on to the details of your question. You say:

i remove file from working directory using rm empty.txt

now i am removing file from index using git rm empty.txt

after this i used git commit -a

So:

  • If you remove a file from the working tree, git commit -a automatically removes that file from the index as well (as if by calling git rm --cached) before making the commit. The file is now not in the index and therefore the commit created from it is missing that file (just like the dog).

  • In your case, you yourself removed the file from both the working tree and the index. So now the -a part of git commit -a has no work to do with regard to the index as far as this file is concerned; you already did that work. And now very same operation occurs: the file is now not in the index and therefore the commit created from it is missing that file (just like the dog).

0
Mark Adelsberger On

Initially I thought the docs were pretty clear about this, but after testing there is a bit of a weird case here...

So for the most part, the -a flag is going to skip the index and apply the changes from your worktree. Deleting a file is a change. My reading of the (perhaps ambiguous) docs would suggest that the index would be basically ignored, except that new files wouldn't be added.

There's some weirdness in the case where a file in the previous commit is removed from the stage, though. What my tests show is, in this case the file is removed from the new commit based on being removed from the index; and then any further changes in the work tree (i.e. if the file was recreated) are ignored. In that sense, what OP observed is consistent - it's just hard to get that out of a reading of the docs.

It is too bad, because it ruins a bunch of seemingly-true simple statements that would describe the behavior; but here it is:

git init
touch file1
git add .
git commit -m "initial commit"

echo CHANGES > file1
git rm --cached file1
git status

# this will show a staged change to remove the file, and an untracked file
# with the CHANGES

git commit -a -mtest

...and now the commit has an empty directory, and file1 is untracked. And with that in mind, the case in the question is just the degenerate case where the change in the worktree is the same as the change in the index.