Git Worktrees: From Zero to Hero - A comprehensive guide to using Git worktrees with submodules Git worktrees allow developers to create multiple working directories from a single Git repository, enabling different branches to be checked out simultaneously without context switching. This solves the problem of having to stash or commit work before switching branches, as each worktree operates independently while sharing the same Git history. The article also covers how to use worktrees with submodules in monolith repositories, requiring separate initialization and management of each submodule across different worktrees. Git Worktrees: From Zero to Hero Table of Contents 1. What Are Git Worktrees? First Principles what-are-git-worktrees-first-principles 2. The Problem Worktrees Solve the-problem-worktrees-solve 3. How Worktrees Work how-worktrees-work 4. Worktrees + Submodules: Monolith Setup worktrees--submodules-monolith-setup 5. Practical Tutorial: Creating Your First Worktree practical-tutorial-creating-your-first-worktree 6. Advanced Workflows advanced-workflows 7. Best Practices best-practices 8. Troubleshooting troubleshooting 9. For Non-Technical Stakeholders for-non-technical-stakeholders --- What Are Git Worktrees? First Principles The Traditional Git Model Normally, when you work with Git, you have: - One working directory the folder with your code - One active branch at a time - Switching branches changes all files in that directory my-project/ ├── src/ ├── README.md └── .git/ When you run git checkout feature-branch , ALL files change to match that branch. The Worktree Model Git worktrees let you have: - Multiple working directories from the same repository - Different branches checked out simultaneously - Independent work in each directory my-project/ ← Main repo main branch ├── src/ ├── README.md └── .git/ my-project-feature-1/ ← Worktree 1 feature-1 branch ├── src/ ├── README.md └── .git ← File pointing to main repo my-project-feature-2/ ← Worktree 2 feature-2 branch ├── src/ ├── README.md └── .git ← File pointing to main repo Key Insight Think of worktrees as parallel universes of your code: - Each universe worktree shows your project at a different point in time branch/commit - Changes in one universe don't affect the others - All universes share the same Git history they're connected to the same .git repository --- The Problem Worktrees Solve Without Worktrees Traditional Workflow bash Working on feature A git checkout feature-a Make changes, test, etc. Need to quickly check feature B git stash Save current work git checkout feature-b Switch context Look at feature B code Back to feature A git checkout feature-a git stash pop Restore work Continue where you left off Problems: - Context switching overhead - Risk of losing uncommitted work - Can't compare branches side-by-side - Can't run tests on multiple branches simultaneously - Interrupts your flow With Worktrees bash Create separate worktrees git worktree add ../project-feature-a feature-a git worktree add ../project-feature-b feature-b Work in parallel cd ../project-feature-a Work on feature A cd ../project-feature-b Work on feature B in another terminal Benefits: - No context switching - Work on multiple features simultaneously - Compare code side-by-side - Run different tests in parallel - Perfect for AI tools like Claude Code --- How Worktrees Work The Git Magic When you create a worktree, Git: 1. Creates a new directory with all your project files 2. Links it to the main repository shares Git history 3. Checks out a specific branch in that directory 4. Prevents conflicts same branch can't be checked out twice Under the Hood main-repo/ └── .git/ ├── objects/ ← All Git data shared ├── refs/ ← Branch references shared └── worktrees/ ← Worktree metadata ├── worktree-1/ └── worktree-2/ worktree-1/ ├── your-files/ ← Working files independent └── .git ← File pointing to main-repo/.git worktree-2/ ├── your-files/ ← Working files independent └── .git ← File pointing to main-repo/.git The "One Branch Per Worktree" Rule Git prevents the same branch from being checked out in multiple worktrees: bash This works git worktree add ../repo-feature-a feature-a This fails if feature-a is already checked out git worktree add ../repo-feature-a-copy feature-a Error: 'feature-a' is already checked out This prevents confusion and conflicts. --- Worktrees + Submodules: Monolith Setup What Makes This Setup Special A monolith repository can contain multiple repositories as submodules : monolith/ ├── frontend/ ← Git submodule separate repo ├── backend/ ← Git submodule separate repo ├── infrastructure/ ← Git submodule separate repo ├── shared-components/ ← Git submodule separate repo └── .gitmodules ← Submodule configuration The Challenge When you create a worktree of a repository with submodules: - The main repository gets a new worktree - The submodules need to be initialized separately - Each submodule can be on different branches in different worktrees Automation Solution Create automation scripts to handle this complexity: - create worktree.py https://gist.github.com/ashwch/79177b4af7f2ea482418d6e9934d4787 - Creates worktrees with proper submodule setup - update submodules.py https://gist.github.com/ashwch/909ea473250e8c8a937a8a4aa4a4dc72 - Manages submodule updates Visual Example monolith/ ← Main repo main branch ├── frontend/ main branch ├── backend/ main branch └── infrastructure/ main branch monolith-feature-123/ ← Worktree feature-123 branch ├── frontend/ feature-123-frontend branch ├── backend/ main branch └── infrastructure/ feature-123-infra branch Notice how: - Main repo worktree is on feature-123 branch - Each submodule can be on different branches - This lets you work on related changes across multiple repositories --- Practical Tutorial: Creating Your First Worktree Prerequisites bash Make sure you're in the main repository cd /path/to/your-monolith Check current setup git status git worktree list Method 1: Using Automated Script Recommended bash Run smart worktree creation script python scripts/create worktree.py or with uv: uv run scripts/create worktree.py What this script does: 1. Asks for a worktree name suggests smart defaults 2. Shows available branches for main repo with search 3. For each submodule , lets you choose which branch to use 4. Creates the worktree one directory above current location 5. Initializes all submodules with your chosen branches 6. Handles conflicts gracefully Example interaction: Enter worktree name e.g., 'feature-auth' : feature-oauth Creating worktree: ../monolith-feature-oauth Select branch for main repository: 1 main 2 feature/oauth-integration 3 develop Choice: 2 Select branch for frontend submodule: 1 main 2 feature/oauth-ui 3 develop Choice: 2 ... continues for each submodule ✅ Worktree created successfully 📁 Location: ../monolith-feature-oauth 🌳 Branch: feature/oauth-integration Method 2: Manual Creation Educational Step 1: Create the Basic Worktree bash Create worktree in parent directory git worktree add ../monolith-feature-oauth feature/oauth-integration Navigate to the new worktree cd ../monolith-feature-oauth Step 2: Initialize Submodules bash Initialize all submodules this takes time git submodule update --init --recursive Check what branches submodules are on git submodule foreach 'echo "Submodule: $name, Branch: $ git branch --show-current "' Step 3: Set Up Submodule Branches Optional bash Switch submodules to feature branches if needed cd frontend git checkout feature/oauth-ui cd ../backend git checkout main or whatever branch you need cd ../infrastructure git checkout feature/oauth-config cd .. Verify Your Setup bash Check worktree status git worktree list Check branch in main repo git branch --show-current Check submodule branches git submodule foreach 'echo "$name: $ git branch --show-current "' --- Advanced Workflows Working Across Multiple Worktrees Scenario: Comparing Two Feature Implementations bash Create two worktrees for comparison python scripts/create worktree.py Create approach-a python scripts/create worktree.py Create approach-b Work in parallel cd ../monolith-approach-a Implement solution A cd ../monolith-approach-b Implement solution B Compare side-by-side in your IDE code ../monolith-approach-a ../monolith-approach-b Scenario: AI-Assisted Development bash Create worktree for AI session python scripts/create worktree.py In the new worktree, run Claude Code cd ../monolith-feature-ai-assist claude Meanwhile, continue manual work in main repo cd /path/to/monolith Continue your work without interruption Managing Submodule Changes Making Changes Across Multiple Repos bash In your worktree cd ../monolith-feature-123 Make changes in frontend cd frontend git checkout -b feature-123-frontend Make changes git add . && git commit -m "Frontend changes for feature 123" git push origin feature-123-frontend Make changes in backend cd ../backend git checkout -b feature-123-backend Make changes git add . && git commit -m "Backend changes for feature 123" git push origin feature-123-backend Update monolith to point to new commits cd .. git add frontend backend git commit -m "Update submodules for feature 123" git push origin feature-123 Updating Submodules from Remote bash Use update script python scripts/update submodules.py Or manually git submodule update --recursive --remote Cleaning Up Worktrees When Feature is Complete bash List all worktrees git worktree list Remove completed worktree git worktree remove ../monolith-feature-123 Clean up any leftover references git worktree prune --- Best Practices Naming Conventions bash Good worktree names ../monolith-feature-auth Feature-based ../monolith-bugfix-12345 Issue-based ../monolith-hotfix-critical Purpose-based ../monolith-experiment-new-arch Experiment-based Avoid ../temp Too generic ../test Unclear purpose ../monolith Confusing with main Directory Organization bash Recommended structure projects/ ├── monolith/ ← Main repository ├── monolith-feature-auth/ ← Feature worktree ├── monolith-feature-payments/ ← Another feature └── monolith-hotfix-urgent/ ← Hotfix worktree Branch Strategy bash Main repository branches main ← Production develop ← Integration feature/auth-system ← Feature branch hotfix/critical-bug ← Hotfix branch Submodule branches can be independent frontend: feature/auth-ui backend: feature/auth-api infrastructure: main ← Unchanged for this feature Workflow Tips 1. One Worktree Per Feature - Don't reuse worktrees for different features - Create new worktrees for each major task - Clean up when done 2. Initialize Submodules Immediately bash Always run after creating worktree git submodule update --init --recursive 3. Use Automation Scripts bash Let automation handle complexity python create worktree.py Download from: https://gist.github.com/ashwch/79177b4af7f2ea482418d6e9934d4787 python update submodules.py Download from: https://gist.github.com/ashwch/909ea473250e8c8a937a8a4aa4a4dc72 4. Regular Cleanup bash Weekly cleanup of old worktrees git worktree list git worktree remove ../old-worktree-name git worktree prune --- Troubleshooting Common Issues and Solutions Issue: "Branch is already checked out" bash Error when trying to create worktree fatal: 'main' is already checked out at '/path/to/monolith' Solution: Use a different branch or create new branch git worktree add ../monolith-new -b new-branch-name main Issue: Submodules Not Initialized bash Symptoms: Empty submodule directories ls frontend/ Empty Solution: Initialize submodules git submodule update --init --recursive Issue: Submodule in Wrong Branch bash Check current branches git submodule foreach 'echo "$name: $ git branch --show-current "' Fix: Switch to correct branch cd problematic-submodule git checkout correct-branch cd .. Issue: Can't Remove Worktree bash Error: worktree contains modified or untracked files git worktree remove ../old-worktree Solution: Force removal loses uncommitted changes git worktree remove --force ../old-worktree Issue: Submodule Conflicts During Merge bash When merging between branches with different submodule commits Solution: Choose which submodule commits to keep git add problematic-submodule git commit -m "Resolve submodule conflicts" Performance Tips Large Repository Optimization bash Speed up submodule operations git config submodule.recurse true git config diff.submodule log git config status.submodulesummary 1 Disk Space Management bash Share objects between worktrees done automatically But be aware: multiple worktrees = multiple working copies Check disk usage du -sh ../monolith --- For Non-Technical Stakeholders What This Means for You The Problem We Solved Imagine you're writing a document and need to: - Work on Chapter 1 revisions - Also draft Chapter 5 - Compare two different approaches for Chapter 3 Traditionally, you'd have to: 1. Save Chapter 1 work 2. Switch to Chapter 5 3. Save Chapter 5 work 4. Switch to Chapter 3 5. Go back and forth constantly This is inefficient and error-prone. Our Solution: Git Worktrees Now we can have: - Document-v1/ folder for Chapter 1 work - Document-v2/ folder for Chapter 5 work - Document-experiment/ folder for Chapter 3 approaches All folders stay synchronized with the main document, but you can work on different parts independently. Business Benefits 1. Faster Development - No context switching delays - developers stay in flow - Parallel development - multiple features simultaneously - Reduced merge conflicts - isolated work streams 2. Better Quality - Side-by-side comparisons - easy to evaluate approaches - Isolated testing - test features without affecting others - Safer experimentation - try ideas without risk 3. Enhanced Collaboration - AI tools work better - can analyze multiple implementations - Code reviews easier - compare implementations directly - Knowledge sharing - team members can see different approaches Impact on Project Timelines Before Worktrees Week 1: Start Feature A Week 2: Urgent bug interrupt → Switch context → Fix bug Week 3: Return to Feature A → Re-understand code → Continue Week 4: Complete Feature A Total: 4 weeks for Feature A + 1 bug fix With Worktrees Week 1: Start Feature A main worktree Week 2: Urgent bug → Create hotfix worktree → Fix bug in parallel Week 3: Complete Feature A uninterrupted + Complete bug fix Week 4: Start Feature B Total: 3 weeks for Feature A + 1 bug fix + start Feature B What You'll Notice As a Product Manager - Faster feature delivery - less time lost to context switching - Better estimations - developers can work more predictably - Easier demonstrations - can show multiple versions side-by-side As a Designer - Quick iterations - developers can implement multiple design approaches - Live comparisons - see different implementations running simultaneously - Faster feedback loops - no delay switching between versions As a Stakeholder - More reliable timelines - fewer interruptions and delays - Higher quality output - easier to compare and choose best solutions - Reduced risk - experiments don't affect main development --- Summary Git worktrees with submodules give us superpowers: 1. Multiple parallel universes of our codebase 2. No context switching between features 3. AI tools work better with isolated environments 4. Complex projects simplified through automation 5. Team productivity increased through better workflows Key Commands to Remember bash Create worktree automated python scripts/create worktree.py List worktrees git worktree list Remove worktree git worktree remove ../worktree-name Update submodules python scripts/update submodules.py Next Steps 1. Try creating your first worktree with our script 2. Experiment with parallel development 3. Use worktrees for your next feature 4. Share this guide with your team 5. Contribute improvements to automation scripts --- This guide covers Git worktrees with submodules for modern development workflows. Questions? Contributions welcome