CHAPTER 04

The three areas

One file, two kinds of change, and only one of them is supposed to leave the building today.

Friday afternoon, 4:40 PM

You found it — the mobile nav bug. On phones under 480px, the menu button was invisible because of one wrong CSS class in index.html. Real fix, three lines, clean. While you were in there hunting for it, you also dropped in two console.log() lines to watch a variable while you debugged. Both changes are sitting in the same file, unsaved to history, right now.

Rachit leans over: "Anvesha's doing a quick review of the nav fix at 5 — can you commit it before then?"

You go to commit. And you realize: index.html is just "modified" as far as Git's concerned. There's no way to tell it "these three lines, not those two" — or is there?

The packing-table problem

Picture how the club actually preps merch orders before a workshop. There's a table with all the loose stock — T-shirts, stickers, lanyards — that's the equivalent of your working directory: everything as it currently sits, edited or not, ready or not. Before anything ships, someone portions out exactly what's going in today's box: two shirts, one sticker, no lanyard. That portioned pile, set aside but not yet sealed, is the staging area. Only once the box is taped shut — the commit — does that exact portioned set become a permanent, shippable record.

The reason this three-step process exists instead of just "seal whatever's on the table" is exactly your situation right now. The table has both the nav fix and the debug logs on it. You don't want to seal a box with debug logs in it. So you don't portion the whole table — you portion just the lines you want.

WHERE index.html IS RIGHT NOW
WORKING DIRECTORY
nav fix + 2 console.logs
git add -p
STAGING AREA
nav fix only
git commit
REPOSITORY
a clean, honest commit

Portioning one file into two piles

git add -p — "patch mode" — walks you through your changes one small chunk ("hunk") at a time and asks, for each one, whether it belongs in the box:

separating the fix from the debug lines
$ git add -p index.html
 
@@ -22,6 +22,6 @@ <nav class="mobile-menu">
- <button class="menu-btn-hiden">
+ <button class="menu-btn">
Stage this hunk [y,n,q,a,d,s,e,?]? y
 
@@ -40,3 +40,5 @@ function toggleMenu() {
+ console.log('menu state:', open)
+ console.log('width:', window.innerWidth)
Stage this hunk [y,n,q,a,d,s,e,?]? n

y puts that hunk on the portioned pile. n leaves it on the table. The nav fix is now staged; the debug logs are still sitting, unstaged, in the same physical file on your disk — Git is tracking two different versions of one file at once, and that's exactly the trick that solves your 4:40 problem.

checking before sealing the box
$ git diff --staged # exactly what's about to be committed
- <button class="menu-btn-hiden">
+ <button class="menu-btn">
 
$ git diff # exactly what's still sitting unstaged
+ console.log('menu state:', open)
+ console.log('width:', window.innerWidth)
 
$ git commit -m "fix(nav): show mobile menu button below 480px"
[main 3f8a1b2] fix(nav): show mobile menu button below 480px
1 file changed, 1 insertion(+), 1 deletion(-)

5:00 PM. Anvesha reviews a commit that contains exactly the fix, nothing else. Your debug lines are still right there in index.html, unstaged, ready for you to keep poking at the bug — or just git restore index.html to throw them away once you're done, without touching the commit you already sealed.

Naming the three areas properly

  1. Working directory — the actual files on disk. What your editor shows you, right now, edited or not.
  2. Staging area (Git's manual calls it "the index") — your portioned pile. Marked as ready, not yet permanent.
  3. Repository — the sealed boxes. Every commit you've made, living inside .git/, exactly as Chapter 3 described.

Every command you've used so far, and most of what's coming, is just a movement between these three places:

CommandMoves fromTo
git add <file>Working dirStaging (whole file)
git add -pWorking dirStaging (chosen hunks)
git commitStagingRepository
git commit -aWorking dir (tracked files)Repository — skips staging entirely
git restore --staged <file>StagingBack to working dir (unstage, keep edits)
git restore <file>Repository (last commit)Working dir (discard edits)

The trap: editing after staging

One thing catches almost everyone once. Say you'd staged the nav fix, then kept editing index.html a little more before committing — maybe you tightened the CSS further. That later edit does not retroactively update what you staged. Staging captured a snapshot at the moment you ran git add; anything you type afterward is a fresh, separate, unstaged change sitting on top of it.

the trap
$ git status
Changes to be committed:
modified: index.html
Changes not staged for commit:
modified: index.html # same file, listed twice — two different versions

If you commit right now, only the staged version ships. Run git add again first if you want your later edits included too. This is exactly why git status before every commit is worth the two seconds — it's the only place that shows you both piles at once.

CHECK
You staged index.html with git add, then edited index.html again. You run git commit right now. What gets recorded?
Staging is a snapshot taken at the moment you run git add, not a live link to the file. Whatever you typed after that moment sits in the working directory, unstaged, until you stage it too.

The commit's in. Anvesha approves it at 5:03. But now it's the following Thursday, the "temporary" homepage preview you've been sharing with the Board looks subtly broken — a spacing issue that definitely wasn't there Monday — and nobody remembers which of the forty-odd commits since then caused it.