fix(git-worktree): auto-copy .env files when creating worktrees
Problem:
When Claude creates worktrees, it sometimes calls `git worktree add` directly
instead of using the worktree-manager.sh script. This means .env files don't
get copied to the new worktree, causing the app to fail on startup.
Solution:
1. Add copy_env_files() function to worktree-manager.sh that copies all .env*
files (except .env.example) from main repo to new worktree
2. Call copy_env_files() automatically during worktree creation
3. Add new 'copy-env' command to manually copy env files to existing worktrees
4. Update SKILL.md with CRITICAL section instructing Claude to NEVER call
git worktree add directly - always use the manager script
5. Update all code examples to use ${CLAUDE_PLUGIN_ROOT} for portability
6. Add troubleshooting section for missing .env files
Features:
- Automatically copies .env, .env.local, .env.test, etc.
- Skips .env.example (should be in git)
- Creates .backup if destination already exists
- New 'copy-env' command for manual copying to existing worktrees
This commit is contained in:
@@ -15,6 +15,24 @@ This skill provides a unified interface for managing Git worktrees across your d
|
||||
- **Clean up completed worktrees** automatically
|
||||
- **Interactive confirmations** at each step
|
||||
- **Automatic .gitignore management** for worktree directory
|
||||
- **Automatic .env file copying** from main repo to new worktrees
|
||||
|
||||
## CRITICAL: Always Use the Manager Script
|
||||
|
||||
**NEVER call `git worktree add` directly.** Always use the `worktree-manager.sh` script.
|
||||
|
||||
The script handles critical setup that raw git commands don't:
|
||||
1. Copies `.env`, `.env.local`, `.env.test`, etc. from main repo
|
||||
2. Ensures `.worktrees` is in `.gitignore`
|
||||
3. Creates consistent directory structure
|
||||
|
||||
```bash
|
||||
# ✅ CORRECT - Always use the script
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh create feature-name
|
||||
|
||||
# ❌ WRONG - Never do this directly
|
||||
git worktree add .worktrees/feature-name -b feature-name main
|
||||
```
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
@@ -41,17 +59,20 @@ The skill is automatically called from `/workflows:review` and `/workflows:work`
|
||||
You can also invoke the skill directly from bash:
|
||||
|
||||
```bash
|
||||
# Create a new worktree
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh create feature-login
|
||||
# Create a new worktree (copies .env files automatically)
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh create feature-login
|
||||
|
||||
# List all worktrees
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh list
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh list
|
||||
|
||||
# Switch to a worktree
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh switch feature-login
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh switch feature-login
|
||||
|
||||
# Copy .env files to an existing worktree (if they weren't copied)
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh copy-env feature-login
|
||||
|
||||
# Clean up completed worktrees
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh cleanup
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh cleanup
|
||||
```
|
||||
|
||||
## Commands
|
||||
@@ -66,14 +87,15 @@ Creates a new worktree with the given branch name.
|
||||
|
||||
**Example:**
|
||||
```bash
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh create feature-login
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh create feature-login
|
||||
```
|
||||
|
||||
**What happens:**
|
||||
1. Checks if worktree already exists
|
||||
2. Updates the base branch from remote
|
||||
3. Creates new worktree and branch
|
||||
4. Shows path for cd-ing to the worktree
|
||||
4. **Copies all .env files from main repo** (.env, .env.local, .env.test, etc.)
|
||||
5. Shows path for cd-ing to the worktree
|
||||
|
||||
### `list` or `ls`
|
||||
|
||||
@@ -81,7 +103,7 @@ Lists all available worktrees with their branches and current status.
|
||||
|
||||
**Example:**
|
||||
```bash
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh list
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh list
|
||||
```
|
||||
|
||||
**Output shows:**
|
||||
@@ -96,7 +118,7 @@ Switches to an existing worktree and cd's into it.
|
||||
|
||||
**Example:**
|
||||
```bash
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh switch feature-login
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh switch feature-login
|
||||
```
|
||||
|
||||
**Optional:**
|
||||
@@ -108,7 +130,7 @@ Interactively cleans up inactive worktrees with confirmation.
|
||||
|
||||
**Example:**
|
||||
```bash
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh cleanup
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh cleanup
|
||||
```
|
||||
|
||||
**What happens:**
|
||||
@@ -126,35 +148,35 @@ bash .claude/skills/git-worktree/scripts/worktree-manager.sh cleanup
|
||||
# Offers: "Use worktree for isolated review? (y/n)"
|
||||
|
||||
# You respond: yes
|
||||
# Script runs:
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh create pr-123-feature-name
|
||||
# Script runs (copies .env files automatically):
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh create pr-123-feature-name
|
||||
|
||||
# You're now in isolated worktree for review
|
||||
# You're now in isolated worktree for review with all env vars
|
||||
cd .worktrees/pr-123-feature-name
|
||||
|
||||
# After review, return to main:
|
||||
cd ../..
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh cleanup
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh cleanup
|
||||
```
|
||||
|
||||
### Parallel Feature Development
|
||||
|
||||
```bash
|
||||
# For first feature:
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh create feature-login
|
||||
# For first feature (copies .env files):
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh create feature-login
|
||||
|
||||
# Later, start second feature:
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh create feature-notifications
|
||||
# Later, start second feature (also copies .env files):
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh create feature-notifications
|
||||
|
||||
# List what you have:
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh list
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh list
|
||||
|
||||
# Switch between them as needed:
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh switch feature-login
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh switch feature-login
|
||||
|
||||
# Return to main and cleanup when done:
|
||||
cd .
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh cleanup
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh cleanup
|
||||
```
|
||||
|
||||
## Key Design Principles
|
||||
@@ -216,11 +238,11 @@ If you see this, the script will ask if you want to switch to it instead.
|
||||
|
||||
### "Cannot remove worktree: it is the current worktree"
|
||||
|
||||
Switch out of the worktree first, then cleanup:
|
||||
Switch out of the worktree first (to main repo), then cleanup:
|
||||
|
||||
```bash
|
||||
cd /Users/kieranklaassen/rails/cora
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh cleanup
|
||||
cd $(git rev-parse --show-toplevel)
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh cleanup
|
||||
```
|
||||
|
||||
### Lost in a worktree?
|
||||
@@ -228,7 +250,15 @@ bash .claude/skills/git-worktree/scripts/worktree-manager.sh cleanup
|
||||
See where you are:
|
||||
|
||||
```bash
|
||||
bash .claude/skills/git-worktree/scripts/worktree-manager.sh list
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh list
|
||||
```
|
||||
|
||||
### .env files missing in worktree?
|
||||
|
||||
If a worktree was created without .env files (e.g., via raw `git worktree add`), copy them:
|
||||
|
||||
```bash
|
||||
bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh copy-env feature-name
|
||||
```
|
||||
|
||||
Navigate back to main:
|
||||
|
||||
@@ -24,6 +24,47 @@ ensure_gitignore() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Copy .env files from main repo to worktree
|
||||
copy_env_files() {
|
||||
local worktree_path="$1"
|
||||
|
||||
echo -e "${BLUE}Copying environment files...${NC}"
|
||||
|
||||
# Find all .env* files in root (excluding .env.example which should be in git)
|
||||
local env_files=()
|
||||
for f in "$GIT_ROOT"/.env*; do
|
||||
if [[ -f "$f" ]]; then
|
||||
local basename=$(basename "$f")
|
||||
# Skip .env.example (that's typically committed to git)
|
||||
if [[ "$basename" != ".env.example" ]]; then
|
||||
env_files+=("$basename")
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${#env_files[@]} -eq 0 ]]; then
|
||||
echo -e " ${YELLOW}ℹ️ No .env files found in main repository${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
local copied=0
|
||||
for env_file in "${env_files[@]}"; do
|
||||
local source="$GIT_ROOT/$env_file"
|
||||
local dest="$worktree_path/$env_file"
|
||||
|
||||
if [[ -f "$dest" ]]; then
|
||||
echo -e " ${YELLOW}⚠️ $env_file already exists, backing up to ${env_file}.backup${NC}"
|
||||
cp "$dest" "${dest}.backup"
|
||||
fi
|
||||
|
||||
cp "$source" "$dest"
|
||||
echo -e " ${GREEN}✓ Copied $env_file${NC}"
|
||||
copied=$((copied + 1))
|
||||
done
|
||||
|
||||
echo -e " ${GREEN}✓ Copied $copied environment file(s)${NC}"
|
||||
}
|
||||
|
||||
# Create a new worktree
|
||||
create_worktree() {
|
||||
local branch_name="$1"
|
||||
@@ -71,6 +112,9 @@ create_worktree() {
|
||||
echo -e "${BLUE}Creating worktree...${NC}"
|
||||
git worktree add -b "$branch_name" "$worktree_path" "$from_branch"
|
||||
|
||||
# Copy environment files
|
||||
copy_env_files "$worktree_path"
|
||||
|
||||
echo -e "${GREEN}✓ Worktree created successfully!${NC}"
|
||||
echo ""
|
||||
echo "To switch to this worktree:"
|
||||
@@ -141,6 +185,38 @@ switch_worktree() {
|
||||
echo -e "${BLUE}Now in: $(pwd)${NC}"
|
||||
}
|
||||
|
||||
# Copy env files to an existing worktree (or current directory if in a worktree)
|
||||
copy_env_to_worktree() {
|
||||
local worktree_name="$1"
|
||||
local worktree_path
|
||||
|
||||
if [[ -z "$worktree_name" ]]; then
|
||||
# Check if we're currently in a worktree
|
||||
local current_dir=$(pwd)
|
||||
if [[ "$current_dir" == "$WORKTREE_DIR"/* ]]; then
|
||||
worktree_path="$current_dir"
|
||||
worktree_name=$(basename "$worktree_path")
|
||||
echo -e "${BLUE}Detected current worktree: $worktree_name${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}Usage: worktree-manager.sh copy-env [worktree-name]${NC}"
|
||||
echo "Or run from within a worktree to copy to current directory"
|
||||
list_worktrees
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
worktree_path="$WORKTREE_DIR/$worktree_name"
|
||||
|
||||
if [[ ! -d "$worktree_path" ]]; then
|
||||
echo -e "${RED}Error: Worktree not found: $worktree_name${NC}"
|
||||
list_worktrees
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
copy_env_files "$worktree_path"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Clean up completed worktrees
|
||||
cleanup_worktrees() {
|
||||
if [[ ! -d "$WORKTREE_DIR" ]]; then
|
||||
@@ -213,6 +289,9 @@ main() {
|
||||
switch|go)
|
||||
switch_worktree "$2"
|
||||
;;
|
||||
copy-env|env)
|
||||
copy_env_to_worktree "$2"
|
||||
;;
|
||||
cleanup|clean)
|
||||
cleanup_worktrees
|
||||
;;
|
||||
@@ -235,16 +314,27 @@ Git Worktree Manager
|
||||
Usage: worktree-manager.sh <command> [options]
|
||||
|
||||
Commands:
|
||||
create <branch-name> [from-branch] Create new worktree
|
||||
create <branch-name> [from-branch] Create new worktree (copies .env files automatically)
|
||||
(from-branch defaults to main)
|
||||
list | ls List all worktrees
|
||||
switch | go [name] Switch to worktree
|
||||
copy-env | env [name] Copy .env files from main repo to worktree
|
||||
(if name omitted, uses current worktree)
|
||||
cleanup | clean Clean up inactive worktrees
|
||||
help Show this help message
|
||||
|
||||
Environment Files:
|
||||
- Automatically copies .env, .env.local, .env.test, etc. on create
|
||||
- Skips .env.example (should be in git)
|
||||
- Creates .backup files if destination already exists
|
||||
- Use 'copy-env' to refresh env files after main repo changes
|
||||
|
||||
Examples:
|
||||
worktree-manager.sh create feature-login
|
||||
worktree-manager.sh create feature-auth develop
|
||||
worktree-manager.sh switch feature-login
|
||||
worktree-manager.sh copy-env feature-login
|
||||
worktree-manager.sh copy-env # copies to current worktree
|
||||
worktree-manager.sh cleanup
|
||||
worktree-manager.sh list
|
||||
|
||||
|
||||
Reference in New Issue
Block a user