Skip to content

Instantly share code, notes, and snippets.

@ben-vargas
Created January 1, 2026 19:33
Show Gist options
  • Select an option

  • Save ben-vargas/8da2a12a64b76773c853ce6717ca2d69 to your computer and use it in GitHub Desktop.

Select an option

Save ben-vargas/8da2a12a64b76773c853ce6717ca2d69 to your computer and use it in GitHub Desktop.
git-worktree skill

Initial Setup (New Projects)

This guide walks through setting up a new project with the bare git repository + worktree structure.

Setup Steps

1. Clone as Bare Repository

# 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/*"

2. Add Upstream Remote (for Forked Repositories Only)

If this is a fork, add the upstream remote:

git remote add upstream <original-repo-url>

3. Create Main Worktree

# Fetch and create main worktree
git fetch origin
git worktree add main main
cd main && git branch --set-upstream-to=origin/main main && cd ..

4. Verify Setup

# Check worktree list
git worktree list

# Check remote configuration
git remote -v

# Verify main worktree is properly tracked
cd main && git status && cd ..

Complete Example

Here's a full example of setting up a new project:

# Navigate to your projects directory
cd ~/projects

# Create project directory
mkdir my-project
cd my-project

# Clone as bare repository
git clone --bare git@github.com:username/my-repo.git .bare

# Create pointer file
echo "gitdir: ./.bare" > .git

# Configure fetch refs
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"

# Fetch all branches
git fetch origin

# Create main worktree
git worktree add main main

# Set upstream tracking for main
cd main
git branch --set-upstream-to=origin/main main
cd ..

# Verify everything works
git worktree list
cd main && git status && cd ..

Creating Additional Worktrees

For a new feature branch:

# From project root
git worktree add feature-name -b feature-name main
cd feature-name && git push -u origin feature-name && cd ..

For an existing remote branch:

# From project root
git worktree add existing-branch existing-branch
cd existing-branch && git branch --set-upstream-to=origin/existing-branch existing-branch && cd ..

Troubleshooting

"fatal: not a git repository"

Make sure you're in the project root directory and the .git pointer file exists:

cat .git
# Should output: gitdir: ./.bare

"no tracking information for the current branch"

Set up upstream tracking:

cd worktree-name
git branch --set-upstream-to=origin/branch-name branch-name
cd ..

"refusing to create a worktree"

The branch might already have a worktree. Check existing worktrees:

git worktree list

If there's a stale entry, clean it up:

git worktree prune

Migration from Old Worktree Setup

This guide helps you convert from a traditional git repository or an old "main/ manages worktrees" approach to the bare repository + worktree structure.

Overview

The migration process:

  1. Backup existing project
  2. Remove existing worktrees (if any)
  3. Create bare repository structure
  4. Recreate worktrees from project root
  5. Verify and cleanup

Step-by-Step Migration

1. Backup and Identify Structure

IMPORTANT: Always backup before starting migration!

# Backup entire project
cp -r my-project my-project-backup

# Navigate to project
cd my-project

# List all files and directories (including hidden)
ls -la

2. Remove Existing Worktrees (if applicable)

If you were using the old "main/ manages worktrees" setup:

# Navigate to main directory
cd main/

# List existing worktrees
git worktree list

# Remove all worktrees except main
git worktree remove ../feature-branch
git worktree remove ../other-branch
# ... repeat for all worktrees

# Verify only main remains
git worktree list

3. Create Bare Repository Structure

# From project root
cd ..

# Clone the main directory's git repo as bare
git clone --bare main/.git .bare

# Remove old .git from main and create pointer
rm -rf main/.git
echo "gitdir: ./.bare" > .git

# Configure fetch refs
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"

# Fetch all branches
git fetch origin

4. Recreate Main Worktree

# Rename old main directory
mv main main-old

# Create new main worktree
git worktree add main main

# Set upstream tracking
cd main && git branch --set-upstream-to=origin/main main && cd ..

# Copy any uncommitted changes from main-old to main
# (if you have uncommitted work)
rsync -av --exclude='.git' main-old/ main/

