Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions plugins/compound-engineering/skills/git-worktree/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@ This skill provides a unified interface for managing Git worktrees across your d
- **Interactive confirmations** at each step
- **Automatic .gitignore management** for worktree directory
- **Automatic .env file copying** from main repo to new worktrees
- **Automatic dev tool trusting** for mise and direnv configs (safe: only unchanged configs)

## 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
2. Trusts dev tool configs (mise, direnv) so hooks and scripts work immediately
3. Ensures `.worktrees` is in `.gitignore`
4. Creates consistent directory structure

```bash
# ✅ CORRECT - Always use the script
Expand Down Expand Up @@ -95,7 +97,8 @@ bash ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh creat
2. Updates the base branch from remote
3. Creates new worktree and branch
4. **Copies all .env files from main repo** (.env, .env.local, .env.test, etc.)
5. Shows path for cd-ing to the worktree
5. **Trusts dev tool configs** (mise, direnv) if unchanged from base branch; flags modified configs for manual review
6. Shows path for cd-ing to the worktree

### `list` or `ls`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,95 @@ copy_env_files() {
echo -e " ${GREEN}✓ Copied $copied environment file(s)${NC}"
}

# Trust development tool configs in a new worktree.
# Worktrees get a new filesystem path that tools like mise and direnv
# have never seen. Without trusting, these tools block with interactive
# prompts or refuse to load configs, which breaks hooks and scripts.
#
# Safety: only auto-trusts configs that are unchanged from the default branch.
# Modified configs (e.g., from a PR) are flagged for manual review.
#
# Note: there is an inherent TOCTOU gap between the hash check and the trust
# command. Exploiting it requires local filesystem write access + timing,
# which is acceptable for single-user dev machines.
trust_dev_tools() {
local worktree_path="$1"
local base_ref="$2"
local trusted=0
local skipped=()

# mise: trust the specific config file if present and unchanged
if command -v mise &>/dev/null; then
for f in .mise.toml mise.toml .tool-versions; do
if [[ -f "$worktree_path/$f" ]]; then
if _config_unchanged "$f" "$base_ref" "$worktree_path"; then
if (cd "$worktree_path" && mise trust "$f" --quiet); then
trusted=$((trusted + 1))
else
echo -e " ${YELLOW}Warning: 'mise trust $f' failed -- run manually in $worktree_path${NC}"
fi
else
skipped+=("mise trust $f")
fi
break
fi
done
fi

# direnv: allow .envrc
if command -v direnv &>/dev/null; then
if [[ -f "$worktree_path/.envrc" ]]; then
if _config_unchanged ".envrc" "$base_ref" "$worktree_path"; then
if (cd "$worktree_path" && direnv allow); then
Comment thread
NimbleEngineer21 marked this conversation as resolved.
Outdated
trusted=$((trusted + 1))
else
echo -e " ${YELLOW}Warning: 'direnv allow' failed -- run manually in $worktree_path${NC}"
fi
else
skipped+=("direnv allow")
fi
fi
fi

if [[ $trusted -gt 0 ]]; then
echo -e " ${GREEN}✓ Trusted $trusted dev tool config(s)${NC}"
fi

if [[ ${#skipped[@]} -gt 0 ]]; then
echo -e " ${YELLOW}Skipped auto-trust for modified config(s):${NC}"
for item in "${skipped[@]}"; do
echo -e " - $item"
done
local joined
joined=$(printf ' && %s' "${skipped[@]}")
echo -e " ${BLUE}Review the diff, then run manually: cd $worktree_path${joined}${NC}"
fi
}

# Check if a config file is unchanged from the base branch.
# Returns 0 (true) if the file is identical to the base branch version.
# Returns 1 (false) if the file was added or modified by this branch.
#
# Note: git hash-object on a file path applies gitattributes filters (e.g.,
# line-ending normalization) while git show pipes raw bytes. A mismatch
# would cause a false negative (trust skipped), which is the safe direction.
_config_unchanged() {
local file="$1"
local base_ref="$2"
local worktree_path="$3"

# Get the blob hash directly from git's object database. This avoids
# content round-tripping through shell variables (which strips trailing
# newlines) and pipefail issues with git show | git hash-object.
local base_hash
base_hash=$(git rev-parse "$base_ref:$file" 2>/dev/null) || return 1

local worktree_hash
worktree_hash=$(git hash-object "$worktree_path/$file")

[[ "$base_hash" == "$worktree_hash" ]]
}

# Create a new worktree
create_worktree() {
local branch_name="$1"
Expand Down Expand Up @@ -107,6 +196,23 @@ create_worktree() {
# Copy environment files
copy_env_files "$worktree_path"

# Trust dev tool configs (mise, direnv) so hooks and scripts work immediately.
# Compare against the default branch (not from_branch) so that passing a PR
# branch as from_branch doesn't bypass the safety check.
local default_branch
default_branch=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||')
default_branch="${default_branch:-main}"
# Ensure the ref is fresh -- create_worktree only fetches from_branch
if ! git fetch origin "$default_branch" --quiet 2>/dev/null; then
echo -e " ${YELLOW}Warning: could not fetch origin/$default_branch -- trust check may use stale data${NC}"
fi
# Skip trust entirely if the ref doesn't exist locally (no baseline to compare)
if git rev-parse --verify "origin/$default_branch" &>/dev/null; then
trust_dev_tools "$worktree_path" "origin/$default_branch"
else
echo -e " ${YELLOW}Skipping dev tool trust -- origin/$default_branch not found locally${NC}"
fi

echo -e "${GREEN}✓ Worktree created successfully!${NC}"
echo ""
echo "To switch to this worktree:"
Expand Down Expand Up @@ -321,6 +427,13 @@ Environment Files:
- Creates .backup files if destination already exists
- Use 'copy-env' to refresh env files after main repo changes

Dev Tool Trust:
- Trusts mise config (.mise.toml, mise.toml, .tool-versions) and direnv (.envrc)
- Only auto-trusts configs unchanged from the base branch
- Modified configs are flagged for manual review (safety for PR reviews)
- Only runs if the tool is installed and config exists
- Prevents hooks/scripts from hanging on interactive trust prompts

Examples:
worktree-manager.sh create feature-login
worktree-manager.sh create feature-auth develop
Expand Down