Skip to content

therohitdas/copy-env

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 

Repository files navigation

Git Worktree .env Auto-Copy Setup

Problem

When working with Git worktrees, environment files (.env, .env.local, etc.) are not automatically copied from the main repository to new worktrees. This causes issues because:

  • ❌ New worktrees can't run the project without .env files
  • ❌ You have to manually copy .env files every time you create a worktree
  • ❌ Easy to forget, leading to confusing errors when trying to test
  • ❌ Especially problematic with Claude Code which creates worktrees automatically

Solution

Set up a global Git hook that automatically copies all .env* files from the main repository to any new worktree when it's created.

Setup Instructions

Step 1: Check for Existing Global Hooks Directory

git config --global core.hooksPath

If this returns a path:

  • You already have a global hooks directory configured
  • Use that path instead of ~/.git-hooks in the steps below
  • Skip to Step 3

If this returns nothing (or an error):

  • No global hooks configured yet
  • Proceed to Step 2

Step 2: Create Global Hooks Directory

# Create the directory
mkdir -p ~/.git-hooks

# Configure Git to use it globally
git config --global core.hooksPath ~/.git-hooks

# Verify it's set
git config --global core.hooksPath
# Should output: /Users/yourname/.git-hooks

Step 3: Create the Post-Checkout Hook

Run this command to create the hook file:

cat > ~/.git-hooks/post-checkout << 'EOF'
#!/bin/bash
# Global Git hook: post-checkout
# Automatically copy .env files to new worktrees

# Only run for worktree checkouts (not regular branch switches in main repo)
# $3 = 1 means it's a branch checkout (not file checkout)
if [ "$3" != "1" ]; then
    exit 0
fi

# Get the common git directory (works for both main repo and worktrees)
GIT_COMMON_DIR=$(git rev-parse --git-common-dir)
MAIN_REPO=$(cd "$GIT_COMMON_DIR/.." && pwd)
CURRENT_DIR=$(pwd)

# If we're in a worktree (not the main repo), copy .env files
if [ "$CURRENT_DIR" != "$MAIN_REPO" ]; then
    echo "📋 Worktree detected: $CURRENT_DIR"

    # Copy all .env* files from main repo to worktree
    for envfile in "$MAIN_REPO"/.env*; do
        if [ -f "$envfile" ]; then
            filename=$(basename "$envfile")
            if [ ! -f "$CURRENT_DIR/$filename" ]; then
                cp "$envfile" "$CURRENT_DIR/$filename"
                echo "  ✓ Copied $filename"
            else
                echo "  ⊘ Skipped $filename (already exists)"
            fi
        fi
    done

    echo "✅ Environment files synced!"
fi
EOF

Step 4: Make the Hook Executable

chmod +x ~/.git-hooks/post-checkout

Step 5: Verify Installation

# Check the hook exists and is executable
ls -la ~/.git-hooks/post-checkout

# Should show something like:
# -rwxr-xr-x  1 yourname  staff  XXX Jan 14 XX:XX /Users/yourname/.git-hooks/post-checkout

Testing

Create a test worktree to verify it works:

# Navigate to any repo with .env files
cd /path/to/your/repo

# Create a test worktree
git worktree add ~/.test-worktree -b test-branch

# You should see output like:
# Preparing worktree (new branch 'test-branch')
# HEAD is now at XXXXXXX <commit message>
# 📋 Worktree detected: /Users/yourname/.test-worktree
#   ✓ Copied .env
#   ✓ Copied .env.local
# ✅ Environment files synced!

# Verify files were copied
ls ~/.test-worktree/.env*

# Clean up
git worktree remove ~/.test-worktree
git branch -D test-branch

How It Works

  1. Trigger: When you run git worktree add, Git executes the post-checkout hook
  2. Detection: The hook detects if you're in a worktree (not the main repo)
  3. Copy: It finds all .env* files in the main repository
  4. Sync: Copies them to the new worktree (skips if they already exist)

What Gets Copied

All files matching .env* pattern:

  • .env
  • .env.local
  • .env.development
  • .env.production
  • .env.test
  • .env.example
  • etc.

