GitWorktree.org logoGitWorktree.org

Git Worktree with .gitignore and .env Files

Understanding which files are shared between git worktrees and which are not is essential for a smooth workflow. This guide covers how .gitignore rules propagate across worktrees, why .env files need special attention, and strategies for managing both.

How .gitignore Works with Worktrees

The .gitignore file is a tracked file in your repository. Because it is tracked, it is automatically present in every worktree when the branch is checked out. All worktrees on the same branch share the same .gitignore rules.

.gitignore is shared via Git
# .gitignore is tracked — it appears in every worktree automatically
$ git worktree add ../myapp-feature feature/auth
$ cat ../myapp-feature/.gitignore
node_modules/
dist/
.env
.env.local
*.log

If different branches have different .gitignorefiles, each worktree will use the version from its checked-out branch. This is standard Git behavior — the ignore rules are part of the repository content, not worktree-specific configuration.

Nested .gitignore files in subdirectories also work exactly as expected. They are tracked files and follow their branch.

.env Files Are NOT Shared

Because .env files are listed in .gitignore, they are untracked. Git does not know about them, and they exist only in the working directory where they were created. When you add a new worktree, there is no .env file in it.

.env files are per-worktree
# Main worktree has .env
~/projects/myapp/
├── .env               # exists (you created it manually)
├── .env.local          # exists
├── .gitignore          # tracked — lists .env
└── src/

# New worktree — NO .env files
~/projects/myapp-feature/
├── .gitignore          # tracked — present automatically
├── src/
└── (no .env file)      # you must create or copy it

This applies to all untracked and ignored files: .env, .env.local, .env.development, node_modules/, dist/, IDE configuration like .idea/, and any other files matching your .gitignore patterns.

Strategies for Managing .env

1. Keep a .env.example in the repo

Track a template file with placeholder values. In each new worktree, copy it and fill in the real values.

.env.example pattern
# .env.example (tracked in Git)
DATABASE_URL=postgres://user:password@localhost:5432/myapp
API_KEY=your-api-key-here
REDIS_URL=redis://localhost:6379

# In each new worktree:
cp .env.example .env
# Then edit .env with real values

2. Copy from the main worktree

Copy .env on worktree creation
# After creating a worktree, copy .env from the main checkout
git worktree add ../myapp-feature feature/auth
cp .env ../myapp-feature/.env
cp .env.local ../myapp-feature/.env.local

3. Use a secrets manager

For team environments, tools like dotenv-vault, 1Password CLI, or doppler can pull secrets from a central store. This eliminates the need to copy .env files entirely.

4. Symlink .env files

Symlink approach
# Symlink to a single .env outside the worktrees
ln -s ~/secrets/myapp.env .env

# Or symlink to the main worktree's .env
cd ../myapp-feature
ln -s ../myapp/.env .env

# Caveat: changes in one worktree affect all symlinked copies

Using .git/info/exclude for Per-Worktree Ignores

The .gitignore file applies to all worktrees because it is tracked. But sometimes you want to ignore a file in only one worktree without changing the shared .gitignore. That is what .git/info/exclude is for.

In a linked worktree, .gitis a file (not a directory) that points to the actual Git directory. The exclude file for a linked worktree lives inside the main repository’s .git/worktrees/<name>/info/exclude path.

Per-worktree ignore rules
# Find the actual Git directory for a worktree
$ cat ../myapp-feature/.git
gitdir: /home/dev/projects/myapp/.git/worktrees/myapp-feature

# Edit the exclude file for this worktree only
echo "my-local-test-data/" >> /home/dev/projects/myapp/.git/worktrees/myapp-feature/info/exclude

# Or use git rev-parse to find it programmatically
cd ../myapp-feature
GITDIR=$(git rev-parse --git-dir)
echo "my-local-test-data/" >> "$GITDIR/info/exclude"

Rules in info/exclude work the same as .gitignore rules but are not tracked and not shared with other worktrees or other developers.

Should You .gitignore the Worktree Directory?

If you create worktrees inside the main repository directory (which is generally not recommended), those directories will show up as untracked content. You might be tempted to add them to .gitignore.

The better solution: create worktrees as sibling directories, not inside the main repo. This avoids the issue entirely.

Sibling layout avoids ignore issues
# BAD: worktree inside the main repo (causes .gitignore headaches)
~/projects/myapp/
├── .git/
├── src/
├── worktrees/              # this would show as untracked
│   └── feature-auth/
└── .gitignore              # you'd need to add "worktrees/"

# GOOD: worktrees as siblings (no .gitignore changes needed)
~/projects/
├── myapp/                  # main worktree
├── myapp-feature-auth/     # linked worktree (sibling)
└── myapp-hotfix/           # linked worktree (sibling)

If you must create worktrees inside the main repo (for example, due to tooling constraints), add the directory to .gitignore or to .git/info/exclude if you do not want to affect other developers.

Related Guides