The Problem: Manually Copying .env Files Every Time
When you frequently create Git worktrees in a Bun monorepo, you run into this annoyance: every new worktree needs its .env files manually copied over. Especially when using GUI apps like oh-my-worktree to manage worktrees, having to open a terminal just to copy files each time is tedious and error-prone.
In my case, I needed two environment files:
apps/api-server/.envapps/wetrials-x-mobile/.env
Every time I created a worktree, I had to copy these files one by one.
Approaches Considered
1. Symlinks
Keep .env files in a central location and symlink them in worktrees.
- Pros: Changes propagate to all worktrees
- Cons: Hard to automate with GUI apps; still need manual symlink creation per worktree
2. direnv
A tool that auto-loads environment variables per directory.
- Pros: Powerful and flexible
- Cons: Overkill since Bun already auto-loads
.envfiles
3. .env.example + Auto Copy
Copy from a version-controlled .env.example to the actual .env file.
- Pros: Team-friendly, trackable in git
- Cons: Need to re-enter sensitive values every time
4. External .env-store Directory
Copy from a central store outside the project.
- Pros: Clean structure
- Cons: Requires hardcoded paths, hard to share across team members
The Solution: Git post-checkout Hook
When Git creates a worktree, it automatically runs the post-checkout hook. We can leverage this to automatically copy .env files.
Key idea:
- Auto-copy
.envfiles from the main worktree (bare root) to the new worktree - Use relative paths to avoid hardcoding
- Skip when running in the main worktree itself
Implementation: post-checkout Hook Script
Create a .git/hooks/post-checkout file with the following content:
#!/bin/bash
# Git worktree post-checkout hook
# Auto-copies .env files from bare root on worktree creation
BARE_ROOT="$(cd "$(git rev-parse --git-common-dir)/.." && pwd)"
CURRENT="$(pwd)"
# Skip if we're in the bare root itself
[ "$BARE_ROOT" = "$CURRENT" ] && exit 0
# Copy .env files (only if they don't already exist)
for env_file in apps/api-server/.env apps/wetrials-x-mobile/.env; do
if [ -f "$BARE_ROOT/$env_file" ] && [ ! -e "$env_file" ]; then
cp "$BARE_ROOT/$env_file" "$env_file"
fi
doneHow It Works
git rev-parse --git-common-dir: Returns the path to the shared.gitdirectory across all worktrees.BARE_ROOTcalculation: The parent of the common.gitdirectory is the main worktree (bare root).- Condition check: If we're already in the bare root, the original
.envfiles are already there, so exit. - File copy: Copy
.envfiles from the bare root to the current worktree. Won't overwrite existing files.
Installation
1. Create the Hook File
Create the file in your main repository's .git/hooks/ directory:
cat > .git/hooks/post-checkout << 'EOF'
#!/bin/bash
BARE_ROOT="$(cd "$(git rev-parse --git-common-dir)/.." && pwd)"
CURRENT="$(pwd)"
[ "$BARE_ROOT" = "$CURRENT" ] && exit 0
for env_file in apps/api-server/.env apps/wetrials-x-mobile/.env; do
if [ -f "$BARE_ROOT/$env_file" ] && [ ! -e "$env_file" ]; then
cp "$BARE_ROOT/$env_file" "$env_file"
fi
done
EOF2. Make It Executable
chmod +x .git/hooks/post-checkout3. Test
Create a new worktree and verify that .env files are copied automatically:
git worktree add ../test-branch test-branch
cd ../test-branch
ls -la apps/api-server/.env apps/wetrials-x-mobile/.env # check files existCaveats
Won't Apply to Existing Worktrees
Worktrees created before the hook was installed didn't trigger post-checkout, so you'll need to copy .env files manually:
cd /path/to/existing-worktree
cp /path/to/main-worktree/apps/api-server/.env apps/api-server/.env
cp /path/to/main-worktree/apps/wetrials-x-mobile/.env apps/wetrials-x-mobile/.envSharing with Team Members
The .git/hooks/ directory isn't tracked by Git by default. To share the setup with your team:
Option 1: Manual install (simple) Add installation instructions to your README and let everyone set it up.
Option 2: Shared Git hooks (recommended)
Create a .githooks/ directory in the project root and commit the hooks:
mkdir -p .githooks
mv .git/hooks/post-checkout .githooks/post-checkout
chmod +x .githooks/post-checkout
git add .githooks/post-checkout
git config core.hooksPath .githooksThen other developers will automatically use the hooks after cloning.
Conclusion
Using the Git post-checkout hook, you can automatically copy .env files when creating worktrees. This approach:
- Works perfectly with GUI apps (runs automatically)
- No hardcoded paths, works anywhere
- No extra tools needed (no direnv, symlinks, etc.)
A simple but effective solution that completely eliminates the hassle of manually copying files every time.
While dealing with this problem, I ended up building a macOS app to make worktree management even easier. It's called oh-my-worktree, and it has built-in .env auto-copy so you don't even need the hook setup.

If you're a macOS user who frequently works with worktrees, give it a try.