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.mdor.claude/is intentionally ignored;- you use
git worktreeregularly; - 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; 1for a branch checkout,0for 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.