The three trees: working, staging, repository
Git has three areas: the files you edit (working tree), the changes you've prepared (staging), and the committed history (repository). Every Git command moves data between these.
Git's 'three trees' is a helpful mental model — internally there are exactly three trees Git tracks: HEAD (the last commit on the current branch), the index (a binary file at .git/index listing staged content), and the working tree (filesystem state).
Working tree → index (staging): git add <path> reads the file from disk, hashes its content into a blob, and updates the index entry to point at that blob. The file in your working tree is unchanged afterward; only the index changes.
Index → HEAD (commit): git commit walks the index, builds a tree object reflecting it, creates a commit object pointing to that tree (with the previous HEAD as parent), and updates the current branch ref to point at the new commit.
Inverse operations: git restore --staged <path> un-stages (copies HEAD entry over the index entry), git restore <path> overwrites the working tree from the index. git reset --hard resets all three to the same point — destructive.
git status reads all three: it diffs working tree vs index ('Changes not staged') and index vs HEAD ('Changes to be committed'). git diff (no args) shows working tree vs index. git diff --cached (or --staged) shows index vs HEAD.
Why staging beats one-step commit: lets you git add -p to stage hunks (parts of a file), build atomic commits that group related changes, and review what you're about to commit. Mercurial historically lacked this; Git's index is one of its differentiators.
Practice
The Git workflow:
Edit a file → to stage it → to write it to history.
Grounded on https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified
Next up
Your first commit
A commit is a snapshot with a message. You stage what you want, then commit with a description of *why* you made the change. That message is the gift you give to your future self.