Safety Features

  • Won't overwrite: If a file already exists in the worktree, it's skipped
  • Only worktrees: Won't affect your main repository
  • Only on creation: Only runs when checking out a new worktree, not on branch switches
  • Global: Works for all repositories on your machine

Benefits

Zero manual copying: Environment files are automatically synced to new worktrees

Works with Claude Code: Claude creates worktrees automatically, and this hook ensures they have the necessary .env files

Works with manual worktrees: Also works when you create worktrees manually with git worktree add

Set once, use everywhere: Global hook applies to all repositories on your machine

No maintenance: Set it up once and it works forever

Troubleshooting

Hook doesn't run when creating worktree

Check if global hooks path is set:

git config --global core.hooksPath

If not set, configure it:

git config --global core.hooksPath ~/.git-hooks

Hook runs but files aren't copied

Check if hook is executable:

ls -la ~/.git-hooks/post-checkout
# Should show -rwxr-xr-x (note the 'x' for executable)

If not executable, fix it:

chmod +x ~/.git-hooks/post-checkout

Files still not copied

Verify .env files exist in main repo:

cd /path/to/main/repo
ls -la .env*

Test hook manually in a worktree:

cd /path/to/worktree
bash -x ~/.git-hooks/post-checkout 0 0 1

This will show debug output to help identify the issue.

Important Technical Detail

Why --git-common-dir instead of --git-dir?

In worktrees, git rev-parse --git-dir returns .git/worktrees/<worktree-name>, which is the worktree-specific git directory. If we use cd "$GIT_DIR/..", we end up in .git/worktrees/ instead of the main repo root.

Using --git-common-dir always points to the main .git directory, so cd "$GIT_COMMON_DIR/.." correctly resolves to the main repository root where .env files are stored.

Incorrect approach (buggy):

GIT_DIR=$(git rev-parse --git-dir)
MAIN_REPO=$(cd "$GIT_DIR/.." && pwd)
# Results in: /path/to/repo/.git/worktrees (WRONG!)

Correct approach:

GIT_COMMON_DIR=$(git rev-parse --git-common-dir)
MAIN_REPO=$(cd "$GIT_COMMON_DIR/.." && pwd)
# Results in: /path/to/repo (CORRECT!)

For Team Members

After setting this up, you can:

  • Create worktrees with git worktree add and environment files will be automatically copied
  • Use Claude Code without worrying about missing .env files
  • Test features in isolated worktrees without manual setup

One-Time Setup Script

If you prefer, you can run this all-in-one script:

# Create global hooks directory if it doesn't exist
mkdir -p ~/.git-hooks

# Create the post-checkout hook
cat > ~/.git-hooks/post-checkout << 'EOF'
#!/bin/bash
if [ "$3" != "1" ]; then exit 0; fi
GIT_COMMON_DIR=$(git rev-parse --git-common-dir)
MAIN_REPO=$(cd "$GIT_COMMON_DIR/.." && pwd)
CURRENT_DIR=$(pwd)
if [ "$CURRENT_DIR" != "$MAIN_REPO" ]; then
    echo "📋 Worktree detected: $CURRENT_DIR"
    for envfile in "$MAIN_REPO"/.env*; do
        if [ -f "$envfile" ]; then
            filename=$(basename "$envfile")
            if [ ! -f "$CURRENT_DIR/$filename" ]; then
                cp "$envfile" "$CURRENT_DIR/$filename"
                echo "  ✓ Copied $filename"
            else
                echo "  ⊘ Skipped $filename (already exists)"
            fi
        fi
    done
    echo "✅ Environment files synced!"
fi
EOF

# Make it executable
chmod +x ~/.git-hooks/post-checkout

# Configure Git to use global hooks
git config --global core.hooksPath ~/.git-hooks

echo "✅ Global Git worktree .env auto-copy hook installed!"

Questions?

If you run into issues, check:

  1. Global hooks path is configured: git config --global core.hooksPath
  2. Hook file exists: ls ~/.git-hooks/post-checkout
  3. Hook is executable: ls -la ~/.git-hooks/post-checkout
  4. .env files exist in main repo: ls -la .env*

About

Copy local .env files to created worktrees. Works with all coding agents.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published