#!/bin/bash # Git Worktree Batch Setup Script # Generated by git-worktree-setup skill # # This script automates the creation of multiple git worktrees with parallel dependency installation. # # Usage: # ./batch-setup.sh branch1 branch2 branch3 [--no-install] [--pattern=/path/{branch}] set -euo pipefail # ============================================================================ # Configuration # ============================================================================ BRANCHES=() SKIP_INSTALL=false PATH_PATTERN="" # Parse arguments for arg in "$@"; do case $arg in --no-install) SKIP_INSTALL=true ;; --pattern=*) PATH_PATTERN="${arg#*=}" ;; *) BRANCHES+=("$arg") ;; esac done # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # ============================================================================ # Helper Functions # ============================================================================ print_success() { echo -e "${GREEN}✓${NC} $1" } print_error() { echo -e "${RED}✗${NC} $1" >&2 } print_warning() { echo -e "${YELLOW}⚠${NC} $1" } print_info() { echo -e "${BLUE}ℹ${NC} $1" } print_header() { echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "$1" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" } # ============================================================================ # Prerequisite Checks # ============================================================================ check_prerequisites() { print_header "Checking Prerequisites" # Check if in git repository if ! git rev-parse --is-inside-work-tree &>/dev/null; then print_error "Not in a git repository" exit 1 fi print_success "Git repository detected" # Get repository info REPO_NAME=$(basename "$(git rev-parse --show-toplevel)") REPO_ROOT=$(git rev-parse --show-toplevel) CURRENT_BRANCH=$(git branch --show-current) print_info "Repository: $REPO_NAME" print_info "Current branch: $CURRENT_BRANCH" # Check for branch names if [ ${#BRANCHES[@]} -eq 0 ]; then print_error "No branch names provided" echo "Usage: $0 branch1 branch2 branch3 [--no-install] [--pattern=/path/{branch}]" exit 1 fi print_info "Branches to create: ${#BRANCHES[@]}" for branch in "${BRANCHES[@]}"; do echo " - $branch" done } validate_branches() { print_header "Validating Branches" declare -gA BRANCH_TYPES declare -gA WORKTREE_PATHS for branch in "${BRANCHES[@]}"; do # Check if branch exists if git show-ref --verify "refs/heads/$branch" &>/dev/null; then BRANCH_TYPES[$branch]="existing" print_info "$branch: existing branch" elif git show-ref --verify "refs/remotes/origin/$branch" &>/dev/null; then BRANCH_TYPES[$branch]="remote" print_info "$branch: exists on remote" else BRANCH_TYPES[$branch]="new" print_info "$branch: will create new branch" fi # Determine worktree path if [ -n "$PATH_PATTERN" ]; then # Use custom pattern WORKTREE_PATHS[$branch]="${PATH_PATTERN//\{branch\}/$branch}" else # Use default pattern WORKTREE_PATHS[$branch]="$(dirname "$REPO_ROOT")/$REPO_NAME-$branch" fi echo " → ${WORKTREE_PATHS[$branch]}" done } check_directory_conflicts() { print_header "Checking for Directory Conflicts" CONFLICTS=() for branch in "${BRANCHES[@]}"; do path="${WORKTREE_PATHS[$branch]}" if [ -d "$path" ]; then CONFLICTS+=("$branch → $path") fi done if [ ${#CONFLICTS[@]} -gt 0 ]; then print_warning "Found ${#CONFLICTS[@]} directory conflicts:" for conflict in "${CONFLICTS[@]}"; do echo " $conflict" done echo "" echo "Options:" echo " 1. Skip conflicting worktrees" echo " 2. Remove and recreate" echo " 3. Abort" read -p "Choose (1/2/3): " -r choice case $choice in 1) print_info "Will skip conflicting directories" for conflict in "${CONFLICTS[@]}"; do branch="${conflict%% →*}" # Remove from BRANCHES array BRANCHES=("${BRANCHES[@]/$branch}") done # Remove empty elements BRANCHES=("${BRANCHES[@]}") ;; 2) print_warning "Removing conflicting directories..." for conflict in "${CONFLICTS[@]}"; do path="${conflict##*→ }" rm -rf "$path" print_success "Removed: $path" done ;; 3) print_info "Aborted by user" exit 0 ;; esac else print_success "No directory conflicts" fi } # ============================================================================ # Worktree Creation # ============================================================================ create_worktrees() { print_header "Creating Worktrees" declare -gA CREATED_WORKTREES declare -ga FAILED_WORKTREES local total=${#BRANCHES[@]} local current=0 for branch in "${BRANCHES[@]}"; do ((current++)) echo "" print_info "[$current/$total] Creating worktree for $branch..." path="${WORKTREE_PATHS[$branch]}" branch_type="${BRANCH_TYPES[$branch]}" case $branch_type in new) if git worktree add "$path" -b "$branch" 2>&1; then CREATED_WORKTREES[$branch]="$path" print_success "$branch: Created with new branch" else FAILED_WORKTREES+=("$branch") print_error "$branch: Failed to create" fi ;; existing) if git worktree add "$path" "$branch" 2>&1; then CREATED_WORKTREES[$branch]="$path" print_success "$branch: Created from existing branch" else FAILED_WORKTREES+=("$branch") print_error "$branch: Failed to create" fi ;; remote) if git worktree add "$path" -b "$branch" --track "origin/$branch" 2>&1; then CREATED_WORKTREES[$branch]="$path" print_success "$branch: Created tracking remote" else FAILED_WORKTREES+=("$branch") print_error "$branch: Failed to create" fi ;; esac done echo "" print_header "Worktree Creation Summary" print_success "Created: ${#CREATED_WORKTREES[@]}/$total worktrees" if [ ${#FAILED_WORKTREES[@]} -gt 0 ]; then print_error "Failed: ${#FAILED_WORKTREES[@]} worktrees" for failed in "${FAILED_WORKTREES[@]}"; do echo " - $failed" done fi } # ============================================================================ # Development Environment Setup # ============================================================================ detect_package_manager() { cd "$REPO_ROOT" if [ -f "pnpm-lock.yaml" ]; then PKG_MANAGER="pnpm" INSTALL_CMD="pnpm install" elif [ -f "yarn.lock" ]; then PKG_MANAGER="yarn" INSTALL_CMD="yarn install" elif [ -f "bun.lockb" ]; then PKG_MANAGER="bun" INSTALL_CMD="bun install" elif [ -f "package-lock.json" ]; then PKG_MANAGER="npm" INSTALL_CMD="npm install" elif [ -f "package.json" ]; then PKG_MANAGER="npm" INSTALL_CMD="npm install" else PKG_MANAGER="none" INSTALL_CMD="" fi if [ "$PKG_MANAGER" != "none" ]; then print_info "Using $PKG_MANAGER for all worktrees" fi } install_dependencies() { if [ "$SKIP_INSTALL" = true ]; then print_info "Skipping dependency installation (--no-install flag)" return 0 fi if [ "$PKG_MANAGER" = "none" ]; then print_info "No package.json found, skipping dependency installation" return 0 fi if [ ${#CREATED_WORKTREES[@]} -eq 0 ]; then print_warning "No worktrees created, skipping dependency installation" return 0 fi print_header "Installing Dependencies (Parallel)" declare -gA INSTALL_SUCCESS declare -gA INSTALL_FAILED declare -A INSTALL_PIDS # Start installations in parallel for branch in "${!CREATED_WORKTREES[@]}"; do path="${CREATED_WORKTREES[$branch]}" print_info "Starting installation in $branch..." # Run in background ( cd "$path" $INSTALL_CMD > "/tmp/install-$branch.log" 2>&1 ) & INSTALL_PIDS[$branch]=$! done # Wait for all installations for branch in "${!INSTALL_PIDS[@]}"; do pid=${INSTALL_PIDS[$branch]} print_info "Waiting for $branch (PID: $pid)..." if wait "$pid"; then INSTALL_SUCCESS[$branch]=true print_success "$branch: Dependencies installed" else INSTALL_FAILED[$branch]=true print_error "$branch: Installation failed (see /tmp/install-$branch.log)" fi done echo "" print_header "Installation Summary" print_success "Successful: ${#INSTALL_SUCCESS[@]}/${#CREATED_WORKTREES[@]}" if [ ${#INSTALL_FAILED[@]} -gt 0 ]; then print_warning "Failed: ${#INSTALL_FAILED[@]}" for branch in "${!INSTALL_FAILED[@]}"; do path="${CREATED_WORKTREES[$branch]}" echo " - $branch (manually run: cd $path && $INSTALL_CMD)" done fi } # ============================================================================ # Summary and Next Steps # ============================================================================ print_final_summary() { print_header "Batch Worktree Creation Complete" echo "Created: ${#CREATED_WORKTREES[@]}/${#BRANCHES[@]} worktrees" if [ ${#FAILED_WORKTREES[@]} -gt 0 ]; then echo "Failed: ${#FAILED_WORKTREES[@]}/${#BRANCHES[@]} worktrees" fi echo "" if [ ${#CREATED_WORKTREES[@]} -gt 0 ]; then echo "Successful worktrees:" for branch in "${!CREATED_WORKTREES[@]}"; do path="${CREATED_WORKTREES[$branch]}" branch_type="${BRANCH_TYPES[$branch]}" print_success "$branch → $path ($branch_type)" done fi echo "" if [ ${#FAILED_WORKTREES[@]} -gt 0 ]; then echo "Failed worktrees:" for branch in "${FAILED_WORKTREES[@]}"; do print_error "$branch" done echo "" fi print_header "Next Steps" echo "Start working on each worktree:" echo "" for branch in "${!CREATED_WORKTREES[@]}"; do path="${CREATED_WORKTREES[$branch]}" echo "${BLUE}# $branch${NC}" echo "cd $path" echo "claude" echo "" done print_header "All Worktrees" git worktree list echo "" print_header "Batch Management" echo "List all: git worktree list" echo "Remove all:" for branch in "${!CREATED_WORKTREES[@]}"; do path="${CREATED_WORKTREES[$branch]}" echo " git worktree remove $path" done echo "" # Offer to generate cleanup script read -p "Generate cleanup script? (yes/no): " -r if [[ $REPLY =~ ^[Yy]es$ ]]; then generate_cleanup_script fi } generate_cleanup_script() { CLEANUP_SCRIPT="cleanup-worktrees.sh" cat > "$CLEANUP_SCRIPT" << 'EOF' #!/bin/bash # Cleanup script for batch-created worktrees # Generated by git-worktree-setup skill set -euo pipefail GREEN='\033[0;32m' RED='\033[0;31m' NC='\033[0m' echo "Cleaning up worktrees..." EOF for branch in "${!CREATED_WORKTREES[@]}"; do path="${CREATED_WORKTREES[$branch]}" cat >> "$CLEANUP_SCRIPT" << EOF echo "Removing $branch..." if git worktree remove "$path" 2>/dev/null; then echo -e "\${GREEN}✓\${NC} Removed: $branch" read -p "Delete branch '$branch'? (yes/no): " -r if [[ \$REPLY =~ ^[Yy]es$ ]]; then git branch -d "$branch" 2>/dev/null && echo -e "\${GREEN}✓\${NC} Deleted branch: $branch" || echo -e "\${RED}✗\${NC} Failed to delete branch: $branch" fi else echo -e "\${RED}✗\${NC} Failed to remove: $branch" fi EOF done cat >> "$CLEANUP_SCRIPT" << 'EOF' echo "" echo "Cleanup complete!" echo "" echo "Remaining worktrees:" git worktree list EOF chmod +x "$CLEANUP_SCRIPT" print_success "Generated cleanup script: $CLEANUP_SCRIPT" print_info "Run with: ./$CLEANUP_SCRIPT" } # ============================================================================ # Main Execution # ============================================================================ main() { print_header "Git Worktree Batch Setup" # Phase 0: Prerequisites check_prerequisites validate_branches check_directory_conflicts # Confirm before proceeding echo "" read -p "Create ${#BRANCHES[@]} worktrees? (yes/no): " -r if [[ ! $REPLY =~ ^[Yy]es$ ]]; then print_info "Aborted by user" exit 0 fi # Phase 1: Create worktrees create_worktrees # Phase 2: Setup development environments detect_package_manager install_dependencies # Phase 3: Summary print_final_summary print_success "Batch setup complete!" } # Run main function main "$@"