GitWorktree
Git Worktree

Git Worktree Script

A bash script for creating git worktrees quickly and efficiently for parallel development.

Installation

Quick Setup (3 steps)

  1. Create the script file:

    mkdir -p ~/bin
    nano ~/bin/worktree
  2. Copy the script content from the bottom of this page, paste it into the editor, then save (Ctrl+X, Y, Enter)

  3. Make it available globally:

    chmod +x ~/bin/worktree
    echo 'export PATH="$HOME/bin:$PATH"' >> ~/.zshrc  # For macOS
    echo 'export PATH="$HOME/bin:$PATH"' >> ~/.bashrc # For Linux
    source ~/.zshrc  # or source ~/.bashrc

Alternative: System-wide Installation

For system-wide access (all users):

sudo nano /usr/local/bin/worktree
# Copy script content and save
sudo chmod +x /usr/local/bin/worktree

Verify Installation

Test in any git repository:

which worktree
worktree feature-test

Troubleshooting:

  • If command not found: restart terminal or run source ~/.zshrc
  • If permission denied: run chmod +x ~/bin/worktree

Usage

Navigate to any git repository and run:

worktree {branch-name}

Examples

# Create a feature branch worktree
worktree feature-login-improvements
 
# Create a bug fix worktree
worktree fix-dashboard-calculation
 
# Create a hotfix worktree
worktree hotfix-security-vulnerability
 
# Create a refactor worktree
worktree refactor-auth-service

What It Does

  1. Validates inputs - Checks branch name is provided and target directory doesn't exist
  2. Checks environment - Ensures you're in a git repository
  3. Fetches latest branches - Gets all remote branch information
  4. Intelligently handles branches:
    • πŸ“‘ Remote branch exists: Checks out existing remote branch
    • πŸ’» Local branch exists: Checks out existing local branch
    • πŸ†• New branch: Creates new branch from origin/development
  5. Sets up upstream tracking - Automatically configures proper upstream tracking for all branch types
  6. Creates worktree - Makes a new directory ../{project-name}-{branch-name}
  7. Verifies upstream tracking - Confirms proper upstream configuration and warns about potential issues
  8. Copies environment - Automatically copies .env file if it exists
  9. Installs dependencies - Runs npm install if package.json exists
  10. Auto-navigation - Opens new shell in the worktree directory

Directory Structure

The script creates worktrees in parallel directories:

/path/to/projects/
β”œβ”€β”€ myproject/                           # Main repository
β”œβ”€β”€ myproject-feature-login-improvements/ # Worktree 1
β”œβ”€β”€ myproject-fix-dashboard-calculation/  # Worktree 2
└── myproject-hotfix-security/           # Worktree 3

Branch Naming Conventions

  • Features: feature-{description}
  • Bug fixes: fix-{description}
  • Hotfixes: hotfix-{description}
  • Refactoring: refactor-{description}

Managing Worktrees

List all worktrees

git worktree list

Switch to a worktree

cd ../myproject-feature-name

Remove a completed worktree

# First ensure work is committed and pushed
git worktree remove ../myproject-feature-name

Clean up after merge

# Delete remote branch (if merged)
git push origin --delete feature-name
 
# Delete local branch reference
git branch -d feature-name

Intelligent Branch Handling

The script automatically detects and handles different branch scenarios:

πŸ“‘ Remote Branch Exists

worktree feature-existing-remote
# Output: Branch 'feature-existing-remote' exists on remote, checking out existing remote branch

πŸ’» Local Branch Exists

worktree feature-existing-local
# Output: Branch 'feature-existing-local' exists locally, checking out existing local branch

πŸ†• New Branch Creation

worktree feature-brand-new
# Output: Branch 'feature-brand-new' doesn't exist, creating new branch from origin/development
# Output: πŸ”„ Setting up upstream tracking for new branch...
# Output: βœ… Branch pushed and upstream tracking configured!

Automatic Setup Features

  • πŸ”„ Upstream Tracking: Automatically configures upstream tracking for all branch types:
    • New branches: Pushes to origin and sets upstream tracking
    • Remote branches: Sets upstream tracking to existing remote branch
    • Local branches: Checks for remote and pushes if needed, or sets upstream to existing remote
  • πŸ” Verification: Confirms upstream tracking is properly configured and warns about potential issues
  • πŸ” Environment Variables: Copies .env file from main repository
  • πŸ“¦ Dependencies: Runs npm install automatically if package.json exists
  • πŸš€ Ready to Code: Opens new shell in worktree directory

Error Handling

The script checks for:

  • βœ… Branch name provided
  • βœ… Inside git repository
  • βœ… Target directory doesn't exist
  • βœ… Can fetch from remote origin

