Use Git Worktrees for Parallel WordPress Theme and Plugin Development

Git worktrees allow multiple working directories to be checked out from a single Git repository simultaneously — each worktree has its own working files and index, but they all share the same .git directory and object database, meaning no disk space is wasted on duplicate history and switching between worktrees is instantaneous compared to cloning multiple copies of a large WordPress repository. The primary worktree is the repository root created by git clone; additional linked worktrees are created with git worktree add <path> <branch>, which checks out the specified branch into a new directory. A common WordPress development workflow: main branch in the primary worktree running the production-like XAMPP environment on port 8080, a feature/new-checkout-flow worktree in a separate directory running on port 8081, and a hotfix/urgent-security-patch worktree ready for the production server — all three can be edited and tested simultaneously without stashing changes or switching branches. Worktrees are particularly useful for WordPress theme development when a long-running design overhaul on a feature branch should not block the ability to apply and test a quick CSS fix on main — adding a worktree takes 2 seconds versus 30+ seconds to stash, switch branches, and unstash. Running git worktree list shows all active worktrees with their paths, HEAD commits, and branch names. Removing a worktree is done with git worktree remove <path>, which deletes the worktree directory and cleans up the linked worktree metadata. The branch checked out in one worktree is locked and cannot be checked out in another worktree simultaneously — this prevents the two worktrees from corrupting each other’s working state. The Git submodules post covers sharing code between projects; worktrees cover working on multiple branches within one project simultaneously.

Problem: A WordPress developer is in the middle of a two-week theme redesign on a feature branch when a critical bug is reported in production — switching branches to create a hotfix means stashing in-progress work, losing the local server state, and waiting for the branch switch to complete on a large repository with many generated asset files.

Solution: Add a separate worktree for the hotfix branch — the feature branch worktree continues running untouched while the hotfix is developed, tested, and deployed from its own directory with its own local server instance.

# ── Current state: feature branch in primary worktree ────────────────────────
cd ~/projects/my-wp-theme   # main working directory, feature/redesign branch
git branch   # * feature/redesign

# ── Add a hotfix worktree WITHOUT disturbing the current work ─────────────────
# Creates /tmp/hotfix-worktree directory checked out at main branch
git worktree add /tmp/hotfix-worktree main

# Open the hotfix worktree in a separate editor/terminal window
cd /tmp/hotfix-worktree

# Create hotfix branch from main
git checkout -b hotfix/fix-mobile-nav

# Make the fix, test it with a second local server on a different port
vim wp-content/themes/my-theme/css/nav.css

git add -p
git commit -m "fix: mobile nav dropdown z-index on iOS Safari"

# Push hotfix and merge to main
git push origin hotfix/fix-mobile-nav
# ... create PR, merge via GitHub/GitLab UI, then:
git checkout main && git pull

# ── Return to feature work unaffected ────────────────────────────────────────
cd ~/projects/my-wp-theme   # feature/redesign branch still intact
# No stash pop needed, no branch switch, local server was never touched

# ── Merge main fixes back into the feature branch ────────────────────────────
git merge main --no-ff -m "merge: pull hotfix from main into redesign"

# ── Clean up the hotfix worktree after merging ────────────────────────────────
git worktree remove /tmp/hotfix-worktree
git branch -d hotfix/fix-mobile-nav

# ── List all active worktrees ─────────────────────────────────────────────────
git worktree list
# /home/dev/projects/my-wp-theme  a1b2c3d [feature/redesign]

# ── Add a worktree for a brand-new branch from origin/main ───────────────────
git worktree add -b feature/new-footer ~/projects/my-wp-theme-footer origin/main

# ── Prune stale worktree entries (e.g., directory was deleted manually) ───────
git worktree prune --verbose

NOTE: Each linked worktree needs its own wp-config.php pointing to a separate WordPress database if you want fully independent WordPress instances per branch — otherwise, both worktrees share the same database and a schema migration in one branch will break the other. A clean approach is to maintain a wp-config-local.php with per-worktree database settings, add if (file_exists(__DIR__ . '/wp-config-local.php')) require_once __DIR__ . '/wp-config-local.php'; at the top of wp-config.php, and list wp-config-local.php in .gitignore. This lets each worktree have its own WP_HOME, WP_SITEURL, and DB_NAME without touching the committed configuration file.