• Auto-Symlink Claude Code Memory in Git Worktrees

    Git worktrees are excellent when you want several branches checked out at the same time:

    git worktree add ../feature-auth -b feature/auth
    git worktree add ../hotfix-login -b hotfix/login

    The annoying part is local project context. Claude Code can use project memory files such as CLAUDE.md, and many teams keep local AI notes, custom commands, or machine-specific settings out of Git. That is reasonable: local context may contain private paths, personal workflow notes, or commands that are useful to you but noisy for everyone else.

    Then you create a new worktree and the ignored files are gone. The code is there, but the local AI context is missing.

    The fix is small: use a Git hook to create symlinks from the main working tree into each linked worktree.

    When This Pattern Fits

    Use this when:

    • CLAUDE.md or .claude/ is intentionally ignored;
    • you use git worktree regularly;
    • you want every linked worktree to see the same local AI context;
    • your environment supports symbolic links.

    Do not use it blindly for secrets. If .claude/ contains tokens, credentials, or machine-specific files that should not be shared across worktrees, link only the safe files instead of the whole directory.

    Why post-checkout

    Git runs the post-checkout hook after git checkout, git switch, git clone, and also after git worktree add unless --no-checkout is used. The hook receives three arguments:

    • previous HEAD;
    • new HEAD;
    • 1 for a branch checkout, 0 for a file checkout.

    That makes it a convenient place to do lightweight worktree setup.

    Linked worktrees also have a useful property: their .git entry is a file, not a directory. The file points to Git’s per-worktree administrative directory. Git exposes the shared common directory through git rev-parse --git-common-dir, so the hook does not need to guess where the main repository lives.

    The Hook

    Create .git/hooks/post-checkout in the main working tree:

    #!/usr/bin/env sh
    set -eu
    
    branch_checkout=${3:-0}
    
    # Ignore file checkouts. We only want branch checkouts and worktree creation.
    [ "$branch_checkout" = "1" ] || exit 0
    
    # In the main working tree, .git is a directory. In linked worktrees, .git is a file.
    [ -f .git ] || exit 0
    
    worktree_root=$(git rev-parse --show-toplevel)
    common_git_dir=$(git rev-parse --git-common-dir)
    main_worktree=$(cd "$common_git_dir/.." && pwd -P)
    
    link_one() {
      name=$1
      source=$main_worktree/$name
      target=$worktree_root/$name
    
      if [ ! -e "$source" ] && [ ! -L "$source" ]; then
        return 0
      fi
    
      if [ -e "$target" ] || [ -L "$target" ]; then
        return 0
      fi
    
      ln -s "$source" "$target"
      printf 'Linked %s -> %s\n' "$target" "$source"
    }
    
    link_one CLAUDE.md
    link_one .claude

    Make it executable:

    chmod +x .git/hooks/post-checkout

    Now create a new worktree:

    git worktree add ../feature-auth -b feature/auth

    If the main working tree has CLAUDE.md or .claude/, the new worktree gets symlinks to them.

    Test It

    You can test the hook without touching a real branch:

    git worktree add ../hook-test -b hook-test
    ls -la ../hook-test/CLAUDE.md ../hook-test/.claude
    git worktree remove ../hook-test

    If one of the files does not exist in the main working tree, the hook silently skips it. If the target already exists in the linked worktree, the hook also leaves it alone.

    Install It More Deliberately

    Git hooks stored in .git/hooks are local to one repository clone. That is often exactly what you want for personal AI context.

    If your repository uses a shared hooks directory, check it first:

    git config --get core.hooksPath

    When core.hooksPath is set, install the hook there instead of .git/hooks/post-checkout.

    You can also keep a copy in a tracked script, for example scripts/hooks/post-checkout, and install it locally:

    cp scripts/hooks/post-checkout .git/hooks/post-checkout
    chmod +x .git/hooks/post-checkout

    That gives the team an opt-in setup without forcing everyone to use the same local Claude Code files.

    Caveats

    This is a Unix-style symlink solution. On Windows, symlink behavior depends on developer mode, permissions, filesystem, and shell. If symlinks are painful in your environment, copying files may be a better trade-off.

    The hook intentionally skips existing targets. That avoids overwriting local files, but it also means a stale file in a worktree will not be replaced automatically.

    If you move worktrees by hand, Git’s worktree metadata can become stale. Prefer git worktree move, git worktree remove, and git worktree repair instead of moving directories manually.

    Finally, think before linking an entire .claude/ directory. Shared commands are fine. Personal secrets are not. A safer version of the hook can link only CLAUDE.md and .claude/commands.

    Remove It

    Delete the hook:

    rm .git/hooks/post-checkout

    Then remove symlinks from worktrees where you no longer want them:

    rm ../feature-auth/CLAUDE.md
    rm ../feature-auth/.claude

    That removes only the symlinks in the linked worktree. The original files in the main working tree stay untouched.