Requirements

  • Git repository with origin/development branch
  • Bash shell
  • Git configured with origin remote

Troubleshooting

"Not in a git repository"

  • Make sure you're inside a git project directory

"Failed to fetch origin/development"

  • Ensure your repository has a development branch on origin
  • Check your internet connection and git credentials

"Branch already exists"

  • Choose a different branch name or delete the existing branch

"Directory already exists"

  • Remove the existing directory or choose a different branch name

What Happens Automatically

After running the script, you'll be automatically placed in the new worktree with:

  1. βœ… Upstream tracking configured: Proper git upstream tracking set up for your branch type
  2. βœ… Environment ready: .env file copied (if exists)
  3. βœ… Dependencies installed: npm install completed (if package.json exists)
  4. βœ… Safety checks: Verification that upstream tracking is working correctly
  5. βœ… New shell opened: Ready to start coding immediately

The script provides clear feedback about what type of branch you're working with and shows the tracking configuration for safety.

Next Steps

  1. Start development server: npm run dev, npm start, etc.
  2. Begin development: Make your changes and commits
  3. Push changes: git push (upstream already configured automatically)

No manual setup required! The script shows you exactly which upstream branch you're tracking for safety.

Safety Features

The script includes several safety features:

  • πŸ’‘ Safety reminders: Clear information about what branch you're tracking
  • ⚠️ Warning system: Alerts if branches are tracking unexpected remotes (like development)
  • πŸ” Upstream verification: Confirms tracking is configured properly
  • πŸ“„ Current tracking display: Shows exactly where your pushes will go

Always check the output to confirm your branch is tracking the expected remote!

Advanced Usage

Manual worktree commands

# Create worktree manually
git worktree add ../project-branch -b branch-name origin/development
 
# Create from specific commit
git worktree add ../project-temp --detach commit-hash
 
# Repair broken worktree links
git worktree repair
 
# Clean up stale worktrees
git worktree prune

This script automates the common worktree workflow while maintaining best practices for branch naming and directory organization.

The Script

#!/bin/bash
 
# Git Worktree Creation Script
# Creates a new worktree with branch from origin/development
 
# Get branch name as first argument
BRANCH_NAME="$1"
PROJECT_NAME=$(basename "$PWD")
 
# Validate inputs
if [ -z "$BRANCH_NAME" ]; then
    echo "Error: Branch name is required"
    echo "Usage: worktree {branch-name}"
    echo ""
    echo "Examples:"
    echo "  worktree feature-login-improvements"
    echo "  worktree fix-dashboard-calculation" 
    echo "  worktree hotfix-security-vulnerability"
    exit 1
fi
 
# Check if we're in a git repository
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
    echo "Error: Not in a git repository"
    exit 1
fi
 
# Check if target directory already exists
TARGET_DIR="../${PROJECT_NAME}-${BRANCH_NAME}"
if [ -d "$TARGET_DIR" ]; then
    echo "Error: Directory '$TARGET_DIR' already exists"
    exit 1
fi
 
# Fetch all branches to get latest info
echo "Fetching latest branches..."
git fetch origin
 
# Check if branch exists locally
LOCAL_BRANCH_EXISTS=$(git show-ref --verify --quiet refs/heads/$BRANCH_NAME && echo "true" || echo "false")
 
# Check if branch exists on remote
REMOTE_BRANCH_EXISTS=$(git show-ref --verify --quiet refs/remotes/origin/$BRANCH_NAME && echo "true" || echo "false")
 
# Determine the worktree creation strategy
if [ "$REMOTE_BRANCH_EXISTS" = "true" ]; then
    echo "πŸ“‘ Branch '$BRANCH_NAME' exists on remote, checking out existing remote branch"
    WORKTREE_CMD="git worktree add \"$TARGET_DIR\" -b \"$BRANCH_NAME\" origin/$BRANCH_NAME"
    BRANCH_SOURCE="origin/$BRANCH_NAME"
    NEEDS_UPSTREAM_SETUP="remote"
elif [ "$LOCAL_BRANCH_EXISTS" = "true" ]; then
    echo "πŸ’» Branch '$BRANCH_NAME' exists locally, checking out existing local branch"
    WORKTREE_CMD="git worktree add \"$TARGET_DIR\" \"$BRANCH_NAME\""
    BRANCH_SOURCE="local branch"
    NEEDS_UPSTREAM_SETUP="local"
else
    echo "πŸ†• Branch '$BRANCH_NAME' doesn't exist, creating new branch from origin/development"
    if ! git fetch origin development; then
        echo "Error: Failed to fetch origin/development"
        echo "Make sure 'development' branch exists on origin"
        exit 1
    fi
    WORKTREE_CMD="git worktree add \"$TARGET_DIR\" -b \"$BRANCH_NAME\" origin/development"
    BRANCH_SOURCE="origin/development"
    NEEDS_UPSTREAM_SETUP="new"
