Here's how to to understand the staging area. I'll call it the "index".
First, some names:
Okay, here we go.
The first thing to understand is that every commit contains all your files. By that I mean that if you have commited files A, B, and C, and you then change just C and add-and-commit, there is a bad tendency to think that the resulting commit consists of "just C" or even "just the change in C". That is false. A commit is a complete snapshot of all the files.
Now, when you checkout
a branch, which is always the start of operations, two things happen: the contents of the commit at the end of the branch are copied into the index and the worktree, both. So now, what you see (the worktree) and what's in the index are the same. If that branch's last commit contains A, B, and C in a certain state, now so does the worktree and so does the index.
So now we are ready for the edit-add-commit cycle:
You edit a file in the worktree (let's pick C). That has no effect on the index.
Next, you add that file; now the way C looks in the index matches the way it looks in the worktree, and vice versa. That is what "add" actually means.
Finally, you commit, and what happens? Git looks only at the index. It just wraps all of those files up and snapshots them, kaboom. That means A as it was before, B as it was before, and C as modified because you did an add
of C in the modified state.
Okay, so now we appreciate what the index is for. It is the place where you are constantly building what should go into the next commit.
Note that the index can be committed without corresponding to exactly what's in the worktree. You could modify C and D and add
only C and commit. Now D is still sitting there modified in your worktree. No problem! That is why it is so nice to have a distinction between the worktree and the index.
So, to sum up: you work in the worktree. Based on your work, you construct the index; you can make it look as much like the worktree as you like, but it doesn't have to be identical to it. Finally, you commit, which mean you wrap up exactly the index as a commit. And on you go.
I should probably add: the files in the index are also the tracked files. When you say git status
, git simply compares the contents of the index to the contents of the worktree and divides what it sees into various groups:
Things that are identical in both places. These are the tracked unmodified files. But git status
does not bother to mention these, which is why people are so confused about what is "in" the index or what is "in" a commit.
Things that are present in both places but differ. These are the modified, tracked files.
Things that are present in one place but not the other. Git might remark upon these as untracked files, deleted files, and so on, depending on the nature of the difference.