The index (.git/index, the staging area) is your next commit's tree kept as a flat, sorted list of paths, modes and blob hashes. git add writes a blob and records it there; git commit runs write-tree on it. So a file can have three versions at once, in HEAD, the index and the working tree:
git ls-files --stage
echo 'Runs on Node.js 24.' >> README.md
git status --short
git add README.md
echo 'Uses PostgreSQL 18.' >> README.md
git status --short100644 6f046deb11577fe2bc71307bf78265c602bf8f86 0 README.md 100644 94568a7a08dacaf7a3afeb81ba74d6e3991cb40c 0 db/schema.sql M README.md MM README.md
The first status column compares the index with HEAD, the second the working tree with the index, so MM means staged changes plus further unstaged ones. The 0 after each hash is the stage number: during a merge conflict a path appears at stages 1, 2 and 3 (base, ours, theirs) until you resolve it (Merge Conflicts). The index also caches each file's size, timestamps and inode (git ls-files --debug shows them), and a file whose metadata still matches is never reread, which is why git status is fast.