fi
 
# Create worktree
echo "Creating worktree for branch: $BRANCH_NAME"
echo "Target directory: $TARGET_DIR"
echo "Source: $BRANCH_SOURCE"
 
if eval $WORKTREE_CMD; then
    echo ""
    echo "βœ… Worktree created successfully!"
    echo "πŸ“ Location: $TARGET_DIR"
    echo "🌿 Branch: $BRANCH_NAME (from $BRANCH_SOURCE)"
    
    # Navigate to new worktree
    cd "$TARGET_DIR"
    
    # Set up proper upstream tracking for all branches
    echo ""
    echo "πŸ”„ Setting up upstream tracking..."
    
    case "$NEEDS_UPSTREAM_SETUP" in
        "new")
            echo "Setting up upstream tracking for new branch..."
            git push -u origin "$BRANCH_NAME"
            echo "βœ… Branch pushed and upstream tracking configured!"
            ;;
        "remote")
            echo "Setting up upstream tracking for existing remote branch..."
            git branch --set-upstream-to=origin/"$BRANCH_NAME" "$BRANCH_NAME"
            echo "βœ… Upstream tracking configured to origin/$BRANCH_NAME!"
            ;;
        "local")
            echo "Checking upstream tracking for existing local branch..."
            # Check if remote branch exists for this local branch
            if git show-ref --verify --quiet refs/remotes/origin/"$BRANCH_NAME"; then
                echo "Remote branch exists, setting upstream tracking..."
                git branch --set-upstream-to=origin/"$BRANCH_NAME" "$BRANCH_NAME"
                echo "βœ… Upstream tracking configured to origin/$BRANCH_NAME!"
            else
                echo "No remote branch found. Pushing local branch to origin..."
                git push -u origin "$BRANCH_NAME"
                echo "βœ… Branch pushed and upstream tracking configured!"
            fi
            ;;
    esac
    
    # Verify upstream tracking
    echo ""
    echo "πŸ” Verifying upstream tracking..."
    UPSTREAM_INFO=$(git branch -vv | grep "^\*" | grep -o '\[.*\]' | tr -d '[]' || echo "none")
    if [ "$UPSTREAM_INFO" != "none" ]; then
        echo "βœ… Upstream tracking verified: $UPSTREAM_INFO"
        
        # Additional safety check - warn if tracking unexpected branch
        if [[ "$UPSTREAM_INFO" == *"development"* ]] && [ "$BRANCH_NAME" != "development" ]; then
            echo "⚠️  WARNING: Branch '$BRANCH_NAME' is tracking development branch!"
            echo "⚠️  This might cause accidental pushes to development."
        fi
    else
        echo "⚠️  WARNING: No upstream tracking configured!"
        echo "⚠️  You may need to run 'git push -u origin $BRANCH_NAME' manually."
    fi
    
    # Copy .env file if it exists in the original repository
    if [ -f "../${PROJECT_NAME}/.env" ]; then
        echo ""
        echo "πŸ” Found .env file, copying to new worktree..."
        cp "../${PROJECT_NAME}/.env" .env
        echo "βœ… Environment file copied successfully!"
    fi
    
    # Check for package.json and run npm install if it exists
    if [ -f "package.json" ]; then
        echo ""
        echo "πŸ“¦ Found package.json, installing dependencies..."
        if npm install; then
            echo "βœ… Dependencies installed successfully!"
        else
            echo "⚠️ Failed to install dependencies. You may need to run 'npm install' manually."
        fi
    fi
    
    echo ""
    echo "πŸš€ Ready to start development!"
    echo "πŸ“„ Current branch tracking: $(git branch -vv | grep "^\*" | grep -o '\[.*\]' | tr -d '[]' || echo 'none')"
    echo ""
    echo "πŸ’‘ Safety reminders:"
    echo "  β€’ 'git push' will push to the tracked remote branch shown above"
    echo "  β€’ Always verify your current branch with 'git branch'"
    echo "  β€’ Use 'git push origin $BRANCH_NAME' to be explicit about destination"
    echo ""
    echo "To list all worktrees:"
    echo "  git worktree list"
    echo ""
    echo "To remove this worktree later:"
    echo "  git worktree remove $TARGET_DIR"
    echo ""
    echo "Navigating to new worktree..."
    
    # Start a new shell in the worktree directory
    exec bash -c "cd '$TARGET_DIR' && exec \$SHELL"
else
    echo "❌ Failed to create worktree"
    exit 1
fi