Chapter 12Lesson 02~135 minutes

Stash, Worktrees, Temporary Work, and Parallel Development Contexts: Guided Hands-On Workflow and Core Operations

Practice stash push/list/show/apply/pop/drop/branch and worktree add/list/lock/move/remove/prune in a disposable repository, including conflict recovery and parallel feature/review/hotfix contexts.

Stash operationsConflict recoverygit worktreeParallel lab

Learning objectives

  • Create selected-path and staged-only stash entries and inspect exactly what they contain.
  • Apply, pop, drop, and recover via stash branch while preserving evidence through a conflict.
  • Create feature, detached-review, and hotfix worktrees attached to one repository.
  • Observe branch checkout exclusivity and use worktree lock, move, remove, and prune safely.
  • Verify branch associations and shared commit visibility before cleanup.

1. Build a disposable context-switching repository

The entire lab lives in a new disposable directory. It uses no remote account and no valuable repository.

Git Bash, Bash, or zsh

mkdir git-context-lab
cd git-context-lab
git init -b trunk main
cd main
git config user.name "Context Lab"
git config user.email "context-lab@example.invalid"

printf "mode=stable\nmetrics=false\n" > service.conf
printf "# Context Service\n" > README.md
printf "build/\n" > .gitignore
git add service.conf README.md .gitignore
git commit -m "Create context-switching baseline"

git status --short --branch
git stash list
git worktree list --porcelain

PowerShell setup alternative

New-Item -ItemType Directory git-context-lab | Out-Null
Set-Location git-context-lab
git init -b trunk main
Set-Location main
git config user.name "Context Lab"
git config user.email "context-lab@example.invalid"

@('mode=stable','metrics=false') | Set-Content service.conf
Set-Content README.md '# Context Service'
Set-Content .gitignore 'build/'
git add service.conf README.md .gitignore
git commit -m "Create context-switching baseline"

git status --short --branch
git stash list
git worktree list --porcelain

2. Stash one selected path and prove another path remains

Modify both tracked files, then stash only service.conf:

# Change metrics=false to metrics=true in service.conf.
# Append "draft docs" to README.md.
git status --short
git diff

git stash push -m "service.conf only | metrics experiment" -- service.conf
git status --short
git stash list
git stash show -p stash@{0}

Expected: the service.conf edit is parked in the stash and restored to HEAD in the current worktree; the README edit remains in the worktree because it was outside the pathspec.

git restore -- README.md
git stash apply stash@{0}
git diff -- service.conf
git stash list
git restore -- service.conf
git stash drop stash@{0}
git stash list

apply retained the stash. After proving the saved change, you restored the disposable working file and explicitly dropped the entry.

3. Stash staged state without hiding an unrelated unstaged edit

# Change metrics=false to metrics=true in service.conf and stage it.
git add service.conf

# Append "local prose experiment" to README.md but do not stage it.
git status --short
git diff --staged
git diff

git stash push --staged -m "staged metrics change only"
git status --short
git stash show -p stash@{0}

Expected: the staged metrics change moves into the stash, while the unstaged README edit remains visible. This is useful when a staged change belongs to another future task and should not be mixed into the current commit.

git restore -- README.md
git stash pop stash@{0}
git status --short
git diff -- service.conf
git restore -- service.conf

A successful pop removes that stash entry. The restored metrics edit is intentionally discarded at the end because this is a disposable demonstration.

4. Decide explicitly whether untracked and ignored files belong in the stash

printf "investigation notes\n" > incident-notes.txt
mkdir -p build
printf "generated cache\n" > build/cache.txt
git status --short --ignored

git stash push -m "tracked only demonstration"
git status --short --ignored

The default stash does not remove the untracked note or ignored build cache. If those files must travel with the temporary context:

git stash drop stash@{0}
git stash push -u -m "include untracked incident notes"
git status --short --ignored
git stash show -u --stat stash@{0}
git stash pop
rm -f incident-notes.txt
rm -rf build

-u includes untracked files but not ignored files. -a would include ignored content too; use it only after inspecting exactly what ignored files exist.

5. Engineer a stash-pop conflict and keep the recovery evidence

Create an isolated conflict branch:

git switch -c conflict-demo trunk
printf "mode=feature\n" > conflict.conf
git add conflict.conf
git commit -m "Add conflict baseline"
BASE_CONFLICT=$(git rev-parse HEAD)

printf "mode=stashed\n" > conflict.conf
git stash push -m "conflict demo | stashed value"
STASH_OID=$(git rev-parse stash@{0})

printf "mode=current\n" > conflict.conf
git add conflict.conf
git commit -m "Advance conflict file"

git stash pop stash@{0}

Git should stop with a content conflict. Inspect before repairing:

git status
git diff
git stash list
git rev-parse stash@{0}

Critical observation: because pop failed, the stash entry remains. The failed apply did not erase the only saved copy.

