I use a bare Git repository approach with Git worktrees extensively. Every subdirectory in my projects represents a different git branch as a worktree.
When you see a project like /home/code/projects/my-app/:
my-app/= project container (NOT a working tree)my-app/.bare/= actual Git repository databasemy-app/.git= pointer file directing Git commands to.bare/- All other subdirectories = worktrees representing different branches
project-name/ # Project container (NOT a working tree)
βββ .bare/ # ποΈ Bare git repository (the actual Git database)
βββ .git # π Pointer file directing Git commands to .bare
βββ main/ # β
Worktree (branch: main)
βββ feature-auth/ # β
Worktree (branch: feature-auth)
βββ hotfix-security/ # β
Worktree (branch: hotfix-security)
Before setting up worktrees, ensure your remotes are properly configured:
git remote -v # Check existing remotes
# If no origin exists (rare but possible):
git remote add origin <your-repo-url>
# For forked repositories, also add upstream:
git remote add upstream <original-repo-url>EVERY worktree needs upstream tracking configured! Without this, git pull and git push will fail with "no tracking information" errors.
- When creating new branches: Use
git push -u origin branch-name - When adding worktrees for existing remote branches: Run
git branch --set-upstream-to=origin/branch-name branch-name - This applies to ALL worktrees, not just main!
# Clone and setup bare repository
git clone --bare <repository-url> .bare
echo "gitdir: ./.bare" > .git
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
# For forked repositories, add upstream remote
git remote add upstream <original-repo-url> # Only if this is a fork
# Fetch and create main worktree
git fetch origin
git worktree add main main
cd main && git branch --set-upstream-to=origin/main main && cd ..- Navigate to branch:
cd main/orcd feature-auth/ - Work normally within each worktree directory
- Create worktrees from project root:
git worktree add new-feature -b new-feature - Switch branches by changing directories (never use
git checkout)
# Worktree management (from project root)
# For NEW branches (not on remote yet):
git worktree add branch-name -b branch-name main # Create new
cd branch-name && git push -u origin branch-name && cd .. # Push and set upstream
# For EXISTING remote branches:
git worktree add branch-name branch-name # Create worktree
cd branch-name && git branch --set-upstream-to=origin/branch-name branch-name && cd ..
# Other commands:
git worktree remove branch-name # Remove
git worktree list # List all
git worktree prune # Clean stale refs
# Verification
pwd && git status # Where am I?
git worktree list # Show all worktrees
# Custom scripts (available globally)
wt feature-name [base-branch] # Quick create + navigate
wt-status # Status of all worktrees
# For forked repositories - sync with upstream
git fetch upstream # Get latest from original repo
cd main && git merge upstream/main && cd .. # Update main from upstream- Run
git worktree listfrom project root to see all worktrees - Navigate to correct worktree directory before making changes
- Use branch names directly as directory names
- Run worktree management (add/remove/list) from project root
- Don't run git commands from project root (except worktree management)
- Don't use
git checkout- change directories instead - Don't assume any directory is special - all worktrees are equal
To convert from old "main/ manages worktrees" approach:
# 1. Backup and identify structure
cp -r my-project my-project-backup
cd my-project && ls -la
# 2. Remove existing worktrees (from main/)
cd main/
git worktree list # See what exists
git worktree remove ../feature-branch # Remove all except main/
# 3. Create bare structure
cd .. && git clone --bare main/.git .bare
rm -rf main/.git && echo "gitdir: ./.bare" > .git
# 4. Configure and recreate worktrees
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
git fetch origin
mv main main-old && git worktree add main main
cd main && git branch --set-upstream-to=origin/main main && cd ..
# Copy uncommitted changes from main-old to main/
rm -rf main-old
# 5. Recreate other worktrees
git worktree add feature-branch feature-branch
cd feature-branch && git branch --set-upstream-to=origin/feature-branch feature-branch && cd ..
# 6. Verify
git worktree list && wt-statusEvery subdirectory is a worktree representing a different branch. Project root contains bare repository for worktree management only. Navigate between branches by changing directories. All git operations happen within worktree directories.