# Verify main is working
cd main && git status && cd ..

# Remove old main directory (after verifying everything is correct)
rm -rf main-old

5. Recreate Other Worktrees

For each branch you want as a worktree:

# For existing remote branches:
git worktree add feature-branch feature-branch
cd feature-branch && git branch --set-upstream-to=origin/feature-branch feature-branch && cd ..

# For new local branches:
git worktree add new-branch -b new-branch main
cd new-branch && git push -u origin new-branch && cd ..

6. Verify Setup

# Check all worktrees are listed
git worktree list

# Check status of each worktree
cd main && git status && cd ..
cd feature-branch && git status && cd ..

# Verify remote configuration
git remote -v

# If using custom scripts, test them
wt-status  # If you have this script

7. Cleanup

Once everything is verified:

# Remove backup (if everything works)
rm -rf ../my-project-backup

# Clean up any stale worktree references
git worktree prune

Alternative: Clean Migration (No History Loss)

If the above seems complex, you can do a clean migration:

# 1. Note all your branches
cd my-project/main
git branch -a

# 2. Ensure all changes are committed and pushed
git status
git push

# 3. Clone fresh with bare repository setup
cd ~/projects
mv my-project my-project-old
mkdir my-project
cd my-project

# 4. Follow the Initial Setup steps (see INITIAL_SETUP.md)
git clone --bare <repository-url> .bare
echo "gitdir: ./.bare" > .git
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
git fetch origin
git worktree add main main
cd main && git branch --set-upstream-to=origin/main main && cd ..

# 5. Add other worktrees as needed
git worktree add feature-branch feature-branch
cd feature-branch && git branch --set-upstream-to=origin/feature-branch feature-branch && cd ..

# 6. Remove old directory after verification
rm -rf ../my-project-old

Common Migration Issues

Issue: "refusing to create a worktree"

The branch might already exist in the old structure. Remove stale references:

git worktree prune

Issue: Uncommitted changes in old worktrees

Before migration, commit or stash all changes:

# In each old worktree
git status
git stash  # or git commit

Issue: Lost remote tracking after migration

Set upstream tracking for each worktree:

cd worktree-name
git branch --set-upstream-to=origin/branch-name branch-name
cd ..

Issue: .bare directory doesn't exist

Make sure you cloned correctly:

git clone --bare main/.git .bare  # Not just 'git clone'

Verification Checklist

After migration, verify:

  • git worktree list shows all expected worktrees
  • Each worktree directory exists and has content
  • .bare/ directory contains git objects
  • .git pointer file exists at project root
  • git remote -v shows correct remotes
  • cd main && git status works without errors
  • cd main && git pull works without errors
  • All uncommitted work is preserved
  • Custom scripts (wt, wt-status) work if applicable

Rollback Plan

If migration fails:

# Stop migration
cd ~/projects

# Remove failed migration
rm -rf my-project

# Restore backup
cp -r my-project-backup my-project

# Investigate issue before trying again

Git Worktree Command Reference

Complete reference for managing bare git repositories with worktrees.

Core Worktree Commands

Creating Worktrees

# Create worktree for NEW branch (doesn't exist on remote)
git worktree add branch-name -b branch-name main
cd branch-name && git push -u origin branch-name && cd ..

# Create worktree for EXISTING remote branch
git worktree add branch-name branch-name
cd branch-name && git branch --set-upstream-to=origin/branch-name branch-name && cd ..

# Create worktree based on specific branch
git worktree add new-feature -b new-feature existing-branch

# Create worktree at specific path
git worktree add ../path/to/worktree branch-name

Managing Worktrees

# List all worktrees
git worktree list

# List with more details
git worktree list --porcelain

# Remove a worktree
git worktree remove branch-name

# Force remove (with uncommitted changes)
git worktree remove --force branch-name

# Clean up stale worktree references
git worktree prune

# Move a worktree to new location
git worktree move branch-name new-location

# Lock a worktree (prevent removal/pruning)
git worktree lock branch-name

# Unlock a worktree
git worktree unlock branch-name

Worktree Information

