Git worktree missing .env and node_modules? Copy them in
On this page
  1. What a new worktree is missing
  2. Step 1: copy the ignored files you need
  3. With Claude Code
  4. With any other agent, or plain git
  5. Step 2: bring node_modules over
  6. Step 3: give each worktree its own port
  7. Put it in one script
  8. Step 4: clean up
  9. Where Joxo fits
  10. Frequently asked questions
  11. Why is my .env missing in a git worktree?
  12. Can git worktrees share node_modules?
  13. How do I remove a locked git worktree?
  14. Try it with your team

Blog / git worktrees

Git worktree missing .env and node_modules? Copy them in

A new git worktree has no .env, no node_modules and no spare port. Copy the ignored files, clone the install in a second, and give each worktree its own port.

A new git worktree is a clean checkout of your tracked files and nothing else. Your .env, node_modules, build caches and local config are all gitignored, so none of them come along. An agent started there runs the dev server, finds no database URL and no packages, and spends its first ten minutes installing and guessing.

The fix is three steps you do once per worktree: copy the ignored files you need, bring the install over (fast), and give the worktree its own port. Below is each step, then the cleanup, with every command tested on a real repo.

What a new worktree is missing#

Make a worktree and look inside:

bash
git worktree add ../shop-fix -b fix/cart
ls -a ../shop-fix

You get .git, .gitignore, package.json and the rest of your tracked files. You don't get:

MissingWhy it matters
.env, .env.localThe app starts without its database URL or keys
node_modulesEvery command fails until someone installs
Local config (config/secrets.json and similar)Tests read the wrong settings
A port of its ownTwo dev servers both want port 3000

The worktree also shares one thing you might not expect: the .git directory. Commits, branches and stashes are shared across all worktrees of a repository.

Step 1: copy the ignored files you need#

With Claude Code#

Claude Code reads a .worktreeinclude file at the root of your repository. It uses .gitignore syntax and lists the ignored files to copy into every worktree Claude Code creates:

.env
.env.local
config/secrets.json

Only files that match a pattern and are gitignored are copied, so tracked files are never duplicated. It applies to claude --worktree <name>, to subagents that run in their own worktree, and to parallel sessions in the desktop app. We checked it with claude -p --worktree test: the new worktree under .claude/worktrees/test had the .env from the main checkout. The Claude Code worktree docs have the details.

Commit .worktreeinclude so everyone on the team gets the same list. Add .claude/worktrees/ to .gitignore so those worktrees don't show up as untracked files.

With any other agent, or plain git#

The same file works for worktrees you make yourself. From the main checkout, this copies every untracked file that matches .worktreeinclude into the new worktree:

bash
git ls-files -z --others --ignored --exclude-from=.worktreeinclude \
  | xargs -0 -I{} cp -p {} ../shop-fix/{}

Run the first line alone to see the list before copying. If a file sits in a folder the worktree doesn't have yet, create the folder first.

Step 2: bring node_modules over#

You have two honest choices.

Install again. npm ci (or pnpm install, yarn install --frozen-lockfile) in the worktree gives you a clean, correct install. With pnpm it is quick, because packages come from one store on disk.

Clone the install you already have (macOS). On APFS, cp -c makes a copy-on-write clone: it takes almost no time and almost no disk until a file changes.

bash
cp -cR node_modules ../shop-fix/

On our test repo this took 0.03 seconds. Only do this when the worktree's lockfile matches the main checkout's. If the branch changes dependencies, install again.

Don't symlink node_modules between worktrees. It looks like a shortcut, but an install in one worktree then changes the packages under another agent mid-run, and some tools resolve the symlink back to the main checkout and load the wrong copy of your own code.

Step 3: give each worktree its own port#

Most dev servers read a PORT variable. Pick one per worktree and keep it there:

bash
echo "PORT=3001" >> ../shop-fix/.env.local

Do the same for anything else two copies of your app can't share: a local database name, a cache directory, a test server. Two agents migrating one local database break each other as surely as two agents editing one file.

Put it in one script#

Once the steps work, make them one command so neither you nor an agent skips one. Save this as scripts/wt.sh:

bash
#!/bin/sh
# usage: scripts/wt.sh <branch> <port>
set -e
branch="${1:?give a branch name}"
port="${2:?give a port}"
dir="../$(basename "$PWD")-$branch"
git worktree add "$dir" -b "$branch"
git ls-files -z --others --ignored --exclude-from=.worktreeinclude \
  | xargs -0 -I{} cp -p {} "$dir/{}"
(cd "$dir" && npm ci --silent)
echo "PORT=$port" >> "$dir/.env.local"
echo "$dir"

Then tell the agent in your CLAUDE.md or AGENTS.md: "Start new work with scripts/wt.sh <branch> <port> and work in the folder it prints."

Step 4: clean up#

When the branch has landed:

bash
git worktree remove ../shop-fix
git branch -d fix/cart

Ignored files such as .env and node_modules don't block the removal; uncommitted changes to tracked files do, which is the safety you want.

Two things trip people up:

  • "cannot remove a locked working tree": Claude Code locks the worktrees it creates. An interactive session cleans up when you exit, but a claude -p --worktree run leaves its lock in place. Once that session has ended, run git worktree unlock <path>, then git worktree remove <path>.
  • Folders you deleted by hand: git worktree prune forgets worktrees whose folder is gone.

git worktree list shows everything that is left.

Where Joxo fits#

Worktrees keep files apart on one computer. When the agents belong to different people, Joxo gives them one task board and tells an agent when a teammate's agent is already working on the same task or files. Setup is one line pasted into each agent. For running several sessions on one machine, see run parallel Claude Code sessions.

Frequently asked questions#

Why is my .env missing in a git worktree?#

A worktree only contains tracked files, and .env is gitignored. Copy it in: Claude Code does it for you when the file is listed in .worktreeinclude, and for other worktrees the git ls-files --others --ignored command above copies the same list.

Can git worktrees share node_modules?#

Not safely by symlink. Install in each worktree, or on macOS clone the install with cp -cR node_modules <worktree>/, which is near-instant and uses almost no disk until files change.

How do I remove a locked git worktree?#

Make sure no session is still using it, then run git worktree unlock <path> and git worktree remove <path>. Claude Code locks the worktrees it creates, and non-interactive runs leave the lock behind.