Module 11 — Stash and Worktrees (git stash, worktree)

Updated 8 September 2026

Module 11 — Stash and Worktrees (git stash, worktree). The Advanced tier opens with two tools for one problem: an interruption arrives while your work is half-done. git stash parks messy work in seconds and gives you a clean tree; git worktree lets you check out a second branch in a second directory so you never have to park at all. Module 5's hotfix ticket — "fix production while mid-feature" — finally gets its two clean solutions.

🧠 concept → 🧩 analogy → 🧪 exercise → ✅ expected result (hidden) → 🎯 interview questions (hidden)

Before you start. You need Module 5 (branches, switching, the one-working-tree fact), Module 6 (conflicts — stash can conflict), and Module 3 (a stash is secretly commits). A fresh kitchen repo with a sourdough branch works; the exercises are self-contained and rebuild what they need.

Part A — git stash: parking work in seconds

A1. What stash saves, and where

git stash takes your uncommitted changes — modified tracked files and the staged index — records them somewhere safe, and resets your working tree to a clean HEAD. You get an instant clean slate without committing half-finished work. The changes go onto a stack (git stash list), so you can stash several times and retrieve them later. Two everyday retrievals: git stash pop reapplies the most recent stash and removes it from the stack; git stash apply reapplies but leaves it on the stack for reuse. One catch to meet head-on: by default stash ignores untracked files (Git will not touch files it does not track), so a brand-new file is left sitting in your "clean" tree — the -u flag (A3) includes them.

🧪 Exercise 11.1 — stash, get a clean tree, then pop it back
bash
cd ~/git-course/kitchen              # on main, clean
echo "experimental: add honey to bread" >> bread.txt   # modify a tracked file
echo "scratch idea" > ideas.txt                        # and create an untracked one
git status -s
git stash
git status -s                        # what got parked, what didn't?
git stash list
Expected result — click to reveal
plain text
 M bread.txt
?? ideas.txt
Saved working directory and index state WIP on main: 00235f5 Add baking
?? ideas.txt
stash@{0}: WIP on main: 00235f5 Add baking

What to read out of it: the modified bread.txt (␣M) was stashed away — gone from the working tree — but ideas.txt (??, untracked) is still there after the stash: default stash leaves untracked files behind, the surprise A3 fixes. The confirmation names the stash's auto-label: WIP on <branch>: <tip subject>, so git stash list reads as a stack of "work in progress against this point." stash@{0} is the top; further stashes push older ones to @{1}, @{2} — Module 4's reflog @{N} syntax, reused. Nothing is committed and nothing is lost.

🧪 Exercise 11.2 — pop brings it back and clears the stack
bash
cd ~/git-course/kitchen
git stash pop
git status -s
git stash list                       # empty now
Expected result — click to reveal
plain text
On branch main
Changes not staged for commit:
  ...
        modified:   bread.txt
...
Dropped refs/stash@{0} (a81ab87…)
 M bread.txt
?? ideas.txt

What to read out of it: pop reapplied bread.txt's change and then printed Dropped refs/stash@{0} — apply plus remove, in one step. git stash list is now empty. The relationship worth memorizing (interviewers ask it verbatim): git stash pop = git stash apply + git stash drop. Clean up before the next exercise: git checkout -- bread.txt && rm ideas.txt.

Real-world analogy — the coat check

You walk into a restaurant carrying bags (your uncommitted work) and need your hands free (a clean tree) to shake someone's hand. The coat check takes your things, hands you a numbered ticket (stash@{0}), and holds everything until you come back. pop is redeeming the ticket and walking out with your bags; apply is looking at your bags but leaving them checked for now.