6. Abandon the conflicted application narrowly, then recover with stash branch

For this one-file disposable conflict, restore the conflicted path from current HEAD while leaving the stash untouched:

git restore --source=HEAD --staged --worktree -- conflict.conf
git status --short
git stash list

git stash branch recovered-stash stash@{0}
git status --short --branch
cat conflict.conf
git stash list

stash branch creates recovered-stash from the commit where the stash originally began, applies the saved state there, and drops the stash entry after successful application. This avoids forcing old temporary state onto a branch that has since changed incompatibly.

git add conflict.conf
git commit -m "Preserve recovered stash state"
git switch trunk

7. Create feature, review, and hotfix contexts without switching trunk

From the main worktree:

git worktree add -b feature/metrics ../feature-wt trunk
git worktree add --detach ../review-wt trunk
git worktree add -b hotfix/config ../hotfix-wt trunk

git worktree list
git worktree list --porcelain
git branch -vv

The feature and hotfix directories own named branches. The review worktree uses detached HEAD, which is useful for read-only inspection/testing when you do not want a branch ref to move accidentally.

8. Prove branch checkout exclusivity

git worktree add ../duplicate-feature feature/metrics

The command should refuse because feature/metrics is already active in ../feature-wt. Inspect git worktree list --porcelain and use the existing directory rather than forcing a duplicate checkout.

9. Lock a review worktree, then unlock and move it deliberately

git worktree lock --reason "review snapshot in use" ../review-wt
git worktree list --porcelain

git worktree unlock ../review-wt
git worktree move ../review-wt ../review-wt-renamed
git worktree list --porcelain

Lock protects administrative metadata and also prevents ordinary move/remove operations. Moving with the Git command updates the worktree relationship correctly; do not rename a linked worktree directory in the file manager and assume Git knows the new path.

10. Commit independently in the feature and hotfix worktrees

git -C ../feature-wt config user.name "Feature Worker"
git -C ../feature-wt config user.email "feature@example.invalid"
printf "feature metric work\n" > ../feature-wt/feature.txt
git -C ../feature-wt add feature.txt
git -C ../feature-wt commit -m "Prototype metrics feature"

git -C ../hotfix-wt config user.name "Hotfix Worker"
git -C ../hotfix-wt config user.email "hotfix@example.invalid"
printf "safe=true\n" > ../hotfix-wt/hotfix.conf
git -C ../hotfix-wt add hotfix.conf
git -C ../hotfix-wt commit -m "Prepare configuration hotfix"

git log --graph --decorate --oneline --all --max-count=12

Both commits immediately appear in the common object database and graph, even though their working trees/indexes remain independent.

11. Remove worktrees cleanly and verify branch associations

git worktree remove ../feature-wt
git worktree remove ../hotfix-wt
git worktree remove ../review-wt-renamed

git worktree list --porcelain
git branch -vv
git worktree prune --dry-run
git worktree prune -v

Removing the directories with git worktree remove cleans their administrative records. The feature/hotfix branch refs remain unless you delete them separately. With no stale metadata left, prune should have nothing to remove.

12. Challenge — choose stash or worktree from the state model

  1. You have two tracked edits but only one should be parked. Which stash form scopes by path?
  2. An important staged fix belongs to a different future task while unstaged feature edits should remain visible. Which stash mode targets the index selection?
  3. A stash conflicts because the branch moved significantly. Which stash command can recreate a branch at the stash's original base?
  4. You need a read-only review of trunk while feature work remains untouched. What kind of worktree avoids creating a movable branch?
  5. A linked directory is on removable media that may disappear temporarily. Which worktree command protects its metadata from pruning?

13. Cleanup

Verify the path before recursive deletion. All branches and worktrees in this lab are disposable.

Git Bash / Bash / zsh

git stash list
git worktree list
cd ../..
pwd
rm -rf git-context-lab

PowerShell

git stash list
git worktree list
Set-Location ../..
Get-Location
Remove-Item -Recurse -Force git-context-lab

14. Knowledge check

Question 1. Why did stash apply require a later explicit drop?

Question 2. What happens to a stash entry when stash pop conflicts?

Question 3. Why did the duplicate feature worktree creation fail?

Question 4. What did git worktree move preserve that a manual directory rename might not?

Question 5. Does removing a clean worktree delete the branch it had checked out?

15. Summary

You scoped stash entries by path and staged state, inspected and applied them, handled a failed pop without losing the stash, recovered via stash branch, created multiple parallel worktrees, observed branch exclusivity, used lock/move/remove/prune, and proved that worktrees share commits while keeping checkout state separate.

Next

Choose configuration and retention rules for parallel contexts

Lesson 3 adds worktree-specific configuration, naming conventions, stash retention discipline, and the CI tradeoff between shared worktrees and clean clones.

Authoritative references

 git-stash
 git-worktree
 git-switch

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.