• Git Hooks: Auto-Symlink CLAUDE.md in Worktrees

    When working with Claude Code CLI, the CLAUDE.md file in your project root is your AI’s cheat sheet. It tells Claude everything about your codebase: structure, conventions, workflows, and why you decided to name that variable temporaryFinalVersionActuallyThisOne.

    Some developers prefer to keep CLAUDE.md in .gitignore — maybe it contains team-specific workflows, local paths, or just things you’d rather not share with the world. This works perfectly until you discover git worktrees.

    The Problem: Worktrees Have Amnesia

    Git worktrees let you run multiple branches simultaneously in separate directories:

    git worktree add ../feature-branch feature-branch
    git worktree add ../bugfix-123 bugfix-123

    Parallel development! No more stashing! What could go wrong?

    Well, .gitignore files don’t get copied to worktrees. Your shiny new worktree is blissfully unaware that CLAUDE.md even exists. Now you have an AI assistant that’s essentially wandering around your codebase like a tourist without a map.

    The Solution: post-checkout Hook

    Git hooks are scripts that fire at specific moments in git’s lifecycle. The post-checkout hook runs right after checkout — including when you create a worktree. Perfect timing.

    Here’s a hook that automatically symlinks files from your main repo to each worktree:

    #!/bin/bash
    # .git/hooks/post-checkout
    
    BRANCH_CHECKOUT=$3
    [ "$BRANCH_CHECKOUT" = "0" ] && exit 0
    
    if [ -f ".git" ]; then
        CURRENT_DIR=$(pwd)
        MAIN_REPO=$(git rev-parse --git-common-dir | sed 's/\/\.git$//')
    
        echo "🔗 Creating symlinks in the worktree..."
    
        FILES_TO_LINK=(
            "CLAUDE.md"
            ".claude"
        )
    
        for file in "${FILES_TO_LINK[@]}"; do
            SOURCE="$MAIN_REPO/$file"
            TARGET="$CURRENT_DIR/$file"
    
            if [ -e "$SOURCE" ]; then
                if [ ! -e "$TARGET" ]; then
                    ln -s "$SOURCE" "$TARGET"
                    echo "✅ Symlink created: $file"
                else
                    echo "⏭️ File already exists: $file"
                fi
            fi
        done
    fi

    The magic: when .git is a file (not a directory), you’re in a worktree. The hook finds your main repo, then symlinks whatever files you need. Edit CLAUDE.md once, all worktrees see the update instantly.

    Wrapping Up

    Git worktrees + ignored config files = headache. Symlinks via post-checkout hook = problem solved. Your AI assistant now has full context everywhere, and you can keep your CLAUDE.md as private as your browser history.