Where the analogy stops working. A coat check holds your things exactly as given and hands them back unchanged. A stash reapplies onto whatever the tree looks like now — if the room rearranged while your coat was checked (the branch moved, files changed), reapplying is a three-way merge that can conflict (A2's exercise). Your "coat" isn't returned to an empty rack; it's re-draped over a room that may have changed shape.

A2. Stash across branches, and when pop conflicts

Official docs: git-stash manual

Stash's headline use is Module 5's hotfix scenario: mid-feature, park with git stash, switch to a clean branch, do the urgent work, switch back, git stash pop. Because a stash is not tied to a branch, you can even pop it onto a different branch — deliberately moving work you started in the wrong place. But reapplying is a merge (the analogy's punchline), so if the target's content diverged from where you stashed, pop conflicts — same markers, same resolution as Module 6, with one mercy: a conflicting pop keeps the stash rather than dropping it, so a botched reapply loses nothing.

🧪 Exercise 11.3 — force a conflicting pop, and see the stash survive
bash
cd ~/git-course/kitchen              # ensure clean: git checkout -- . ; rm -f ideas.txt
echo "honey version" >> bread.txt
git stash                            # park the honey change
echo "butter version" >> bread.txt   # the same line now changes differently...
git commit -qa -m "Add butter to bread"
git stash pop                        # ...so reapplying the honey change collides
echo "exit code: $?"
git stash list                       # still there!
Expected result — click to reveal (the pop conflicts on purpose)
plain text
Saved working directory and index state WIP on main: ...
Auto-merging bread.txt
CONFLICT (content): Merge conflict in bread.txt
...
        both modified:   bread.txt
...
The stash entry is kept in case you need it again.
exit code: 1
stash@{0}: WIP on main: ...

What to read out of it: Auto-merging then CONFLICT — pop is a merge (Module 6, in a new costume), and it collided because the honey and butter edits touched the same line. Crucially: The stash entry is kept in case you need it again, and git stash list confirms stash@{0} survived — a conflicting pop refuses to throw your work away. Resolve the file normally (edit → git add), then git stash drop to remove the now-applied entry by hand. For this exercise, just bail out with a hard reset (the file is unmerged, so a plain git checkout -- bread.txt is refused with error: path 'bread.txt' is unmerged — you need to clear the merge state): git reset --hard HEAD && git stash drop.

A3. The flags that matter: -u, -m, and inspecting

Official docs: git-stash manual

Four additions make stash production-grade. git stash push -u includes untracked files (A1's omission — the flag you will forget once and never again). git stash push -m "message" gives the entry a real label instead of the auto WIP on…, so a stack of five is legible. git stash show -p stash@{N} prints the entry's diff — look before you pop. And git stash apply (vs pop) is the safe default when you are unsure the reapply will go cleanly: it leaves the stash in place until you confirm success, then git stash drop. (git stash push [paths] even stashes only specific files; git stash clear nukes the whole stack — irreversibly, so treat it like reset --hard.)

🧪 Exercise 11.4 — a labeled stash with untracked files, applied then inspected
bash
cd ~/git-course/kitchen              # clean tree
echo "experimental change" >> bread.txt
echo "new idea" > ideas.txt          # untracked
git stash push -u -m "WIP: honey experiment + ideas"
git status -s                        # truly clean now, ideas.txt included
git stash show -p stash@{0} | head -4
git stash apply                      # apply but KEEP
git stash list                       # still listed
git stash drop                       # now remove by hand
Expected result — click to reveal
plain text
Saved working directory and index state On main: WIP: honey experiment + ideas
diff --git a/bread.txt b/bread.txt
index ...
--- a/bread.txt
+++ b/bread.txt
@@ ...
stash@{0}: On main: WIP: honey experiment + ideas
Dropped refs/stash@{0} (...)

What to read out of it: with -u, git status -s after stashing is completely empty — ideas.txt was parked too, unlike Exercise 11.1. The label reads On main: WIP: honey experiment + ideas (your -m text, no auto WIP on), which is what makes a deep stash stack survivable. stash show -p let you review the parked diff before touching your tree — the look-before-you-pop habit. And apply left the entry on the stack (git stash list still showed it) until you explicitly dropped it: the deliberate, reversible path. Clean up: git checkout -- bread.txt && rm -f ideas.txt.

Trap: the stash stack is out of sight, out of mind — and untracked-by-default means half your "saved" work may never have been stashed at all. Two failure modes bite teams: forgotten stashes (git stash list months later showing stash@{7}: WIP on a branch deleted in Q1 — undead work nobody can place), and git stash clear run to "tidy up," silently deleting real work with no reflog-style recovery for stashes older than the gc window. Rules: prefer a real WIP commit on a branch (Module 7's Ticket, reflog-protected, pushable) for anything you might keep more than an hour; reserve stash for genuinely short, same-session parking; and never clear without list-ing first.

🎯 Interview questions — Part A

🎯 "Tell me something about git stash?" — asked verbatim in InterviewBit's 30+ Git Interview Questions, 2025; also "What is git stash?" in Interview Coder, Sep 2025

git stash saves your uncommitted work — modified tracked files and the staged index — onto a stack and restores a clean working tree, so you can switch context (branches, an urgent fix) without committing half-done work. Retrieve with git stash pop (apply and remove) or git stash apply (apply and keep); manage with git stash list, git stash show -p, git stash drop, git stash clear. Untracked files are excluded unless you pass -u; -m labels the entry. Because reapplying is a three-way merge, a stash can conflict on the way back — and a conflicting pop keeps the entry rather than losing it.

The details that separate candidates: an average answer says "temporarily saves changes." A strong answer names the pop-vs-apply distinction, the -u gotcha (untracked excluded by default — the single most common stash surprise), and the reapply-is-a-merge fact that explains conflicts. The maturity signal: stash is for short same-session parking; anything you might keep belongs in a WIP commit on a branch — reflog-protected, pushable, and not lurking invisibly in a stack across branch deletions.

🎯 "What is the difference between git stash apply vs git stash pop command?" — asked verbatim in InterviewBit's 30+ Git Interview Questions, 2025

Both reapply the stashed changes to your working tree; they differ in what happens to the stash entry afterward. git stash pop removes the entry from the stack after applying it — pop = apply + drop. git stash apply leaves the entry on the stack, so you can reapply it elsewhere or keep it as a safety copy; you remove it later with git stash drop. Use apply when you are unsure the reapply will succeed cleanly (it can conflict) or want to apply the same stash to multiple branches; use pop for the normal park-and-resume where you want the entry gone once restored.

The details that separate candidates: an average answer states "pop removes, apply keeps." A strong answer gives the identity pop = apply + drop, names the concrete reason to prefer apply (a conflicting pop keeps the entry too nowadays, but apply never risks it — and lets you inspect the result before committing to dropping), and the multi-target use case (apply one stash to several branches). Knowing that pop on conflict does not drop the entry — a change many still get wrong — marks current, hands-on experience.

Part B — A stash is secretly commits

B1. Opening the box

Module 3's tools demystify stash the way they demystified everything else. A stash entry is not a special format — it is a commit (actually a small cluster of them: one holding your working-tree changes, one holding the index, tied to the HEAD you stashed from as parents). stash@{0} is a ref pointing at that commit, living in .git/refs/stash plus a reflog. This is why the reflog @{N} syntax works on it, why a stash survives branch switches (commits are global, Module 5), and why a conflicting pop can keep it (dropping is just deleting a ref — Module 5's branch-delete, again). Nothing new under the hood; Git reuses its four objects for everything.

🧪 Exercise 11.5 — prove a stash is a commit
bash
cd ~/git-course/kitchen              # clean tree
echo "peek change" >> bread.txt
git stash push -m "peek demo"
git cat-file -t stash@{0}            # what TYPE of object is a stash?
git cat-file -p stash@{0} | head -3  # read it like any commit
git stash drop
Expected result — click to reveal
plain text
Saved working directory and index state On main: peek demo
commit
tree ec8eb0f3630b49f12d137f6d08f104767129a1ff
parent 6274fb87acad7ca1e7bfd9fae580b4caaebf445d
parent 6e69ff9db2448c4a9326a2c351ee8e019bed06b1

What to read out of it: git cat-file -t stash@{0} prints commit — a stash is a commit, no exotic storage. Reading it (Module 3's -p) shows a tree (your stashed working state) and two parents: the first is the HEAD you stashed from, the second is a commit capturing your staged index at stash time (with -u, a third parent holds untracked files). It is structured like a tiny merge commit. This is the payoff of Module 3 compounding: once you know the object model, no Git feature is a black box — stash, tags (Module 12), even the reflog are all refs pointing at the same four object types.

🎯 Interview questions — Part B

🎯 "What does git stash apply command do?" — asked verbatim in InterviewBit's 30+ Git Interview Questions, 2025

git stash apply restores a stashed entry's changes back into the working tree (and, with --index, re-stages what was staged) without removing the entry from the stash stack. It reapplies the diff between the stash's base and its recorded working state onto your current tree as a three-way merge — so it can conflict, and the entry stays put regardless of outcome, which is exactly why it is the safer choice when you are unsure. By default it targets stash@{0}; name another entry to apply a specific one.

The details that separate candidates: an average answer says "brings stashed work back." A strong answer adds that it keeps the entry (the whole distinction from pop), that reapplying is a merge (hence conflicts and the value of applying to a scratch state first), and — the internals flourish — that a stash is a commit cluster, so apply is really re-merging a saved snapshot, and --index restores the staged/unstaged split rather than dumping everything as unstaged. That last option answers the common complaint "stash pop lost my staging."

Part C — git worktree: no parking needed

C1. Two branches checked out at once

Official docs: git-worktree manual

Stash solves the interruption by clearing your tree. Worktree solves it by giving you a second tree. git worktree add <path> <branch> creates another working directory, linked to the same repository, with a different branch checked out. Now ~/project has your feature and ~/project-hotfix has the fix — both real, both editable, side by side, sharing one object database (so no re-clone, no duplicated history, no wasted disk). You fix the emergency in the second directory while your feature sits exactly as you left it, uncommitted work and all. Module 5's counter-intuitive "one working tree per repo" was the default, not a law — worktree is the opt-in that lifts it.

🧪 Exercise 11.6 — add a worktree, work in it, watch the shared history
bash
cd ~/git-course/kitchen              # leave your (imaginary) messy work untouched
git worktree add ../kitchen-hotfix sourdough   # second dir, sourdough branch
git worktree list
cd ../kitchen-hotfix                  # a real, separate working directory
echo "sourdough note" > sd.txt && git add sd.txt && git commit -m "Work in sourdough worktree"
git -C ../kitchen log --oneline sourdough -1   # the commit is visible from the main tree
Expected result — click to reveal
plain text
Preparing worktree (checking out 'sourdough')
HEAD is now at 00235f5 Add baking
/home/aisha/git-course/kitchen         6274fb8 [main]
/home/aisha/git-course/kitchen-hotfix  00235f5 [sourdough]
[sourdough f2c5990] Work in sourdough worktree
 1 file changed, 1 insertion(+)
 create mode 100644 sd.txt
f2c5990 Work in sourdough worktree

What to read out of it: worktree list shows two directories, each with its branch — kitchen on main, kitchen-hotfix on sourdough. You committed in the second directory, and from the first directory git log sourdough already shows that commit: one shared object database, two windows onto it (Module 3's .git is shared — the second worktree keeps only a tiny pointer file back to it). Your main working tree never moved and never needed stashing. This is the hotfix workflow without the parking step.

C2. The rules and the cleanup

Official docs: git-worktree manual

Two rules and one cleanup. A branch can be checked out in only one worktree at a time — Git refuses a second checkout of the same branch, because two trees editing one branch would fight over its pointer (this is a feature, catching the "wait, which window am I in?" mistake before it happens). And worktrees are directories you must remove properly: git worktree remove <path> deletes the directory and its bookkeeping. Delete the folder by hand and Git is left with a dangling reference until git worktree prune cleans it (it shows as prunable in list meanwhile). Otherwise, everything you know works unchanged: each worktree has its own HEAD, index, and status; commits, branches, and objects are shared.

🧪 Exercise 11.7 — the guardrail, then a clean teardown
bash
cd ~/git-course/kitchen
git worktree add ../kitchen-dup sourdough   # try to check out sourdough AGAIN
echo "exit code: $?"
git worktree remove ../kitchen-hotfix        # proper cleanup of Exercise 11.6's tree
git worktree list
Expected result — click to reveal (the add fails on purpose)
plain text
Preparing worktree (checking out 'sourdough')
fatal: 'sourdough' is already used by worktree at '/home/aisha/git-course/kitchen-hotfix'
exit code: 128
/home/aisha/git-course/kitchen  6274fb8 [main]

What to read out of it: the second checkout of sourdough is refused — the error names the other worktree already using it, so the guardrail is also a locator ("oh, it's open in kitchen-hotfix"). After git worktree remove, worktree list shows only the main tree again: clean teardown, no dangling reference. Had you rm -rf'd the directory instead, list would mark it prunable and git worktree prune would be needed — so prefer worktree remove. (If Exercise 11.6's git commit left sd.txt on sourdough, that is fine — it is real committed work on that branch.)

Now imagine this at 500 hosts. Worktrees are a CI and monorepo workhorse. Build agents keep several worktrees off one bare clone to build multiple branches or releases in parallel without re-cloning a huge repo each time — pairing naturally with the shallow/partial clones of Module 8. In giant monorepos, engineers keep a permanent second worktree for "quick reviews and hotfixes" so their main working tree — with its expensive, warm build cache and IDE index — never gets disturbed by a context switch. The disk and time saved (no repeated multi-gigabyte clones) is exactly why worktree exists; at fleet scale it is infrastructure, not a convenience.

🎯 Interview questions — Part C

🎯 Corpus note — git worktree interview questions

Across the interview-question corpus surveyed for this track (InterviewBit, Interview Coder, GeeksforGeeks, InterviewDrill), git worktree appears only inside broader answers — most often as "the elegant alternative to stashing for a hotfix" and as a monorepo/CI technique — and essentially never as a verbatim standalone question. Rather than invent one and label it published, this Part carries no fabricated interview block. If asked "how do you work on two branches at once without stashing or re-cloning?", the worktree answer above is the complete response: second working directory, shared object database, one-branch-per-worktree rule, worktree add/list/remove/prune. Being the candidate who reaches for worktree where others only know stash is itself the differentiator this topic rewards.

Part D — Cleaning untracked files

D1. git clean

Stash and reset handle tracked changes; neither removes untracked files (Git will not delete files it never tracked). Build artifacts, generated files, and experiment scratch accumulate as ?? clutter that git status keeps nagging about. git clean deletes them — and because it destroys files Git has no record of (unrecoverable, like Module 7's never-staged edits), it is deliberately cautious: it refuses to run without -f (force), and -n (dry-run) shows what would go without touching anything. Add -d to include untracked directories. The muscle memory to build: git clean -nd always first, read the list, then git clean -fd. (.gitignored files are spared unless you add -x — Module 14's territory.)

🧪 Exercise 11.8 — dry-run, read, then delete
bash
cd ~/git-course/kitchen              # clean tracked state
echo junk > junk1.txt
mkdir -p build && echo out > build/artifact.o   # untracked file AND directory
git clean -n                         # dry-run: files only
git clean -nd                        # dry-run: include directories
git clean -fd                        # actually delete
git status -s                        # clean
Expected result — click to reveal
plain text
Would remove junk1.txt
Would remove build/
Would remove junk1.txt
Removing build/
Removing junk1.txt

What to read out of it: plain git clean -n listed only the loose file; adding -d also listed build/ — untracked directories need -d in both the preview and the real run, a common omission that leaves clutter behind. The -fd run printed Removing … and did the deletion; git status -s is now silent. Everything removed was untracked, so — like restore in Module 7 — it is gone with no recovery. That is precisely why -n exists and why the dry-run-first habit is not optional: git clean -fdx in the wrong directory has ended more than one engineer's afternoon.

🎯 Interview questions — Part D

🎯 Corpus note — git clean interview questions

git clean follows the same pattern as git worktree in the surveyed corpus: it appears within answers about undoing changes and cleaning a working tree (usually paired with stash under the Pro Git book's "Stashing and Cleaning" heading) but rarely as a verbatim standalone question. So, no fabricated interview block here. The one thing to be able to say cold: git clean deletes untracked files, is guarded by -f/-n, needs -d for directories and -x to also remove ignored files, and its deletions are unrecoverable — hence dry-run first, every time. It is the natural completion of the undo toolbox: restore for tracked working-tree edits (Module 7), reset for history, stash for parking, clean for the untracked leftovers none of the others touch.

Part E — Production practice

E1. Symptom → cause → diagnosis → fix

Click the symptom you're seeing.

⚠️ Stashed, switched, came back — but a new file I made is still here / missing from the stash

What is really happening: Default stash excludes untracked files.

Diagnose: git stash show -p (only shows what was actually stashed)

The fix: Use git stash push -u to include untracked files next time.

⚠️ git stash pop reported a CONFLICT

What is really happening: Reapplying is a three-way merge; the target diverged from the stash's base.

Diagnose: git status (both modified) — the stash is kept, not lost

The fix: Resolve → git addgit stash drop; or git checkout -- <file> and stash drop to bail.

⚠️ git stash list shows ancient entries against branches that no longer exist

What is really happening: Stashes are global and invisible; nobody cleaned up.

Diagnose: git stash show -p stash@{N} to identify each

The fix: Drop what's dead; going forward, use WIP commits on branches for anything kept > an hour.

⚠️ fatal: '<branch>' is already used by worktree at '<path>'

What is really happening: The one-branch-per-worktree rule — it's open elsewhere.

Diagnose: git worktree list — find which directory holds it

The fix: Work in that existing directory, or check out a different branch in the new one.

⚠️ Deleted a worktree directory with rm -rf; Git still lists it

What is really happening: The bookkeeping reference wasn't removed with the folder.

Diagnose: git worktree list (shows it as prunable)

The fix: git worktree prune; next time use git worktree remove <path>.

⚠️ git clean "didn't remove my build folder"

What is really happening: Untracked directories need -d; plain clean skips them.

Diagnose: git clean -nd (dry-run with directories)

The fix: git clean -fd; add -x only if you also mean to wipe ignored files.

⚠️ git clean -fdx deleted config/build caches I needed

What is really happening: -x removes ignored files too — often local secrets, .env, caches.

Diagnose: Nothing — untracked/ignored deletions are unrecoverable

The fix: Restore from source/backup; never run -x without a careful -ndx dry-run.

E2. Capstone — four tickets

Ticket 1 — "Solve the mid-feature hotfix two ways, and say which you'd pick." You're deep in feature/checkout-flow with six modified files and two untracked ones. Production breaks. Show both the stash path and the worktree path, and recommend one.

Worked answer: Stash path: git stash push -u -m "WIP checkout flow" (the -u is essential — two of your files are untracked and would otherwise be left behind or, worse, follow you onto the hotfix branch per Module 5), git switch main, git switch -c hotfix/timeout, fix, commit, push; return with git switch feature/checkout-flow && git stash pop and resolve any conflict. Worktree path: git worktree add ../proj-hotfix -b hotfix/timeout main (create the hotfix branch in a fresh directory off main), fix and commit there while your feature tree sits untouched — no stash, no risk of the reapply conflicting; git worktree remove ../proj-hotfix when done. Recommendation: worktree, if the fix is non-trivial or your working tree carries expensive state (warm build cache, IDE index, long-running processes) — nothing is disturbed. Stash, for a genuinely 30-second fix where spinning up a directory is overkill. The senior signal is knowing both exist and choosing by the cost of disturbing your current tree — most engineers only reach for stash.

Ticket 2 — "Our repo has 40 abandoned stashes across the team." A survey finds engineers using git stash as long-term storage; stacks are full of unlabeled WIP on <deleted-branch> entries nobody can identify. Fix the practice.

Worked answer: the root cause is stash misuse as durable storage — it is invisible (list-only), local (never pushed or backed up), unlabeled by default, and orphaned when its branch dies. Policy: stash is short-term, same-session parking only; anything kept beyond that becomes a WIP commit on a real branch — visible in git log and git branch, pushable (backed up off-laptop, Module 1's trap), reflog-protected, and shareable. Practical rollout: teach git stash push -m so unavoidable stashes are at least legible; add a pre-push or periodic reminder surfacing git stash list count; and for the existing 40, each owner runs git stash show -p stash@{N} to triage — promote anything valuable to a branch (git stash branch <name> stash@{N} creates a branch from a stash, the cleanest rescue), drop the rest. The framing for the retro: stash is a scratchpad, not a filing cabinet.

Ticket 3 — "CI clones the 8GB monorepo fresh for every branch build — it's killing us." Build times are dominated by repeated full clones. Redesign using worktrees.

Worked answer: clone once, worktree many. Maintain one bare (or reference) clone per agent; for each build, git worktree add --detach <workdir> <commit> checks out the exact commit into a scratch directory sharing the single object database — no re-download of history, just a checkout of the needed tree; tear down with git worktree remove after. Combine with Module 8's --filter=blob:none (partial clone) or shallow fetch so even the base clone stays lean. Guardrails: the one-branch-per-worktree rule means concurrent builds must use --detach (or distinct branches) rather than all checking out main; and prune aggressively (git worktree prune) since ephemeral CI directories vanish without worktree remove. The payoff quantifies itself: history is transferred once per agent instead of once per build — exactly the fleet-scale motivation from Part C.

Ticket 4 — "Write the 'clean working tree' runbook." New hires keep either committing junk files or nuking real work with git clean -fdx. Produce the safe procedure.

Worked answer (the runbook): To see what's dirty: git status -s — tracked changes vs ?? untracked. To undo tracked edits: git restore <file> (working tree) / git restore --staged <file> (unstage) — Module 7. To park tracked work briefly: git stash push -u -m "…" — Module 11, short-term only. To remove untracked clutter: ALWAYS git clean -nd first, read the list out loud, then git clean -fd — and only add -x (removes ignored files: .env, caches, secrets) after an equally careful git clean -ndx, because those deletions are unrecoverable. Never: git clean -fdx reflexively, git stash clear without listing, or committing build output (fix the real problem — .gitignore, Module 14). Pin the one-liner at the top: untracked deletions have no undo — dry-run first, every time. This ties the whole undo toolbox together: restore/reset/stash for tracked state, clean for the untracked remainder, dry-runs and WIP-commits as the safety net throughout.

E3. Documentation reference

TopicOfficial sourceWhat it covers
git stashgit-stash manualpush/pop/apply/list/show/drop/clear/branch, -u, -m, --index
Stashing & cleaning (tutorial)Git Book §7.3 — Stashing and CleaningStash internals, stash branch, git clean walkthrough
git worktreegit-worktree manualadd/list/remove/prune/lock, --detach, -b
git cleangit-clean manual-n/-f/-d/-x/-i, interactive mode

E4. Self-assessment

Try each question aloud, from memory, before opening its answer — the gap between your answer and the hidden one is what to study.

1. What exactly does git stash save, and what does it pointedly not save by default?

It saves your uncommitted changes — modified tracked files and the staged index — onto a stack and resets your working tree to a clean HEAD. By default it pointedly ignores untracked files (Git will not touch files it does not track), so a brand-new file is left sitting in your "clean" tree. The -u flag includes them.

2. State the identity relating pop, apply, and drop.

git stash pop = git stash apply + git stash drop. Pop reapplies the most recent stash and removes it from the stack in one step; apply reapplies but leaves the entry in place until you remove it by hand with drop.

3. Why can git stash pop conflict, and what happens to the stash entry when it does?

Reapplying a stash is a three-way merge onto whatever the tree looks like now, so if the target's content diverged from where you stashed, the pop conflicts — same markers, same resolution as Module 6. The mercy: a conflicting pop keeps the stash entry rather than dropping it ("The stash entry is kept in case you need it again"), so a botched reapply loses nothing. Resolve the file normally (edit → git add), then git stash drop by hand.

4. Which flag includes untracked files, and why is forgetting it the classic stash bug?

git stash push -u. Default stash excludes untracked files, so a brand-new file is left behind in your supposedly clean tree — half your "saved" work may never have been stashed at all. It is the flag you will forget once and never again.

5. What kind of Git object is a stash entry? How many parents, and what does each hold?

A stash entry is a commitgit cat-file -t stash@{0} prints commit, no exotic storage. It is structured like a tiny merge commit: its tree holds your stashed working state, the first parent is the HEAD you stashed from, and the second parent captures your staged index at stash time. With -u, a third parent holds the untracked files.

6. When should work go into a stash versus a WIP commit on a branch? Give two reasons commits win for anything kept.

Reserve stash for genuinely short, same-session parking; anything you might keep more than an hour belongs in a WIP commit on a real branch. Commits win because they are reflog-protected and pushable (backed up off your laptop), and because they are visible in git log and git branch — not lurking invisibly in a stack that outlives deleted branches.

7. What does git worktree add create, and what does it share with the original repository?

It creates a second working directory, linked to the same repository, with a different branch checked out — both trees real and editable, side by side. What is shared is the single object database (commits, branches, history), so there is no re-clone, no duplicated history, no wasted disk; the second worktree keeps only a tiny pointer file back to the shared .git. Each worktree still has its own HEAD, index, and status.

8. Why does Git refuse to check out one branch in two worktrees at once?

Because two trees editing one branch would fight over its pointer. The refusal is a feature: it catches the "wait, which window am I in?" mistake before it happens, and the error message even names the other worktree already using the branch, so the guardrail doubles as a locator.

9. worktree remove vs rm -rf the directory — what's the difference, and what fixes the latter?

git worktree remove <path> deletes the directory and its bookkeeping — a clean teardown. Deleting the folder by hand with rm -rf leaves Git with a dangling reference, shown as prunable in git worktree list. git worktree prune cleans that up — but prefer worktree remove in the first place.

10. What does git clean delete that stash and reset never touch, and why is it guarded by -f?

It deletes untracked files — build artifacts, generated files, experiment scratch — which stash and reset never remove because Git will not delete files it never tracked. Since it destroys files Git has no record of, the deletions are unrecoverable, so it is deliberately cautious: it refuses to run without -f (force), and -n dry-runs first.

11. Recite the safe git clean procedure and what -d and -x each add.

Always git clean -nd first, read the list, then git clean -fd. -d includes untracked directories, which plain clean skips in both the preview and the real run. -x also removes .gitignored files — often local secrets, .env, and caches — so never run it without an equally careful -ndx dry-run.

12. Name the four tools of the undo/parking toolbox and the exact state each one handles.

restore for tracked working-tree edits, reset for history, stash for parking uncommitted work, and clean for the untracked leftovers none of the others touch.

E5. Sources

Interview questions in this module were captured verbatim from: InterviewBit — 30+ Commonly Asked GIT Interview Questions (2025) and Interview Coder — 90+ Common Git Interview Questions (Sep 20, 2025). A corpus note: the published corpus covers git stash well but treats git worktree and git clean only inside broader answers, essentially never as standalone questions — so Parts C and D carry honest corpus notes instead of fabricated interview blocks (the track's rule: never invent a question and present it as published). Technical claims were verified against the official Git documentation in E3; every command and output on this page was executed on Git 2.43.0 on Linux. Commit hashes, stash object IDs, and paths will differ on your machine.

🗒️ Cheat sheet — Module 11

CommandWhat it does
git stash · git stash push -u -m "msg"Park tracked changes, clean the tree · include untracked, with a label
git stash list · git stash show -p stash@{N}The stack (newest @{0}) · inspect an entry's diff before applying
git stash pop · git stash apply · git stash dropApply + remove · apply + keep · remove an entry (pop = apply + drop)
git stash branch <name> stash@{N} · git stash clearRescue a stash into a new branch · wipe the whole stack (irreversible)
git worktree add <path> <branch> · add <path> -b <new> · --detachCheck out a branch in a second directory · create+checkout · detach at a commit (CI)
git worktree list · remove <path> · pruneShow all trees · clean teardown · clear refs after a manual delete
git clean -ndgit clean -fdDry-run untracked incl. dirs → force-delete them (always dry-run first)
git clean -ndxgit clean -fdxSame, also including .gitignored files (dangerous — secrets/caches)

Key concepts: stash parks tracked changes + index and cleans the tree; untracked excluded unless -u · pop = apply + drop; a conflicting pop keeps the entry · a stash is a commit cluster (tree + parents for HEAD, index, and optionally untracked) — hence global, @{N}-addressable, drop-is-just-ref-delete · stash is short-term parking; kept work belongs in a WIP commit (visible, pushable, reflog-safe) · worktree gives a second working directory on a shared object database — the hotfix without parking; one branch per worktree; remove don't rm -rf (else prune) · at scale worktrees replace repeated giant clones · clean deletes untracked files (-d dirs, -x ignored), unrecoverable — dry-run -n first, always · the undo toolbox: restore (tracked working tree), reset (history), stash (parking), clean (untracked).

Next: Module 12 — Tags and Releases — you've referenced tags since Module 5's "tag your releases" advice. Module 12 delivers them: lightweight vs annotated tags, semantic versioning, git describe, pushing tags, and the signed tags that make a release cryptographically provable.
Spotted a mistake or want something added? Send me a note.