# Show current worktree
pwd && git status

# Show branch for current worktree
git branch --show-current

# Show all branches and their worktrees
git worktree list

Remote and Tracking Commands

Remote Configuration

# View configured remotes
git remote -v

# Add origin remote
git remote add origin <repository-url>

# Add upstream remote (for forks)
git remote add upstream <original-repo-url>

# Change remote URL
git remote set-url origin <new-url>

# Remove a remote
git remote remove upstream

Upstream Tracking

# Set upstream for current branch
git branch --set-upstream-to=origin/branch-name

# Set upstream for specific branch
git branch --set-upstream-to=origin/branch-name branch-name

# Push and set upstream in one command
git push -u origin branch-name

# View tracking information
git branch -vv

# Unset upstream
git branch --unset-upstream

Fetching and Syncing

# Fetch from origin
git fetch origin

# Fetch from upstream (for forks)
git fetch upstream

# Fetch all remotes
git fetch --all

# Merge upstream changes (for forks)
cd main
git merge upstream/main
cd ..

# Fetch and prune deleted remote branches
git fetch --prune

Bare Repository Commands

Configuration

# Set fetch configuration (from project root)
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"

# View configuration
git config --list

# View specific config
git config remote.origin.fetch

Inspection

# Check bare repository status
ls -la .bare/

# View all branches (including remote)
git branch -a

# View only remote branches
git branch -r

# View branch details
git show-branch

Custom Helper Scripts

If you have custom scripts installed:

wt (Worktree Quick Create)

# Create and navigate to new worktree
wt feature-name

# Create from specific base branch
wt feature-name develop

# This typically expands to:
# git worktree add feature-name -b feature-name [base-branch]
# cd feature-name

wt-status (Show All Worktrees Status)

# Show status of all worktrees
wt-status

# Typical output shows:
# - Worktree path
# - Current branch
# - Git status
# - Uncommitted changes

Troubleshooting

Common Errors and Solutions

Error: "not a git repository"

Problem: Not in correct directory or .git pointer file missing

Solution:

# Verify you're in project root
pwd

# Check .git pointer file exists
cat .git
# Should output: gitdir: ./.bare

# If missing, recreate it
echo "gitdir: ./.bare" > .git

Error: "no tracking information for the current branch"

Problem: Upstream tracking not configured

Solution:

# Set upstream tracking
git branch --set-upstream-to=origin/branch-name branch-name

# Or push with -u flag
git push -u origin branch-name

Error: "refusing to create a worktree"

Problem: Branch already has a worktree or stale reference exists

Solution:

# Check existing worktrees
git worktree list

# Clean stale references
git worktree prune

# Try again
git worktree add branch-name branch-name

Error: "fatal: 'branch-name' is already checked out"

Problem: Branch is already checked out in another worktree

Solution:

# List all worktrees to see where
git worktree list

# Remove old worktree if no longer needed
git worktree remove old-worktree-name

# Or use a different branch name
git worktree add new-name -b new-name main

Error: "fatal: invalid reference"

Problem: Branch doesn't exist locally or remotely

Solution:

# Fetch latest branches
git fetch origin

# List available branches
git branch -a

# Create new branch if needed
git worktree add new-branch -b new-branch main

Diagnostic Commands

# Check overall git status
git status

# Verify worktree list
git worktree list

# Check remote configuration
git remote -v

# View branch tracking
git branch -vv

# Check fetch configuration
git config remote.origin.fetch

# Verify .bare directory exists
ls -la .bare/

# Check .git pointer
cat .git

Recovery Commands

# Repair missing worktree links
git worktree repair

# Prune stale worktrees
git worktree prune

# Reset upstream tracking
git branch --set-upstream-to=origin/branch-name

# Re-fetch all remotes
git fetch --all --prune

Best Practices

Before Creating Worktrees

  1. Always verify you're in project root: pwd
  2. Check existing worktrees: git worktree list
  3. Fetch latest branches: git fetch origin
  4. Verify remote configuration: git remote -v

