Git add and git commit confusion

git commit takes the snapshot by

  • looking at the index (where you have added the file),
  • not by looking at the working tree (where you go on modifying stuff, including adding or deleting files)

See "What's the difference between HEAD, working tree and index, in Git?"

In your case, after deleting the file (but after adding it to the index), a git status would give you:

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   go.mod

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        deleted:    go.mod

The file is both:

  • ready to be part of the next commit
  • locally deleted

A git restore -- <myFile> is enough to restore it locally.


The working tree (or working directory) is the tree of actual checked out files.
The working tree normally contains the contents of the HEAD commit’s tree, plus any local changes that you have made but not yet committed.


The idea is to prepare your next commit, instead of blindly putty all your current modification into one giant commits.
It is better to make small coherent commits instead of a giant one, for getting a logical history, and making future git bisect easier.

You can even stage (add to index) part of a file (interactive staging)

The OP adds:

Imagine that commit does the work of both the actual commit and add.
Let's call it the imaginary commit.
You can still do this little by little work using the imaginary commit

First: that command (which adds all and commit) does exist:

git commit -am "Let's add everything"

Second, to do "little by little", you must use git add, then commit.
A commit takes everything in the index.


Actually, there is something missing from what you know.

You actually have two copies of that file when you have added it. You have the working tree copy, which is the normal file system copy that you see and edit with normal text editors and whatnot.

But, additionally you have a copy in the index. git add copies the file and its contents from the working tree into the index. This is where the actual snapshot of that particular file is made.

When you afterwards issue a git commit, the index is stored into a commit. What is, or is not, in the working tree (aka on disk) at this point is rather irrelevant. The index is all that matters.

This is why you see that the file is still being added. It was copied to the index with git add, and even if you subsequently removed it from disk, git commit used the index as the source of the commit.

The upshot of having a separate index which makes up what the next commit is going to be is that you get to decide what your next commit is going to contain, as opposed to just "all the things on my disk at the moment". Good git tools even lets you copy files with only parts of their changes into the index, so that if you made 2 or more changes to a file you get to decide if all the changes to that single file go into the next commit or just one or a few of them.

Tags:

Git