383 lines
9.6 KiB
Bash
Executable File
383 lines
9.6 KiB
Bash
Executable File
#!/bin/bash
|
||
# Git Worktree Setup Script
|
||
# Generated by git-worktree-setup skill
|
||
#
|
||
# This script automates the creation of a git worktree with development environment setup.
|
||
#
|
||
# Usage:
|
||
# ./worktree-setup.sh <branch-name> [worktree-path] [--no-install]
|
||
|
||
set -euo pipefail
|
||
|
||
# ============================================================================
|
||
# Configuration
|
||
# ============================================================================
|
||
|
||
BRANCH_NAME="${1:-}"
|
||
WORKTREE_PATH="${2:-}"
|
||
SKIP_INSTALL=false
|
||
|
||
# Parse flags
|
||
for arg in "$@"; do
|
||
case $arg in
|
||
--no-install)
|
||
SKIP_INSTALL=true
|
||
shift
|
||
;;
|
||
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 name
|
||
if [ -z "$BRANCH_NAME" ]; then
|
||
print_error "Branch name required"
|
||
echo "Usage: $0 <branch-name> [worktree-path] [--no-install]"
|
||
exit 1
|
||
fi
|
||
|
||
# Set default worktree path if not provided
|
||
if [ -z "$WORKTREE_PATH" ]; then
|
||
WORKTREE_PATH="$(dirname "$REPO_ROOT")/$REPO_NAME-$BRANCH_NAME"
|
||
fi
|
||
|
||
print_info "Target branch: $BRANCH_NAME"
|
||
print_info "Worktree path: $WORKTREE_PATH"
|
||
}
|
||
|
||
check_working_directory() {
|
||
# Check for uncommitted changes
|
||
if [ -n "$(git status --porcelain)" ]; then
|
||
print_warning "You have uncommitted changes in current worktree"
|
||
git status --short
|
||
echo ""
|
||
read -p "Continue anyway? (yes/no): " -r
|
||
if [[ ! $REPLY =~ ^[Yy]es$ ]]; then
|
||
print_info "Aborted by user"
|
||
exit 0
|
||
fi
|
||
else
|
||
print_success "Working directory is clean"
|
||
fi
|
||
}
|
||
|
||
check_branch_status() {
|
||
# Check if branch exists
|
||
if git show-ref --verify "refs/heads/$BRANCH_NAME" &>/dev/null; then
|
||
BRANCH_TYPE="existing"
|
||
print_info "Branch exists: $BRANCH_NAME"
|
||
else
|
||
BRANCH_TYPE="new"
|
||
print_info "Will create new branch: $BRANCH_NAME"
|
||
|
||
# Check if exists on remote
|
||
if git show-ref --verify "refs/remotes/origin/$BRANCH_NAME" &>/dev/null; then
|
||
print_info "Branch exists on remote, will track it"
|
||
BRANCH_TYPE="remote"
|
||
fi
|
||
fi
|
||
}
|
||
|
||
check_directory_conflict() {
|
||
if [ -d "$WORKTREE_PATH" ]; then
|
||
print_error "Directory already exists: $WORKTREE_PATH"
|
||
echo ""
|
||
read -p "Remove and continue? (yes/no): " -r
|
||
if [[ $REPLY =~ ^[Yy]es$ ]]; then
|
||
rm -rf "$WORKTREE_PATH"
|
||
print_success "Removed existing directory"
|
||
else
|
||
print_info "Aborted by user"
|
||
exit 0
|
||
fi
|
||
else
|
||
print_success "Target directory available"
|
||
fi
|
||
}
|
||
|
||
# ============================================================================
|
||
# Worktree Creation
|
||
# ============================================================================
|
||
|
||
create_worktree() {
|
||
print_header "Creating Worktree"
|
||
|
||
case $BRANCH_TYPE in
|
||
new)
|
||
print_info "Creating new branch: $BRANCH_NAME"
|
||
if git worktree add "$WORKTREE_PATH" -b "$BRANCH_NAME"; then
|
||
print_success "Worktree created with new branch"
|
||
else
|
||
print_error "Failed to create worktree"
|
||
exit 1
|
||
fi
|
||
;;
|
||
|
||
existing)
|
||
print_info "Checking out existing branch: $BRANCH_NAME"
|
||
if git worktree add "$WORKTREE_PATH" "$BRANCH_NAME"; then
|
||
print_success "Worktree created from existing branch"
|
||
else
|
||
print_error "Failed to create worktree"
|
||
exit 1
|
||
fi
|
||
;;
|
||
|
||
remote)
|
||
print_info "Tracking remote branch: origin/$BRANCH_NAME"
|
||
if git worktree add "$WORKTREE_PATH" -b "$BRANCH_NAME" --track "origin/$BRANCH_NAME"; then
|
||
print_success "Worktree created tracking remote branch"
|
||
else
|
||
print_error "Failed to create worktree"
|
||
exit 1
|
||
fi
|
||
;;
|
||
esac
|
||
}
|
||
|
||
verify_worktree() {
|
||
print_header "Verifying Worktree"
|
||
|
||
# Check if worktree appears in list
|
||
if git worktree list | grep -q "$WORKTREE_PATH"; then
|
||
print_success "Worktree appears in git worktree list"
|
||
else
|
||
print_error "Worktree not in git worktree list"
|
||
exit 1
|
||
fi
|
||
|
||
# Check if directory exists
|
||
if [ -d "$WORKTREE_PATH" ]; then
|
||
print_success "Worktree directory exists"
|
||
else
|
||
print_error "Worktree directory not found"
|
||
exit 1
|
||
fi
|
||
|
||
# Check if .git file exists
|
||
if [ -f "$WORKTREE_PATH/.git" ]; then
|
||
print_success "Git metadata configured"
|
||
else
|
||
print_error "Missing .git file in worktree"
|
||
exit 1
|
||
fi
|
||
|
||
# Check if has files
|
||
if [ -n "$(ls -A "$WORKTREE_PATH")" ]; then
|
||
print_success "Worktree populated with files"
|
||
else
|
||
print_error "Worktree directory is empty"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# ============================================================================
|
||
# Development Environment Setup
|
||
# ============================================================================
|
||
|
||
detect_package_manager() {
|
||
cd "$WORKTREE_PATH"
|
||
|
||
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 "Detected package manager: $PKG_MANAGER"
|
||
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
|
||
|
||
print_header "Installing Dependencies"
|
||
|
||
cd "$WORKTREE_PATH"
|
||
|
||
print_info "Running: $INSTALL_CMD"
|
||
|
||
if $INSTALL_CMD; then
|
||
print_success "Dependencies installed successfully"
|
||
else
|
||
print_warning "Dependency installation failed"
|
||
print_info "You can manually install later with: cd $WORKTREE_PATH && $INSTALL_CMD"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
copy_environment_files() {
|
||
if [ "$SKIP_INSTALL" = true ]; then
|
||
return 0
|
||
fi
|
||
|
||
if [ -f "$REPO_ROOT/.env" ]; then
|
||
print_info "Found .env file in repository root"
|
||
read -p "Copy .env to worktree? (yes/no): " -r
|
||
if [[ $REPLY =~ ^[Yy]es$ ]]; then
|
||
cp "$REPO_ROOT/.env" "$WORKTREE_PATH/.env"
|
||
print_success "Copied .env file"
|
||
fi
|
||
fi
|
||
|
||
# Copy other common env files
|
||
for env_file in .env.local .env.development .env.test; do
|
||
if [ -f "$REPO_ROOT/$env_file" ]; then
|
||
read -p "Copy $env_file to worktree? (yes/no): " -r
|
||
if [[ $REPLY =~ ^[Yy]es$ ]]; then
|
||
cp "$REPO_ROOT/$env_file" "$WORKTREE_PATH/$env_file"
|
||
print_success "Copied $env_file"
|
||
fi
|
||
fi
|
||
done
|
||
}
|
||
|
||
# ============================================================================
|
||
# Summary and Next Steps
|
||
# ============================================================================
|
||
|
||
print_summary() {
|
||
print_header "Worktree Created Successfully"
|
||
|
||
echo "Location: $WORKTREE_PATH"
|
||
echo "Branch: $BRANCH_NAME ($BRANCH_TYPE)"
|
||
|
||
if [ "$PKG_MANAGER" != "none" ] && [ "$SKIP_INSTALL" = false ]; then
|
||
echo "Dev Setup: ✓ Complete ($PKG_MANAGER)"
|
||
else
|
||
echo "Dev Setup: ⊘ Skipped"
|
||
fi
|
||
|
||
echo ""
|
||
print_header "Next Steps"
|
||
|
||
echo "1. Navigate to worktree:"
|
||
echo " ${BLUE}cd $WORKTREE_PATH${NC}"
|
||
echo ""
|
||
echo "2. Start Claude Code:"
|
||
echo " ${BLUE}claude${NC}"
|
||
echo ""
|
||
echo "3. Begin development on $BRANCH_NAME"
|
||
echo ""
|
||
|
||
print_header "All Worktrees"
|
||
git worktree list
|
||
echo ""
|
||
|
||
print_header "Quick Reference"
|
||
echo "List worktrees: git worktree list"
|
||
echo "Remove worktree: git worktree remove $WORKTREE_PATH"
|
||
echo "Navigate: cd $WORKTREE_PATH"
|
||
echo "Return to main: cd $REPO_ROOT"
|
||
echo ""
|
||
}
|
||
|
||
# ============================================================================
|
||
# Main Execution
|
||
# ============================================================================
|
||
|
||
main() {
|
||
print_header "Git Worktree Setup"
|
||
|
||
# Phase 0: Prerequisites
|
||
check_prerequisites
|
||
check_working_directory
|
||
check_branch_status
|
||
check_directory_conflict
|
||
|
||
# Phase 1: Create worktree
|
||
create_worktree
|
||
verify_worktree
|
||
|
||
# Phase 2: Setup development environment
|
||
detect_package_manager
|
||
install_dependencies
|
||
copy_environment_files
|
||
|
||
# Phase 3: Summary
|
||
print_summary
|
||
|
||
print_success "Setup complete!"
|
||
}
|
||
|
||
# Run main function
|
||
main "$@"
|