When Working in Worktrees

  1. Navigate to worktree directory: cd worktree-name/
  2. Always verify location: pwd && git status
  3. Keep worktrees clean: Commit or stash before switching
  4. Pull latest changes: git pull

When Managing Worktrees

  1. Remove when done: git worktree remove branch-name
  2. Clean stale references: git worktree prune
  3. Verify tracking: git branch -vv
  4. Keep remotes updated: git fetch --prune

For Team Workflows

  1. Document in README that project uses worktrees
  2. Share setup instructions with team
  3. Use consistent naming for worktrees (match branch names)
  4. Communicate when creating/removing shared branches

Advanced Usage

Working with Submodules

# Update submodules in worktree
cd worktree-name
git submodule update --init --recursive

Sharing Worktrees Across Projects

# Create worktree outside project directory
git worktree add ../shared/feature-name feature-name

# This allows sharing code between projects while working

Temporary Worktrees

# Create temporary worktree for quick fixes
git worktree add --detach ../temp-fix HEAD

# Work on it
cd ../temp-fix
# ... make changes ...

# Remove when done
cd ../project-name
git worktree remove ../temp-fix

Branch Cleanup

# Delete remote branch
git push origin --delete branch-name

# Delete local branch (after removing worktree)
git worktree remove branch-name
git branch -d branch-name

# Force delete if not merged
git branch -D branch-name

Quick Reference Card

Task Command
List worktrees git worktree list
Add new branch worktree git worktree add name -b name main
Add existing branch worktree git worktree add name name
Remove worktree git worktree remove name
Clean stale refs git worktree prune
Set upstream git branch --set-upstream-to=origin/name
Check remotes git remote -v
Fetch all git fetch origin
Sync fork git fetch upstream && git merge upstream/main
Where am I? pwd && git status
Show all branches git branch -a

Additional Resources

name description allowed-tools
git-worktree
Manages bare git repositories with worktrees where each subdirectory represents a different branch. Use when: working with git worktrees, seeing .bare/ directories, creating/removing worktrees, managing multiple branches simultaneously, or when user mentions worktree, bare repository, or branch directories.
Bash, Read, Glob, Grep

Git Bare Repository Worktree Workflow

🚨 CRITICAL: Understanding the Project Structure

This project uses bare Git repository with worktrees. Every subdirectory represents a different git branch as a worktree.

Structure:

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)

Daily Workflow

  1. Navigate to branch: cd main/ or cd feature-auth/
  2. Work normally within each worktree directory
  3. Create worktrees from project root: git worktree add new-feature -b new-feature
  4. Switch branches by changing directories (never use git checkout)

Common Commands

For NEW branches (not on remote):

git worktree add branch-name -b branch-name main
cd branch-name && git push -u origin branch-name && cd ..

For EXISTING remote branches:

git worktree add branch-name branch-name
cd branch-name && git branch --set-upstream-to=origin/branch-name branch-name && cd ..

Management:

git worktree list                 # List all worktrees
git worktree remove branch-name   # Remove worktree
git worktree prune               # Clean stale refs

Verification:

pwd && git status                # Where am I?
git worktree list                # Show all worktrees

Custom scripts (if available):

wt feature-name [base-branch]    # Quick create + navigate
wt-status                        # Status of all worktrees

Critical Guidelines

βœ… DO:

  • Run git worktree list from 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:

  • 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

⚠️ Critical: Upstream Tracking & Remote Configuration

Every Worktree Needs Upstream Tracking

EVERY worktree needs upstream tracking configured! Without this, git pull and git push will fail with "no tracking information" errors.

  • New branches: Use git push -u origin branch-name
  • Existing branches: Run git branch --set-upstream-to=origin/branch-name branch-name
  • This applies to ALL worktrees, not just main!

Verify Remote Configuration

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>

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

Additional Resources

  • New project setup: See INITIAL_SETUP.md for detailed instructions on setting up a new bare repository with worktrees
  • Migrate existing repos: See MIGRATION.md for converting from traditional git repos to this worktree structure
  • Full command reference: See REFERENCE.md for troubleshooting and advanced usage

Summary

Every 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment