Section 1 · Git's Model
The Three Areas: Working Tree, Index, Repository
16 min4 min readFill in the blanks
Lesson at a glance
Move changes deliberately between the working tree, the staging area and the repository, check each step with status and diff, and split messy work into focused commits.
- 1Three places your work can be
- 2Seeing the difference: status and two diffs
- 3Splitting one file into two commits
- 4How big should a commit be?
- 5Short status, and backing out
No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.
You spent an evening on the portfolio. You added a navigation bar to index.html, created styles.css, and fixed a typo in your name along the way. That’s three unrelated changes. If you commit them together as “updates”, future you can’t undo the nav without also undoing the typo fix. Git gives you a place to sort changes before they become history.
Three places your work can be
Every change in a Git project lives in one of three places:
- The working tree is the files on disk, the ones your editor opens. You can change them freely; Git only watches.
- The index, also called the staging area, is the next commit being assembled.
git addcopies a file’s current content into it. - The repository is the commits already recorded, inside
.git.git committurns the index into a new commit.
After a commit, the index isn’t emptied. It still holds the full snapshot you just committed, so it matches the last commit until you stage something new. That’s why “staged changes” means the difference between the index and the last commit.
Seeing the difference: status and two diffs
Here’s the evening’s work, checked with git status:
On branch main
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: index.html
Untracked files:
(use "git add <file>..." to include in what will be committed)
styles.css
no changes added to commit (use "git add" and/or "git commit -a")git status tells you which files differ. To see the lines, use git diff, and remember there are two comparisons:
git diff # working tree vs index: what you haven't staged yet
git diff --staged # index vs last commit: what the next commit will contain--cached is an older synonym for --staged; you’ll see both in tutorials. Get into the habit of running git diff --staged right before every commit. It’s the last moment to notice a stray console.log or a file that doesn’t belong.
Splitting one file into two commits
The typo fix and the nav bar are both in index.html. git add index.html would stage both. Stage just the typo instead:
git add -p index.htmlGit shows each changed block, called a hunk, and asks Stage this hunk [y,n,q,a,d,s,e,?]? (newer versions list a few more letters; ? explains them all). Answer y for the typo hunk and n for the nav hunk (s splits a hunk that’s too big). Then:
git diff --staged # only the typo fix
git commit -m "Fix spelling of name in header"
git add index.html styles.css
git commit -m "Add navigation bar with base styles"Two commits, each with one purpose. Later, if the nav bar needs to go, you can undo that commit alone.
How big should a commit be?
A good commit does one thing you could describe in a short sentence without the word “and”. “Fix spelling of name in header” passes. “Add nav, fix typo, tweak colours” fails, and the failure shows up later: when the colours turn out wrong, undoing that commit also removes the nav and brings back the typo.
There’s no line limit. A commit that renames a CSS class across twelve files is still one idea, and splitting it would leave the site broken in between. Aim for commits where the project still works before and after, each one a step you could explain to a reviewer in one breath. You’ll appreciate this in section 4, when undoing a single commit becomes a one-line command instead of an afternoon of surgery.
Short status, and backing out
git status -s packs the same information into two columns: the left is the index versus the last commit, the right is the working tree versus the index.
M README.md
M index.html
MM styles.css
?? projects.htmlREADME.md is staged; index.html has unstaged changes; styles.css has some of each; projects.html is untracked.
To take a file out of the index without losing your edits, use git restore --staged styles.css. To throw away unstaged edits and go back to the index version, use git restore styles.css. The second one is the only command in this lesson that destroys work: changes that were never staged or committed can’t be recovered.
You can now record exactly the history you mean to. Next you’ll read that history back, and see why Git calls it a graph rather than a list.
Key takeaways
- The working tree is your files, the index (staging area) is the next commit being assembled, and the repository is the commits already recorded.
git diffcompares the working tree to the index;git diff --stagedcompares the index to the last commit.git add -pstages part of a file, so one messy editing session can become several focused commits.git restore --staged <file>unstages and keeps your edits;git restore <file>throws your unstaged edits away.git commit -astages modified tracked files only; brand-new files still needgit add.