| 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:
pnpm install
pnpm docker:infra
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
pnpm docker:infra
pnpm docker:dev
docker compose -f docker/docker-compose.yml ps
Verifying Services
psql -h localhost -U postgres -c "SELECT 1;"
redis-cli ping
Troubleshooting Docker
docker compose -f docker/docker-compose.yml logs postgres
docker compose -f docker/docker-compose.yml logs redis
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.
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:
.claude/skills/claude-worktree-manager/scripts/worktree.sh create my-feature --isolated
This automatically:
- Creates a new PostgreSQL database:
tennis_worktree_<timestamp>
- Updates your
.env with the new DATABASE_URL
- Runs all migrations via
pnpm --filter @tennis/backend run db:migrate
Manual Database Operations
pnpm --filter @tennis/backend run db:migrate
psql -h localhost -U postgres -d tennis_dev
psql -h localhost -U postgres -c "\l"
Isolated DB Cleanup
psql -h localhost -U postgres -c "SELECT datname FROM pg_database WHERE datname LIKE 'tennis_worktree_%';"
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:
redis-cli ping
redis-cli FLUSHALL
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"
Tennis-Team Dev Workflow
Starting Development
pnpm docker:infra
pnpm dev
pnpm --filter @tennis/backend run dev
pnpm --filter @tennis/frontend run dev
Common Commands (pnpm + turbo)
Building
pnpm run build
pnpm --filter @tennis/backend run build
pnpm --filter @tennis/shared run build
pnpm turbo run build
pnpm turbo run build --force
Testing
pnpm test
pnpm --filter @tennis/backend run test
pnpm turbo run test
Development
pnpm run dev
pnpm run lint
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)
pnpm add -w typescript
pnpm add -D -w eslint
Pattern 2: Package-Specific Dependencies
pnpm --filter @tennis/backend add express
pnpm --filter @tennis/backend add -D jest
Pattern 3: Workspace Protocol Dependencies
{
"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.yaml to git
- Never manually edit lock file
- Run
pnpm install after pulling changes
- Don't ignore lock file in
.gitignore
Handling Lock File Conflicts
git checkout --theirs pnpm-lock.yaml
pnpm install
git add pnpm-lock.yaml
git commit --no-edit
Common pnpm Issues in Worktrees
Issue 1: .pnpm-install.pid Blocking Operations
rm -f .pnpm-install.pid
lsof .pnpm-install.pid
kill <PID>
rm .pnpm-install.pid
Issue 2: node_modules Symlink Confusion
ls -la node_modules/@tennis/shared
Issue 3: Workspace Dependencies Not Updating
pnpm --filter @tennis/shared run build
pnpm turbo run build --force
Issue 4: Different pnpm Versions
cat package.json | jq .packageManager
npm install -g pnpm@9.15.4
corepack enable
corepack prepare pnpm@9.15.4 --activate
Turbo Build Caching
Turbo in Worktrees
Issue: Turbo cache is worktree-local
export TURBO_CACHE_DIR=~/.turbo-cache
Cache Invalidation
pnpm turbo run build --force
rm -rf node_modules/.cache/turbo
Debugging Turbo
pnpm turbo run build --dry-run
pnpm turbo run build --verbose
pnpm turbo run build --summarize
pnpm Commands Reference
Installation
pnpm install
pnpm install --frozen-lockfile
pnpm install --force
Adding Dependencies
pnpm add -w <package>
pnpm --filter <package-name> add <dependency>
pnpm add react@^18.0.0
Removing Dependencies
pnpm --filter <package-name> remove <dependency>
pnpm remove -w <package>
Workspace Commands
pnpm -r run build
pnpm --filter @tennis/backend run test
pnpm --filter "./apps/*" run start
pnpm --filter @tennis/frontend... run build
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
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)
cd ~/claude-worktrees/tennis-team/my-feature-1234567
git push -u origin HEAD
gh pr create \
--base main \
--title "feat: my feature" \
--body "Summary of changes"
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
cd ~/claude-worktrees/tennis-team/my-feature-1234567
git stash push -m "WIP: before sync"
git fetch origin main
git rebase origin/main
git stash pop
pnpm install
pnpm run build
Workflow 3: Handling Stale Worktrees
Option A: Update and Continue Working
cd ~/claude-worktrees/tennis-team/my-old-feature
git fetch origin --prune
git rebase origin/main
pnpm install
pnpm turbo run build --force
pnpm docker:infra
pnpm --filter @tennis/backend run db:migrate
Option B: Abandon and Remove
cd /path/to/main/repo
git worktree remove ~/claude-worktrees/tennis-team/my-old-feature --force
git branch -D worktree/my-old-feature
git push origin --delete worktree/my-old-feature
git fetch origin --prune
Workflow 4: Environment Synchronization
MAIN_REPO=/path/to/main/repo
cp $MAIN_REPO/.env .env
cp $MAIN_REPO/.claude/settings.local.json .claude/settings.local.json
What NOT to Sync:
node_modules/ - Should be installed per worktree
dist/, 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
git status
git log origin/HEAD..HEAD
git push origin HEAD
Removal Steps:
cd /path/to/main/repo
git worktree remove ~/claude-worktrees/tennis-team/my-feature
git worktree remove ~/claude-worktrees/tennis-team/my-feature --force
git branch -D worktree/my-feature
git push origin --delete worktree/my-feature
git fetch origin --prune
git worktree prune
Conflict Resolution Patterns
1. Package Lock File Conflicts
git checkout --theirs pnpm-lock.yaml
pnpm install
git add pnpm-lock.yaml
git commit --no-edit
2. .pnpm-install.pid Conflicts
rm -f .pnpm-install.pid
git add .pnpm-install.pid 2>/dev/null || true
3. Environment File Conflicts
git checkout --ours .env
git add .env
4. Build Artifact Conflicts
rm -rf apps/*/dist packages/*/dist
git add -A
pnpm turbo run build --force
TypeScript Module Resolution Errors After Merge
pnpm turbo run build --force
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
pnpm --filter @tennis/shared run build
pnpm turbo run build
Complete Merge Workflow Example
rm -f .pnpm-install.pid
git stash push -m "WIP before merge" 2>/dev/null || true
git fetch origin main
git merge origin/main --no-edit
if git diff --name-only --diff-filter=U | grep -q "pnpm-lock.yaml"; then
git checkout --theirs pnpm-lock.yaml
fi
if git diff --name-only --diff-filter=U | grep -q ".env"; then
git checkout --ours .env
fi
rm -f .pnpm-install.pid
git add pnpm-lock.yaml .env 2>/dev/null || true
git commit --no-edit 2>/dev/null || true
pnpm install
pnpm turbo run build --force
git stash pop 2>/dev/null || true
pnpm run typecheck
echo "Merge complete!"
Best Practices Summary
- Always remove
.pnpm-install.pid before merging
- Use
git checkout --theirs pnpm-lock.yaml for lock conflicts
- Keep your
.env file (use git checkout --ours .env)
- Run
pnpm turbo run build --force after every merge
- Use
pnpm install before 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
worktree/feature-name-<timestamp>
worktree/fix-bug-description-<timestamp>
worktree/staging-env-<timestamp>
Troubleshooting Common Issues
Issue: "fatal: 'branch' is already checked out"
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
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