Git Worktrees skill for Codex

Two branches checked out at once, no stashing. Codex creates a worktree per concurrent task, inside the repo when the sandbox only allows writes there, and gets each one runnable with its own dependencies, port and Docker project name. It knows the stash, branches and config are shared while node_modules and .env are not, and it cleans up by checking every worktree for uncommitted or unpushed work before removing anything.

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- git-worktrees

Installs to ~/.agents/skills/git-worktrees/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $git-worktrees, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Runs several branches side by side with git worktree - add, list, lock, move, remove and prune - for reviewing a PR without stashing, hotfixing a release while a feature is half done, comparing old and new behaviour, or running long test suites in parallel. Covers what worktrees share (objects, refs, stash, config) versus keep separate (index, untracked files, node_modules, .env), per-worktree setup, port and Docker collisions, sandbox-friendly locations and safe cleanup. Use when asked to work on two branches at once, set up worktrees, or clean up stale ones.

Use it when

  • You need a second branch running while your current work stays untouched
  • Reviewing or testing a PR locally mid-task
  • Comparing behaviour between main and a branch side by side
  • Stale worktrees or 'already checked out' errors need sorting out

Use something else when

How to check the result

git worktree list shows each task on its own branch or detached commit, each worktree's app or tests run on distinct ports, and cleanup removed only worktrees that were clean and pushed.

The mistake it prevents

Deleting a worktree folder with rm -rf, which strands its metadata and silently discards any uncommitted changes inside it.

~/.agents/skills/git-worktrees/SKILL.md

--- name: git-worktrees description: Runs several branches side by side with git worktree - add, list, lock, move, remove and prune - for reviewing a PR without stashing, hotfixing a… license: MIT ---

Worktrees are used well when each concurrent task has its own directory and branch, a new worktree is runnable within a minute through a repeatable setup step, nothing collides (ports, Docker project names, databases), and cleanup never deletes uncommitted or unpushed work without the user saying so.

When to reach for one

SituationWorktree?
Review or run a PR while your branch has uncommitted workYes, detached at the PR head
Urgent hotfix on a release branch mid-featureYes, new branch from the release branch
Compare behaviour between main and your branch side by sideYes, detached at origin/main
Long test or build running while you keep codingYes
Several agent tasks in parallel on one repoYes, one worktree per task
Quick look at an old version of one fileNo: git show origin/main:path/to/file
Switching branches with a clean tree and nothing runningNo: git switch is enough

Before creating

git worktree list
git status --short                 # nothing here moves into the new worktree
git fetch origin                   # needs network

Read AGENTS.md for install, env and dev-server commands; the setup step reuses them.

Where to put them

LayoutPathNotes
Inside the repo, ignored.worktrees/<name>Works inside a sandbox whose writable root is the repo. Add .worktrees/ to .git/info/exclude so it never shows as untracked
Sibling directory../<repo>-<name>Clean separation; may be outside the writable area of a Codex workspace-write sandbox, so ask for approval or use the in-repo layout
Bare-repo hubrepo/.bare plus repo/main, repo/feature-xGood for people who live in worktrees; restructure only with the user’s agreement

Tools that search for files recursively (test runners, linters, IDE indexers) may descend into .worktrees/. Exclude it in their configs if they do.

Creating

# New branch from the remote default branch
git worktree add -b fix/login-timeout .worktrees/login-timeout origin/main

# Existing local branch (must not be checked out anywhere else)
git worktree add .worktrees/release-2-4 release/2.4

# Read-only look at a commit or PR head, no branch
git worktree add --detach .worktrees/main-baseline origin/main
git fetch origin pull/123/head:pr-123 && git worktree add .worktrees/pr-123 pr-123

A branch can be checked out in only one worktree. The error '<branch>' is already checked out at '<path>' means use that worktree, use --detach, or create a new branch. Do not reach for --force to check it out twice.

Setting up a worktree to run

Untracked files do not come along. Each worktree needs its own:

cd .worktrees/login-timeout
pnpm install --frozen-lockfile        # pnpm and uv share a global store, so this is fast
cp ../../.env.example .env            # copy real secrets from the main checkout only if the user agrees
export PORT=3101                      # avoid clashing with the main checkout's dev server
export COMPOSE_PROJECT_NAME=app_login_timeout   # separate Docker containers and volumes

If the repo needs more than a couple of these steps, propose a script (scripts/worktree-setup.sh) so every worktree is set up the same way. Shared resources such as one local Postgres database still collide; use a separate database name per worktree when tests write data.

What is shared and what is not

Shared across all worktreesSeparate per worktree
Object database, branches, tags, remotesHEAD, index (staging area), working files
git stash listUntracked and ignored files: node_modules, .venv, .env, build output
Repository config and hooks (unless extensions.worktreeConfig plus git config --worktree)Bisect state, in-progress rebase or merge
rerere cacherefs/worktree/*

Consequences: a commit made in one worktree is immediately visible as a branch in the others; git stash pop in the wrong worktree applies another task’s changes; a git rebase in progress blocks only its own worktree.

Housekeeping

git worktree list --porcelain
git worktree lock --reason "on external drive" .worktrees/big-data   # protect from prune
git worktree move .worktrees/pr-123 .worktrees/pr-123-review
git worktree repair                          # after moving the main repo or a worktree by hand

Safe cleanup

Never delete a worktree directory with rm -rf; it strands metadata and can lose work. Check each candidate first:

for wt in $(git worktree list --porcelain | awk '/^worktree /{print $2}' | tail -n +2); do
  dirty=$(git -C "$wt" status --porcelain | wc -l | tr -d ' ')
  branch=$(git -C "$wt" rev-parse --abbrev-ref HEAD)
  if git -C "$wt" rev-parse -q --verify '@{u}' >/dev/null 2>&1; then
    unpushed=$(git -C "$wt" rev-list --count '@{u}..HEAD')
  else
    unpushed="no-upstream"
  fi
  echo "$wt branch=$branch dirty=$dirty unpushed=$unpushed"
done
  • Clean, pushed or merged: git worktree remove <path>.
  • Dirty, unpushed, or no upstream: show the list to the user and ask. git worktree remove --force discards uncommitted changes and needs explicit approval.
  • Directory already gone: git worktree prune removes the stale entry.
  • Delete the branch separately, and only if merged: git branch -d <branch> (lower-case -d refuses unmerged branches; -D needs approval).

Gotchas

  • Submodules are not initialised in new worktrees; run git submodule update --init --recursive inside each.
  • Editors opened on the parent directory index every worktree; open the worktree folder itself.
  • Some older tools expect .git to be a directory; in a worktree it is a file pointing to .git/worktrees/<name>. Use git rev-parse --git-dir in scripts.
  • Absolute paths in generated config (virtualenv shebangs, caches) point at the worktree that created them; do not copy .venv or node_modules between worktrees.
  • Running two dev servers or test suites against the same port, Docker project or database gives misleading failures; isolate them as above.

Output

Worktrees:
- .worktrees/login-timeout  branch fix/login-timeout (from origin/main), deps installed, PORT=3101
- .worktrees/pr-123         detached at PR #123 head, tests running
Cleanup proposed: .worktrees/old-spike (clean, merged) -> remove; .worktrees/exp (3 uncommitted files) -> kept, needs your call

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Git Worktrees"
  short_description: "Two branches checked out at once, no stashing"
  default_prompt: "$git-worktrees I'm mid-feature. Check out PR 123 in a worktree so I can run it without stashing"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc