feat: add initial worktrees example
This commit is contained in:
208
module-13-worktrees/README.md
Normal file
208
module-13-worktrees/README.md
Normal file
@@ -0,0 +1,208 @@
|
||||
# Module 13: Worktrees
|
||||
|
||||
## Learning Objectives
|
||||
|
||||
By the end of this module, you will:
|
||||
- Understand what Git worktrees are and when to use them
|
||||
- Create and manage multiple working directories for the same repository
|
||||
- Work on multiple branches simultaneously
|
||||
- Understand the benefits of worktrees over stashing or cloning
|
||||
- Remove and clean up worktrees
|
||||
|
||||
## Challenge Description
|
||||
|
||||
You're working on a feature when an urgent bug report comes in. Instead of stashing your work or creating a separate clone, you'll use Git worktrees to work on both the feature and the bugfix simultaneously in different directories.
|
||||
|
||||
Your task is to:
|
||||
1. Create a worktree for the bugfix on a separate branch
|
||||
2. Fix the bug in the worktree
|
||||
3. Commit and verify the fix
|
||||
4. Continue working on your feature in the main working directory
|
||||
5. Clean up the worktree when done
|
||||
|
||||
## Key Concepts
|
||||
|
||||
### What are Git Worktrees?
|
||||
|
||||
A worktree is an additional working directory attached to the same repository. Each worktree can have a different branch checked out, allowing you to work on multiple branches simultaneously without switching.
|
||||
|
||||
### Traditional Workflow vs Worktrees
|
||||
|
||||
**Traditional (switching branches):**
|
||||
```
|
||||
main-repo/
|
||||
- Switch to bugfix branch
|
||||
- Fix bug
|
||||
- Switch back to feature branch
|
||||
- Continue feature work
|
||||
- (Requires stashing or committing incomplete work)
|
||||
```
|
||||
|
||||
**With Worktrees:**
|
||||
```
|
||||
main-repo/ <- feature branch
|
||||
worktrees/bugfix/ <- bugfix branch
|
||||
|
||||
Work in both simultaneously!
|
||||
```
|
||||
|
||||
### Why Use Worktrees?
|
||||
|
||||
**Advantages:**
|
||||
- Work on multiple branches at the same time
|
||||
- No need to stash or commit incomplete work
|
||||
- Each worktree has its own working directory and index
|
||||
- Share the same Git history (one `.git` directory)
|
||||
- Faster than cloning the entire repository
|
||||
- Perfect for code reviews, comparisons, or parallel development
|
||||
|
||||
**Use Cases:**
|
||||
- Urgent bug fixes while working on a feature
|
||||
- Code reviews (checkout PR in separate worktree)
|
||||
- Comparing implementations side by side
|
||||
- Running tests on one branch while coding on another
|
||||
- Building different versions simultaneously
|
||||
|
||||
## Useful Commands
|
||||
|
||||
```bash
|
||||
# List all worktrees
|
||||
git worktree list
|
||||
|
||||
# Add a new worktree
|
||||
git worktree add <path> <branch>
|
||||
git worktree add ../bugfix bugfix-branch
|
||||
|
||||
# Create new branch in worktree
|
||||
git worktree add <path> -b <new-branch>
|
||||
git worktree add ../feature-new -b feature-new
|
||||
|
||||
# Remove a worktree
|
||||
git worktree remove <path>
|
||||
git worktree remove ../bugfix
|
||||
|
||||
# Prune stale worktree information
|
||||
git worktree prune
|
||||
|
||||
# Move a worktree
|
||||
git worktree move <old-path> <new-path>
|
||||
|
||||
# Lock a worktree (prevent deletion)
|
||||
git worktree lock <path>
|
||||
git worktree unlock <path>
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
Run the verification script to check your solution:
|
||||
|
||||
```bash
|
||||
.\verify.ps1
|
||||
```
|
||||
|
||||
The verification will check that:
|
||||
- You created a worktree for the bugfix
|
||||
- The bug was fixed and committed in the worktree
|
||||
- Your feature work continued in the main directory
|
||||
- Both branches have the expected changes
|
||||
|
||||
## Challenge Steps
|
||||
|
||||
1. Navigate to the challenge directory
|
||||
2. You're in main-repo with a feature branch checked out
|
||||
3. View current worktrees: `git worktree list`
|
||||
4. Create a worktree for bugfix: `git worktree add ../bugfix-worktree -b bugfix`
|
||||
5. Navigate to the worktree: `cd ../bugfix-worktree`
|
||||
6. Fix the bug in calculator.js (fix the divide by zero check)
|
||||
7. Commit the fix: `git add . && git commit -m "Fix divide by zero bug"`
|
||||
8. Go back to main repo: `cd ../main-repo`
|
||||
9. Continue working on your feature
|
||||
10. Add a new method to calculator.js
|
||||
11. Commit your feature
|
||||
12. List worktrees: `git worktree list`
|
||||
13. Remove the worktree: `git worktree remove ../bugfix-worktree`
|
||||
14. Run verification
|
||||
|
||||
## Tips
|
||||
|
||||
- Worktree paths are typically siblings of your main repo (use `../worktree-name`)
|
||||
- Each worktree must have a different branch checked out
|
||||
- Can't checkout the same branch in multiple worktrees
|
||||
- The main `.git` directory is shared, so commits in any worktree are visible everywhere
|
||||
- Worktrees are listed in `.git/worktrees/`
|
||||
- Use `git worktree remove` to clean up, or just delete the directory and run `git worktree prune`
|
||||
- Worktrees persist across restarts until explicitly removed
|
||||
|
||||
## Common Worktree Workflows
|
||||
|
||||
### Urgent Bugfix
|
||||
```bash
|
||||
# Currently on feature branch with uncommitted changes
|
||||
git worktree add ../hotfix -b hotfix
|
||||
|
||||
cd ../hotfix
|
||||
# Fix the bug
|
||||
git add .
|
||||
git commit -m "Fix critical bug"
|
||||
git push origin hotfix
|
||||
|
||||
cd ../main-repo
|
||||
# Continue working on feature
|
||||
```
|
||||
|
||||
### Code Review
|
||||
```bash
|
||||
# Review a pull request without switching branches
|
||||
git fetch origin pull/123/head:pr-123
|
||||
git worktree add ../review-pr-123 pr-123
|
||||
|
||||
cd ../review-pr-123
|
||||
# Review code, test it
|
||||
# Run: npm test, npm start, etc.
|
||||
|
||||
cd ../main-repo
|
||||
git worktree remove ../review-pr-123
|
||||
```
|
||||
|
||||
### Parallel Development
|
||||
```bash
|
||||
# Work on two features simultaneously
|
||||
git worktree add ../feature-a -b feature-a
|
||||
git worktree add ../feature-b -b feature-b
|
||||
|
||||
# Terminal 1
|
||||
cd feature-a && code .
|
||||
|
||||
# Terminal 2
|
||||
cd feature-b && code .
|
||||
```
|
||||
|
||||
### Build Comparison
|
||||
```bash
|
||||
# Compare builds between branches
|
||||
git worktree add ../release-build release-v2.0
|
||||
|
||||
cd ../release-build
|
||||
npm run build
|
||||
# Test production build
|
||||
|
||||
# Meanwhile, continue development in main repo
|
||||
```
|
||||
|
||||
## Worktree vs Other Approaches
|
||||
|
||||
### vs Stashing
|
||||
- **Stash**: Temporary, one at a time, requires branch switching
|
||||
- **Worktree**: Persistent, multiple simultaneously, no switching
|
||||
|
||||
### vs Cloning
|
||||
- **Clone**: Full copy, separate `.git`, uses more disk space
|
||||
- **Worktree**: Shared `.git`, less disk space, instant sync
|
||||
|
||||
### vs Branch Switching
|
||||
- **Switching**: Requires clean working directory, one branch at a time
|
||||
- **Worktree**: Keep dirty working directory, multiple branches active
|
||||
|
||||
## What You'll Learn
|
||||
|
||||
Git worktrees are a powerful but underutilized feature that can significantly improve your workflow. They eliminate the need for constant branch switching, stashing, or maintaining multiple clones. Whether you're handling urgent fixes, reviewing code, or comparing implementations, worktrees provide a clean and efficient solution. Once you understand worktrees, you'll find many situations where they're the perfect tool for the job.
|
||||
22
module-13-worktrees/reset.ps1
Normal file
22
module-13-worktrees/reset.ps1
Normal file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Resets the worktrees challenge environment.
|
||||
|
||||
.DESCRIPTION
|
||||
Removes the existing challenge directory and runs setup.ps1
|
||||
to create a fresh challenge environment.
|
||||
#>
|
||||
|
||||
Write-Host "Resetting challenge environment..." -ForegroundColor Yellow
|
||||
|
||||
# Remove existing challenge directory if present
|
||||
if (Test-Path "challenge") {
|
||||
Remove-Item -Path "challenge" -Recurse -Force
|
||||
Write-Host "Removed existing challenge directory." -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
# Run setup script
|
||||
Write-Host "Running setup script...`n" -ForegroundColor Cyan
|
||||
& ".\setup.ps1"
|
||||
138
module-13-worktrees/setup.ps1
Normal file
138
module-13-worktrees/setup.ps1
Normal file
@@ -0,0 +1,138 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Sets up the worktrees challenge environment.
|
||||
|
||||
.DESCRIPTION
|
||||
Creates a Git repository with a feature in progress, ready for
|
||||
demonstrating the use of worktrees for parallel work.
|
||||
#>
|
||||
|
||||
# Remove existing challenge directory if present
|
||||
if (Test-Path "challenge") {
|
||||
Write-Host "Removing existing challenge directory..." -ForegroundColor Yellow
|
||||
Remove-Item -Path "challenge" -Recurse -Force
|
||||
}
|
||||
|
||||
# Create challenge directory
|
||||
Write-Host "Creating challenge environment..." -ForegroundColor Cyan
|
||||
New-Item -ItemType Directory -Path "challenge" | Out-Null
|
||||
Set-Location "challenge"
|
||||
|
||||
# Create main repository
|
||||
New-Item -ItemType Directory -Path "main-repo" | Out-Null
|
||||
Set-Location "main-repo"
|
||||
|
||||
# Initialize git repository
|
||||
git init | Out-Null
|
||||
git config user.name "Workshop User" | Out-Null
|
||||
git config user.email "user@workshop.local" | Out-Null
|
||||
|
||||
# Create initial calculator with a bug
|
||||
$calculator = @"
|
||||
class Calculator {
|
||||
add(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
subtract(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
multiply(a, b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
// BUG: No division by zero check!
|
||||
divide(a, b) {
|
||||
return a / b;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Calculator;
|
||||
"@
|
||||
|
||||
Set-Content -Path "calculator.js" -Value $calculator
|
||||
git add calculator.js
|
||||
git commit -m "Initial calculator implementation" | Out-Null
|
||||
|
||||
$readme = @"
|
||||
# Calculator Project
|
||||
|
||||
A simple calculator with basic operations.
|
||||
|
||||
## Features
|
||||
- Addition
|
||||
- Subtraction
|
||||
- Multiplication
|
||||
- Division (has a bug!)
|
||||
"@
|
||||
|
||||
Set-Content -Path "README.md" -Value $readme
|
||||
git add README.md
|
||||
git commit -m "Add README" | Out-Null
|
||||
|
||||
# Create feature branch and start working on it
|
||||
git checkout -b feature-advanced-math | Out-Null
|
||||
|
||||
# Add work in progress on feature branch
|
||||
$calculatorWithFeature = @"
|
||||
class Calculator {
|
||||
add(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
subtract(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
multiply(a, b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
// BUG: No division by zero check!
|
||||
divide(a, b) {
|
||||
return a / b;
|
||||
}
|
||||
|
||||
// New feature: power function (work in progress)
|
||||
power(a, b) {
|
||||
return Math.pow(a, b);
|
||||
}
|
||||
|
||||
// TODO: Add square root function
|
||||
// TODO: Add logarithm function
|
||||
}
|
||||
|
||||
module.exports = Calculator;
|
||||
"@
|
||||
|
||||
Set-Content -Path "calculator.js" -Value $calculatorWithFeature
|
||||
git add calculator.js
|
||||
git commit -m "Add power function (WIP: more math functions coming)" | Out-Null
|
||||
|
||||
# Return to challenge directory
|
||||
Set-Location ..
|
||||
|
||||
Write-Host "`n========================================" -ForegroundColor Green
|
||||
Write-Host "Challenge environment created!" -ForegroundColor Green
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
Write-Host "`nSituation:" -ForegroundColor Cyan
|
||||
Write-Host "You're working on the 'feature-advanced-math' branch" -ForegroundColor White
|
||||
Write-Host "You have plans to add more math functions (see TODOs)" -ForegroundColor White
|
||||
Write-Host "`nUrgent: A critical bug was discovered in the divide function!" -ForegroundColor Red
|
||||
Write-Host "It doesn't check for division by zero." -ForegroundColor Red
|
||||
Write-Host "`nInstead of stashing your feature work, use a worktree:" -ForegroundColor Yellow
|
||||
Write-Host "`nYour task:" -ForegroundColor Yellow
|
||||
Write-Host "1. Navigate to main-repo: cd challenge/main-repo" -ForegroundColor White
|
||||
Write-Host "2. Create a worktree: git worktree add ../bugfix-worktree -b bugfix" -ForegroundColor White
|
||||
Write-Host "3. Go to worktree: cd ../bugfix-worktree" -ForegroundColor White
|
||||
Write-Host "4. Fix the bug in calculator.js:" -ForegroundColor White
|
||||
Write-Host " Add a check: if (b === 0) throw new Error('Division by zero');" -ForegroundColor White
|
||||
Write-Host "5. Commit the fix: git add . && git commit -m 'Fix divide by zero bug'" -ForegroundColor White
|
||||
Write-Host "6. Return to main-repo: cd ../main-repo" -ForegroundColor White
|
||||
Write-Host "7. Complete your feature: Add square root method to calculator.js" -ForegroundColor White
|
||||
Write-Host "8. Commit: git add . && git commit -m 'Add square root function'" -ForegroundColor White
|
||||
Write-Host "9. Clean up worktree: git worktree remove ../bugfix-worktree" -ForegroundColor White
|
||||
Write-Host "`nRun '../verify.ps1' from the challenge directory to check your solution.`n" -ForegroundColor Cyan
|
||||
165
module-13-worktrees/verify.ps1
Normal file
165
module-13-worktrees/verify.ps1
Normal file
@@ -0,0 +1,165 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Verifies the worktrees challenge solution.
|
||||
|
||||
.DESCRIPTION
|
||||
Checks that the user successfully used worktrees to fix a bug
|
||||
while continuing work on a feature.
|
||||
#>
|
||||
|
||||
Set-Location "challenge" -ErrorAction SilentlyContinue
|
||||
|
||||
# Check if challenge directory exists
|
||||
if (-not (Test-Path "../verify.ps1")) {
|
||||
Write-Host "Error: Please run this script from the module directory" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not (Test-Path ".")) {
|
||||
Write-Host "Error: Challenge directory not found. Run setup.ps1 first." -ForegroundColor Red
|
||||
Set-Location ..
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "Verifying your solution..." -ForegroundColor Cyan
|
||||
|
||||
# Check if main-repo exists
|
||||
if (-not (Test-Path "main-repo")) {
|
||||
Write-Host "[FAIL] main-repo directory not found." -ForegroundColor Red
|
||||
Set-Location ..
|
||||
exit 1
|
||||
}
|
||||
|
||||
Set-Location "main-repo"
|
||||
|
||||
# Check if it's a git repository
|
||||
if (-not (Test-Path ".git")) {
|
||||
Write-Host "[FAIL] main-repo is not a git repository." -ForegroundColor Red
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check if bugfix branch exists
|
||||
$branches = git branch --all 2>$null
|
||||
if ($branches -notmatch "bugfix") {
|
||||
Write-Host "[FAIL] bugfix branch not found." -ForegroundColor Red
|
||||
Write-Host "Hint: Create a worktree with: git worktree add ../bugfix-worktree -b bugfix" -ForegroundColor Yellow
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "[PASS] Bugfix branch exists!" -ForegroundColor Green
|
||||
|
||||
# Check bugfix branch for the fix
|
||||
git checkout bugfix 2>$null | Out-Null
|
||||
|
||||
if (-not (Test-Path "calculator.js")) {
|
||||
Write-Host "[FAIL] calculator.js not found on bugfix branch." -ForegroundColor Red
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
$bugfixCalc = Get-Content "calculator.js" -Raw
|
||||
|
||||
# Check if division by zero check was added
|
||||
if ($bugfixCalc -notmatch "b === 0|b == 0|division by zero|divide by zero") {
|
||||
Write-Host "[FAIL] Division by zero check not found in bugfix branch." -ForegroundColor Red
|
||||
Write-Host "Hint: Add a check in the divide method to prevent division by zero" -ForegroundColor Yellow
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check for commit on bugfix branch
|
||||
$bugfixCommits = git log --pretty=format:"%s" bugfix 2>$null
|
||||
if ($bugfixCommits -notmatch "bug|fix|division|divide") {
|
||||
Write-Host "[FAIL] No bugfix commit found on bugfix branch." -ForegroundColor Red
|
||||
Write-Host "Hint: Commit your fix with a descriptive message" -ForegroundColor Yellow
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "[PASS] Bug fixed on bugfix branch!" -ForegroundColor Green
|
||||
|
||||
# Check feature branch for continued work
|
||||
git checkout feature-advanced-math 2>$null | Out-Null
|
||||
|
||||
$featureCalc = Get-Content "calculator.js" -Raw
|
||||
|
||||
# Check if square root function was added
|
||||
if ($featureCalc -notmatch "sqrt|squareRoot") {
|
||||
Write-Host "[FAIL] Square root function not found on feature branch." -ForegroundColor Red
|
||||
Write-Host "Hint: Add the square root method to calculator.js on feature-advanced-math branch" -ForegroundColor Yellow
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check that feature work was committed
|
||||
$featureCommits = git log --pretty=format:"%s" feature-advanced-math 2>$null
|
||||
$featureCommitArray = $featureCommits -split "`n"
|
||||
|
||||
# Should have at least 3 commits: initial + README + power + sqrt
|
||||
if ($featureCommitArray.Count -lt 4) {
|
||||
Write-Host "[FAIL] Not enough commits on feature branch." -ForegroundColor Red
|
||||
Write-Host "Expected: initial, README, power, and square root commits" -ForegroundColor Yellow
|
||||
Write-Host "Found $($featureCommitArray.Count) commits" -ForegroundColor Yellow
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check if the latest feature commit is about square root
|
||||
if ($featureCommitArray[0] -notmatch "sqrt|square|root") {
|
||||
Write-Host "[FAIL] Latest commit on feature branch should be about square root." -ForegroundColor Red
|
||||
Write-Host "Latest commit: $($featureCommitArray[0])" -ForegroundColor Yellow
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "[PASS] Feature work completed!" -ForegroundColor Green
|
||||
|
||||
# Check if worktree was cleaned up (bugfix-worktree should not exist or be removed)
|
||||
Set-Location ..
|
||||
$worktreeStillExists = Test-Path "bugfix-worktree"
|
||||
|
||||
if ($worktreeStillExists) {
|
||||
Write-Host "[WARNING] bugfix-worktree directory still exists." -ForegroundColor Yellow
|
||||
Write-Host "Hint: Clean up with: git worktree remove ../bugfix-worktree" -ForegroundColor Yellow
|
||||
# Don't fail on this, just warn
|
||||
}
|
||||
|
||||
# Check worktree list
|
||||
Set-Location "main-repo"
|
||||
$worktrees = git worktree list 2>$null
|
||||
|
||||
# Verify that the concept was understood (they should have created the worktree at some point)
|
||||
# We can check this by looking for the bugfix branch existence
|
||||
if ($branches -notmatch "bugfix") {
|
||||
Write-Host "[FAIL] No evidence of worktree usage." -ForegroundColor Red
|
||||
Set-Location ../..
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Success!
|
||||
Write-Host "`n========================================" -ForegroundColor Green
|
||||
Write-Host "SUCCESS! Challenge completed!" -ForegroundColor Green
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
Write-Host "`nYou have successfully:" -ForegroundColor Cyan
|
||||
Write-Host "- Created a worktree for the bugfix" -ForegroundColor White
|
||||
Write-Host "- Fixed the division by zero bug" -ForegroundColor White
|
||||
Write-Host "- Committed the fix on the bugfix branch" -ForegroundColor White
|
||||
Write-Host "- Continued feature work in parallel" -ForegroundColor White
|
||||
Write-Host "- Added the square root function" -ForegroundColor White
|
||||
Write-Host "- Committed the feature work" -ForegroundColor White
|
||||
|
||||
if (-not $worktreeStillExists) {
|
||||
Write-Host "- Cleaned up the worktree" -ForegroundColor White
|
||||
}
|
||||
|
||||
Write-Host "`nYou now understand Git worktrees!" -ForegroundColor Green
|
||||
Write-Host "`nKey takeaway:" -ForegroundColor Yellow
|
||||
Write-Host "Worktrees let you work on multiple branches simultaneously" -ForegroundColor White
|
||||
Write-Host "without stashing, switching, or cloning the repository.`n" -ForegroundColor White
|
||||
|
||||
Set-Location ../..
|
||||
exit 0
|
||||
Reference in New Issue
Block a user