worktree-operations
Guide for working within git worktrees in the tennis-team monorepo. Use this skill when you detect you're working in a worktree (path contains "claude-worktrees" or is outside the main project directory), when asked to "set up worktree", "install dependencies in worktree", "build in worktree", "merge worktree", or when troubleshooting worktree-specific issues. Covers Docker infrastructure, PostgreSQL/Redis setup, pnpm/turbo commands, environment setup, git workflows (merging, conflict resolution, cleanup), and common worktree pitfalls.
SKILL.md
| Name | worktree-operations |
| Description | Guide for working within git worktrees in the tennis-team monorepo. Use this skill when you detect you're working in a worktree (path contains "claude-worktrees" or is outside the main project directory), when asked to "set up worktree", "install dependencies in worktree", "build in worktree", "merge worktree", or when troubleshooting worktree-specific issues. Covers Docker infrastructure, PostgreSQL/Redis setup, pnpm/turbo commands, environment setup, git workflows (merging, conflict resolution, cleanup), and common worktree pitfalls. |
name: worktree-operations description: Guide for working within git worktrees in the tennis-team monorepo. Use this skill when you detect you're working in a worktree (path contains "claude-worktrees" or is outside the main project directory), when asked to "set up worktree", "install dependencies in worktree", "build in worktree", "merge worktree", or when troubleshooting worktree-specific issues. Covers Docker infrastructure, PostgreSQL/Redis setup, pnpm/turbo commands, environment setup, git workflows (merging, conflict resolution, cleanup), and common worktree pitfalls.
Worktree Operations
Detecting a Worktree
You're in a worktree if:
- Path contains
claude-worktrees(e.g.,~/claude-worktrees/tennis-team/my-feature-123456) - Path is outside the main project directory but contains project files
- Branch name starts with
worktree/
Worktrees are isolated checkouts used for parallel development without affecting the main checkout.
Initial Setup (After Worktree Creation)
When a worktree is first created, run these commands:
# Install dependencies with pnpm (runs automatically via worktree creation script)
pnpm install
# Start Docker infrastructure (PostgreSQL + Redis)
pnpm docker:infra
# Run database migrations
pnpm --filter @tennis/backend run db:migrate
Tennis-Team Project Structure
tennis-team/
├── apps/
│ ├── backend/ # Express API server (@tennis/backend)
│ ├── frontend/ # React frontend app (@tennis/frontend)
│ └── website/ # Public website (@tennis/website)
├── packages/
│ └── shared/ # Shared types and utilities (@tennis/shared)
├── docker/
│ ├── docker-compose.yml # Infrastructure services
│ └── docker-compose.dev.yml # Dev overrides
├── pnpm-workspace.yaml
├── turbo.json
└── package.json
Referencing Packages
Use workspace protocol in package.json:
{
"dependencies": {
"@tennis/shared": "workspace:*"
}
}
Docker Infrastructure Setup
The tennis-team project uses Docker for PostgreSQL and Redis.
Starting Infrastructure
# Start PostgreSQL + Redis (from project root)
pnpm docker:infra
# Start full dev environment (all services)
pnpm docker:dev
# Check container status
docker compose -f docker/docker-compose.yml ps
Verifying Services
# Check PostgreSQL
psql -h localhost -U postgres -c "SELECT 1;"
# Check Redis
redis-cli ping
# Should return: PONG
Troubleshooting Docker
# Containers not starting
docker compose -f docker/docker-compose.yml logs postgres
docker compose -f docker/docker-compose.yml logs redis
# Reset containers
docker compose -f docker/docker-compose.yml down -v
pnpm docker:infra
Database Setup in Worktrees
Worktrees can use either a shared database (default) or an isolated database (for schema testing).
Shared Database (Default)
Uses the same database as your main development environment. No additional setup needed.
# Your .env already points to the shared dev database
# Just ensure Docker is running and start developing!
pnpm docker:infra
pnpm run dev
Isolated Database (For Schema Testing)
When you need a separate database (for migrations, schema changes, or isolated testing), use the --isolated flag when creating the worktree:
# Via worktree manager
.claude/skills/claude-worktree-manager/scripts/worktree.sh create my-feature --isolated
This automatically:
- Creates a new PostgreSQL database:
tennis_worktree_<timestamp> - Updates your
.envwith the newDATABASE_URL - Runs all migrations via
pnpm --filter @tennis/backend run db:migrate
Manual Database Operations
# Run migrations
pnpm --filter @tennis/backend run db:migrate
# Connect to database
psql -h localhost -U postgres -d tennis_dev
# List all databases
psql -h localhost -U postgres -c "\l"
Isolated DB Cleanup
# List worktree databases
psql -h localhost -U postgres -c "SELECT datname FROM pg_database WHERE datname LIKE 'tennis_worktree_%';"
# Drop a specific worktree database
psql -h localhost -U postgres -c "DROP DATABASE tennis_worktree_<timestamp>;"
When to Use Isolated Database
Use isolated database when:
- Testing new migrations before merging
- Developing schema changes
- Running destructive tests
- Need a clean database state
Skip isolated database when:
- Normal feature development
- Bug fixes
- Frontend work
- Changes that don't touch the database
Redis Cache Management
Redis is used for caching. In worktrees:
# Check Redis connection
redis-cli ping
# Clear all cache (development only)
redis-cli FLUSHALL
# Monitor Redis activity
redis-cli MONITOR
Worktrees share the same Redis instance by default. If you need isolation, use a different Redis database number in your .env:
REDIS_URL="redis://localhost:6379/1" # Use DB 1 instead of default 0
Tennis-Team Dev Workflow
Starting Development
# Start infrastructure first
pnpm docker:infra
# Start all apps in dev mode (backend + frontend + website)
pnpm dev
# Or start specific apps
pnpm --filter @tennis/backend run dev
pnpm --filter @tennis/frontend run dev
Common Commands (pnpm + turbo)
Building
# Build all packages
pnpm run build
# Build a specific package
pnpm --filter @tennis/backend run build
pnpm --filter @tennis/shared run build
# Build with turbo (uses caching)
pnpm turbo run build
# Force rebuild (ignore cache)
pnpm turbo run build --force
Testing
# Run all tests
pnpm test
# Run tests for a specific package
pnpm --filter @tennis/backend run test
# Run with turbo (respects dependencies)
pnpm turbo run test
Development
# Start development mode (all apps)
pnpm run dev
# Run linting
pnpm run lint
# Type checking
pnpm run typecheck
pnpm and Turbo in Monorepos
pnpm Workspace Architecture
How pnpm Works:
- Content-addressable store at
~/.pnpm-store - Symlinked
node_modules(not flat like npm) - Shared dependencies across all worktrees
- Hard links from store to project
node_modules
Directory Structure:
project/
├── node_modules/
│ ├── .pnpm/ # Actual packages (symlinked)
│ ├── @tennis/shared -> .pnpm/... # Workspace packages
│ └── react -> .pnpm/... # External packages
├── apps/
│ ├── backend/
│ │ └── node_modules/ -> ../../node_modules
│ └── frontend/
│ └── node_modules/ -> ../../node_modules
└── pnpm-lock.yaml # Lock file (CRITICAL)
Dependency Installation Patterns
Pattern 1: Root Level Dependencies (Shared)
# Install dependency for all packages
pnpm add -w typescript # -w = workspace root
# Install dev dependency at root
pnpm add -D -w eslint
Pattern 2: Package-Specific Dependencies
# Install in specific package
pnpm --filter @tennis/backend add express
# Install dev dependency in package
pnpm --filter @tennis/backend add -D jest
Pattern 3: Workspace Protocol Dependencies
// apps/backend/package.json
{
"dependencies": {
"@tennis/shared": "workspace:*"
}
}
Lock File Management
Understanding pnpm-lock.yaml
Critical File: pnpm-lock.yaml must be committed and kept in sync.
Lock File Rules:
- Commit
pnpm-lock.yamlto git - Never manually edit lock file
- Run
pnpm installafter pulling changes - Don't ignore lock file in
.gitignore
Handling Lock File Conflicts
# During merge conflict - accept theirs and regenerate (RECOMMENDED)
git checkout --theirs pnpm-lock.yaml
pnpm install # Regenerates lock file with your changes
# After resolving
git add pnpm-lock.yaml
git commit --no-edit
Common pnpm Issues in Worktrees
Issue 1: .pnpm-install.pid Blocking Operations
# Before merging branches
rm -f .pnpm-install.pid
# If locked by process
lsof .pnpm-install.pid # Find process using file
kill <PID>
rm .pnpm-install.pid
Issue 2: node_modules Symlink Confusion
# Workspace packages symlink
ls -la node_modules/@tennis/shared # -> ../packages/shared
Issue 3: Workspace Dependencies Not Updating
# Rebuild affected packages
pnpm --filter @tennis/shared run build
# Or rebuild everything
pnpm turbo run build --force
Issue 4: Different pnpm Versions
# Check required version
cat package.json | jq .packageManager
# Install correct version globally
npm install -g pnpm@9.15.4
# Or use Corepack (recommended)
corepack enable
corepack prepare pnpm@9.15.4 --activate
Turbo Build Caching
Turbo in Worktrees
Issue: Turbo cache is worktree-local
# Workaround: Share cache between worktrees
export TURBO_CACHE_DIR=~/.turbo-cache
Cache Invalidation
# Clear turbo cache
pnpm turbo run build --force # Bypass cache
# Delete cache directory
rm -rf node_modules/.cache/turbo
Debugging Turbo
# See what turbo is doing
pnpm turbo run build --dry-run
# Verbose output
pnpm turbo run build --verbose
# Show cache hits/misses
pnpm turbo run build --summarize
pnpm Commands Reference
Installation
# Install all dependencies (respects lock file)
pnpm install
# Install with frozen lock file (CI mode)
pnpm install --frozen-lockfile
# Force reinstall everything
pnpm install --force
Adding Dependencies
# Add to root workspace
pnpm add -w <package>
# Add to specific package
pnpm --filter <package-name> add <dependency>
# Add with version constraint
pnpm add react@^18.0.0
Removing Dependencies
# Remove from specific package
pnpm --filter <package-name> remove <dependency>
# Remove from workspace root
pnpm remove -w <package>
Workspace Commands
# Run script in all packages
pnpm -r run build # -r = recursive
# Run in specific package
pnpm --filter @tennis/backend run test
# Run in packages matching glob
pnpm --filter "./apps/*" run start
# Run with dependencies first
pnpm --filter @tennis/frontend... run build
# ... = include dependencies
Best Practices for pnpm in Worktrees
-
Keep lock file in sync
git pull origin main pnpm install -
Clean install for stale worktrees
rm -rf node_modules rm pnpm-lock.yaml git checkout main -- pnpm-lock.yaml pnpm install -
Use consistent pnpm version
{ "packageManager": "pnpm@9.15.4" } -
Ignore temporary files
.pnpm-install.pid .pnpm-debug.log node_modules/.cache/ -
Use filters for focused work
pnpm --filter @tennis/backend... run build pnpm turbo run test --filter=[HEAD^1] -
Handle lock file conflicts properly
git checkout --theirs pnpm-lock.yaml pnpm install git add pnpm-lock.yaml -
Clean up before merging
rm -f .pnpm-install.pid rm -rf node_modules/.cache pnpm install pnpm run build -
Don't mix npm and pnpm
# Always use pnpm in this project pnpm install
Troubleshooting pnpm Issues
"EBUSY: resource busy or locked"
pkill -f pnpm
rm .pnpm-install.pid
pnpm install
"Cannot find module '@tennis/shared'"
pnpm --filter @tennis/shared run build
pnpm run build
"integrity check failed"
rm pnpm-lock.yaml
pnpm install
git add pnpm-lock.yaml
Common Git Worktree Workflows
Workflow 1: Merging Worktree Branch to Main (via PR)
# 1. Ensure branch is pushed
cd ~/claude-worktrees/tennis-team/my-feature-1234567
git push -u origin HEAD
# 2. Create PR using gh CLI
gh pr create \
--base main \
--title "feat: my feature" \
--body "Summary of changes"
# 3. After merge, clean up worktree
cd /path/to/main/repo
git worktree remove ~/claude-worktrees/tennis-team/my-feature-1234567
git fetch origin --prune
Workflow 2: Syncing Worktree with Main Branch
# 1. Navigate to worktree
cd ~/claude-worktrees/tennis-team/my-feature-1234567
# 2. Stash any uncommitted changes
git stash push -m "WIP: before sync"
# 3. Fetch latest from origin
git fetch origin main
# 4. Rebase onto main (cleaner history)
git rebase origin/main
# 5. Restore stashed changes
git stash pop
# 6. Rebuild dependencies and code
pnpm install
pnpm run build
Workflow 3: Handling Stale Worktrees
Option A: Update and Continue Working
cd ~/claude-worktrees/tennis-team/my-old-feature
# 1. Fetch latest
git fetch origin --prune
# 2. Rebase or merge latest changes
git rebase origin/main
# 3. Update dependencies (critical for stale worktrees)
pnpm install
# 4. Rebuild everything
pnpm turbo run build --force
# 5. Start Docker infrastructure
pnpm docker:infra
# 6. Run migrations
pnpm --filter @tennis/backend run db:migrate
Option B: Abandon and Remove
# From main repo directory
cd /path/to/main/repo
# 1. Remove worktree (even if dirty)
git worktree remove ~/claude-worktrees/tennis-team/my-old-feature --force
# 2. Delete local branch
git branch -D worktree/my-old-feature
# 3. Delete remote branch if exists
git push origin --delete worktree/my-old-feature
# 4. Prune remote references
git fetch origin --prune
Workflow 4: Environment Synchronization
# Get main repo path
MAIN_REPO=/path/to/main/repo
# Copy environment files
cp $MAIN_REPO/.env .env
# Copy Claude settings
cp $MAIN_REPO/.claude/settings.local.json .claude/settings.local.json
What NOT to Sync:
node_modules/- Should be installed per worktreedist/,build/- Build artifacts are worktree-specific.pnpm-install.pid- Process-specific temporary files
Workflow 5: Safe Worktree Removal
Before Removing - Checklist:
cd ~/claude-worktrees/tennis-team/my-feature
# 1. Check if there are uncommitted changes
git status
# 2. Check if branch is pushed
git log origin/HEAD..HEAD
# Empty = all commits are pushed
# If unpushed commits:
git push origin HEAD
Removal Steps:
# From main repo (NOT from worktree directory)
cd /path/to/main/repo
# 1. Remove worktree
git worktree remove ~/claude-worktrees/tennis-team/my-feature
# If worktree is dirty:
git worktree remove ~/claude-worktrees/tennis-team/my-feature --force
# 2. Delete branch (if no longer needed)
git branch -D worktree/my-feature
# 3. Delete remote branch
git push origin --delete worktree/my-feature
# 4. Prune
git fetch origin --prune
git worktree prune
Conflict Resolution Patterns
1. Package Lock File Conflicts
# Accept theirs and regenerate (RECOMMENDED)
git checkout --theirs pnpm-lock.yaml
pnpm install
git add pnpm-lock.yaml
git commit --no-edit
2. .pnpm-install.pid Conflicts
# This file should NEVER be committed
rm -f .pnpm-install.pid
git add .pnpm-install.pid 2>/dev/null || true
3. Environment File Conflicts
# Keep your worktree's environment
git checkout --ours .env
git add .env
4. Build Artifact Conflicts
# Delete and rebuild
rm -rf apps/*/dist packages/*/dist
git add -A
pnpm turbo run build --force
TypeScript Module Resolution Errors After Merge
# Solution 1: Force Rebuild with Turbo
pnpm turbo run build --force
# Solution 2: Clean Install and Build
rm -rf node_modules
rm -rf apps/*/node_modules packages/*/node_modules
rm -rf apps/*/dist packages/*/dist
pnpm install
pnpm turbo run build --force
# Solution 3: Build Specific Package First
pnpm --filter @tennis/shared run build
pnpm turbo run build
Complete Merge Workflow Example
# 1. Pre-merge cleanup
rm -f .pnpm-install.pid
git stash push -m "WIP before merge" 2>/dev/null || true
# 2. Fetch and merge
git fetch origin main
git merge origin/main --no-edit
# 3. If conflicts occur:
# Handle lock file
if git diff --name-only --diff-filter=U | grep -q "pnpm-lock.yaml"; then
git checkout --theirs pnpm-lock.yaml
fi
# Handle .env (keep ours)
if git diff --name-only --diff-filter=U | grep -q ".env"; then
git checkout --ours .env
fi
# Remove temp files from conflicts
rm -f .pnpm-install.pid
git add pnpm-lock.yaml .env 2>/dev/null || true
git commit --no-edit 2>/dev/null || true
# 4. Reinstall and rebuild
pnpm install
pnpm turbo run build --force
# 5. Restore stashed changes
git stash pop 2>/dev/null || true
# 6. Verify
pnpm run typecheck
echo "Merge complete!"
Best Practices Summary
- Always remove
.pnpm-install.pidbefore merging - Use
git checkout --theirs pnpm-lock.yamlfor lock conflicts - Keep your
.envfile (usegit checkout --ours .env) - Run
pnpm turbo run build --forceafter every merge - Use
pnpm installbefore building (lock file may have changed) - Don't manually edit
pnpm-lock.yaml - Don't commit build artifacts (
dist/) - Don't skip the rebuild step after merging
Worktree Branch Naming Conventions
# Feature development
worktree/feature-name-<timestamp>
# Bug fixes
worktree/fix-bug-description-<timestamp>
# Environment-specific
worktree/staging-env-<timestamp>
Troubleshooting Common Issues
Issue: "fatal: 'branch' is already checked out"
# You can't checkout same branch in multiple worktrees
# Solution: Create new branch from it
git worktree add ~/worktrees/new -b new-branch existing-branch
Issue: Worktree directory deleted but git still tracks it
git worktree prune
Issue: Cannot remove worktree - "uncommitted changes"
git worktree remove ~/claude-worktrees/tennis-team/feature --force
Issue: Merge conflicts in multiple files
# Abort and rebase instead
git merge --abort
git fetch origin
git rebase origin/main
Cleanup
When done with a worktree:
- Push any unpushed commits
- Remove the worktree:
git worktree remove <path> - Delete the branch:
git branch -D <branch> - If isolated DB was used, drop it:
psql -h localhost -U postgres -c "DROP DATABASE tennis_worktree_<timestamp>;" - Prune:
git worktree prune && git fetch origin --prune