Manage git worktrees for isolated feature development - create after specify, list active worktrees, cleanup merged branches
From spexnpx claudepluginhub rhuss/cc-spex --plugin spexThis skill uses the workspace's default tool permissions.
This skill manages git worktrees to isolate feature development. It supports three actions:
worktrees trait overlay after speckit.specify completes. Creates a worktree, restores main, and prints switch instructions.Determine the action from context:
speckit.specify overlay (post-specify context), the action is create.cleanup, the action is cleanup.list, or invoked directly), the action is list.The project must be a git repository.
git rev-parse --git-dir >/dev/null 2>&1 || { echo "ERROR: Not a git repository"; exit 1; }
This action runs after speckit.specify has created a feature branch and spec files.
Read base_path from .specify/spex-traits.json:
BASE_PATH=$(jq -r '.worktrees_config.base_path // ".."' .specify/spex-traits.json 2>/dev/null)
Default: .. (sibling directory to the repo root).
BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
Verify it matches the NNN-feature-name pattern. If not, warn that worktree creation only applies to feature branches and skip.
A git worktree has a .git file (not directory) pointing to the main repo. Detect this:
REPO_ROOT=$(git rev-parse --show-toplevel)
GIT_DIR=$(git rev-parse --git-dir)
# If git-dir is not <repo>/.git, we're inside a worktree
if [ "$GIT_DIR" != "$REPO_ROOT/.git" ] && [ "$GIT_DIR" != ".git" ]; then
echo "WARNING: Already inside a git worktree. Skipping worktree creation."
echo "Worktree nesting is not supported."
# Skip worktree creation but continue with the rest of the specify flow
fi
If inside a worktree, skip the entire create action (FR-009).
WORKTREE_PATH="$REPO_ROOT/$BASE_PATH/$BRANCH_NAME"
Check if the target path already exists (FR-008):
if [ -d "$WORKTREE_PATH" ] || [ -f "$WORKTREE_PATH" ]; then
echo "ERROR: Target path already exists: $WORKTREE_PATH"
echo "Remove it manually or choose a different base_path in .specify/spex-traits.json"
# Stop worktree creation, but don't fail the entire specify flow
fi
Before switching away from the feature branch, commit any spec files that speckit.specify created. Without this, the files would remain as untracked artifacts in the main worktree and would not appear in the feature worktree.
# Check for uncommitted spec files in the feature's spec directory
SPEC_DIR="specs/$BRANCH_NAME"
if [ -d "$SPEC_DIR" ]; then
UNTRACKED=$(git status --porcelain "$SPEC_DIR" 2>/dev/null)
if [ -n "$UNTRACKED" ]; then
git add "$SPEC_DIR"
git commit -m "feat: Add spec for $BRANCH_NAME
Assisted-By: ๐ค Claude Code"
fi
fi
This ensures the spec files are persisted on the feature branch before the worktree is created from it.
Git does not allow two worktrees to have the same branch checked out. Since speckit.specify just created and checked out the feature branch, we must switch back to main before creating a worktree for that branch.
if ! git checkout main 2>&1; then
echo "WARNING: Could not switch back to main."
echo "You likely have uncommitted changes. Commit or stash them first."
echo "The repository remains on branch $BRANCH_NAME."
echo "Worktree creation skipped (cannot create worktree while branch is checked out here)."
# Stop here - worktree creation is not possible without switching branches first
fi
Now that the current worktree is on main, create a new worktree for the feature branch:
git worktree add "$WORKTREE_PATH" "$BRANCH_NAME"
If this fails (disk full, permission denied, etc.), report the error clearly. The original repo is already back on main:
if ! git worktree add "$WORKTREE_PATH" "$BRANCH_NAME" 2>&1; then
echo "ERROR: Failed to create worktree at $WORKTREE_PATH"
echo "The repository is on main. The feature branch $BRANCH_NAME still exists."
echo "Resolve the issue and retry, or switch to the branch manually: git checkout $BRANCH_NAME"
# Stop here
fi
Print clear instructions for the user (FR-004):
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Worktree created at <worktree-path> โ
โ โ
โ To continue with planning/implementation: โ
โ cd <worktree-path> && claude โ
โ โ
โ In the new session, run /spex:init to set up spec-kit โ
โ commands and spex traits in the worktree. โ
โ โ
โ The spec file contains all context from this session. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Show all active feature worktrees for the project (FR-005).
git worktree list --porcelain
Parse the output. Each worktree entry has:
worktree <path>HEAD <commit>branch refs/heads/<branch-name>Only show worktrees whose branch matches the NNN-* feature branch pattern (three-digit prefix followed by a hyphen).
Skip the main worktree (the original repo).
Display a table:
Active Feature Worktrees:
Path Branch Feature
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
../004-user-auth 004-user-auth user-auth
../007-worktrees-trait 007-worktrees-trait worktrees-trait
If no feature worktrees exist:
No active feature worktrees found.
Create one by running /speckit.specify with the worktrees trait enabled.
Detect worktrees whose branches are merged and offer removal (FR-006, FR-007).
# Get all branches merged into main
MERGED_BRANCHES=$(git branch --merged main | sed 's/^[* ]*//' | grep -E '^[0-9]{3}-')
For each worktree with a feature branch, check if its branch appears in the merged list.
For each merged worktree, present it to the user and ask for confirmation:
Worktree ../004-user-auth (branch 004-user-auth) is merged into main.
Remove this worktree? (yes/no)
If the user confirms, first switch to the main repo root (to avoid cwd pointing at the deleted directory), then remove the worktree:
# Switch cwd to the main worktree BEFORE removing the feature worktree.
# If cwd is inside the worktree being removed, all subsequent commands will
# fail with "Path does not exist" because the Bash tool persists cwd.
MAIN_WORKTREE=$(git worktree list --porcelain | head -1 | sed 's/^worktree //')
cd "$MAIN_WORKTREE"
git worktree remove <path>
git branch -d <branch-name>
For worktrees with unmerged branches, warn the user (FR-007):
Worktree ../007-worktrees-trait (branch 007-worktrees-trait) has NOT been merged.
Skipping. Use --force to remove unmerged worktrees (data may be lost).
Only remove unmerged worktrees if the user explicitly confirms after seeing the warning.