How it works
The explanation, with examples you can run.
Watch a file in all three places
git init -q -b main demo && cd demoecho "hello" > greeting.txtgit add greeting.txt && git commit -q -m "Add greeting"echo "hello, world" > greeting.txtgit add greeting.txtecho "hello, world!" > greeting.txtgit status --shortMM greeting.txtThe two letters are two comparisons. The first column is index against HEAD (staged), the second is working tree against index (not staged). Here both differ, so there are three versions of greeting.txt. The two diffs show each step:
git diff --stagedgit diffdiff --git a/greeting.txt b/greeting.txtindex ce01362..4b5fa63 100644--- a/greeting.txt+++ b/greeting.txt@@ -1 +1 @@-hello+hello, worlddiff --git a/greeting.txt b/greeting.txtindex 4b5fa63..270c611 100644--- a/greeting.txt+++ b/greeting.txt@@ -1 +1 @@-hello, world+hello, world!The index lines in each diff header show the blob hashes: ce01362 is in HEAD, 4b5fa63 is in the index, 270c611 is the working-tree version, which has no object yet. That middle blob was written by git add before any commit:
git ls-files --stagegit cat-file -t 4b5fa63100644 4b5fa63702dd96796042e92787f464e28f09f17d 0 greeting.txtblobgit ls-files --stage lists the index: mode, blob, stage number (0 normally; 1 to 3 during a merge conflict) and path. A commit now would record hello, world without the !.
Why have a middle step
The index lets you build a commit deliberately rather than committing whatever happens to be on disk:
- Split work into clean commits.
git add -pshows each change hunk by hunk and stages only the ones you choose, so a bug fix and an unrelated rename go into separate commits. - Review before committing.
git diff --stagedis exactly the change the commit will contain. - Merges use it. During a conflicted merge the index holds several versions of a file at once; resolving means writing one version back at stage 0 (see the conflicts topic).
- It makes status fast. The index caches file sizes and timestamps, so Git can tell which files might have changed without hashing every one of them.
git commit -a stages changes to files Git already tracks and commits in one step; new files still need git add. To take something out of the index without touching your edits, use git restore --staged <path> (covered with the other undo commands).
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.