A small tool for managing git worktrees with dedicated tmux sessions.
Each worktree lives at $TMUX_WORKTREE_DIR/<name> and is backed by a shared
bare repo at $TMUX_WORKTREE_DIR/.<repo>.git. Each worktree gets its own tmux
session, laid out however you want.
git clone https://github.com/jpugliesi/tmux-worktree ~/.tmux-worktree
echo 'export PATH="$HOME/.tmux-worktree/bin:$PATH"' >> ~/.zshrcUpdate later with git -C ~/.tmux-worktree pull.
No config needed — works out of the box:
twt create git@github.com:org/repo.git feature-xyz
twt create --shallow https://github.com/org/huge-repo.git huge-0
twt create --shallow \
--remote github=https://github.com/org/repo.git \
https://git.example.com/org/repo.git repo-0
# From repo-0, ask to create repo-1 from the same shared repository
cd "$TMUX_WORKTREE_DIR/repo-0"
twt createThis clones the repo (as a bare repo under $TMUX_WORKTREE_DIR), creates a
worktree on a new feature-xyz branch, and opens a tmux session. By default
the session has one window with one pane — customize via config (below).
--shallow (or --depth <n>) does a depth-limited bare clone, useful for
large repositories; it only applies when the bare repo does not already exist.
--remote name=url adds extra remotes on the bare repo (repeatable); the
primary URL is always origin.
When you run twt create without arguments in a numbered workspace, twt
selects the next free number and asks for confirmation. It uses the same bare
repository, remotes, fetch rules, shared-file hook, and session hook. It starts
the new workspace from the repository's default branch. It does not copy the
current branch, uncommitted files, or live tmux pane processes.
Other commands:
twt start ticket-123 # create a task branch + rename the current session
twt reset # reset panes + hard-reset branch to origin default (silent)
twt reset -v # same, but print per-step progress and git output
twt shared enable # (run inside a bare repo) enable symlinked shared filesI start tmux, then create one worktree and session per agent:
tmux
twt create --with-shared https://github.com/jpugliesi/my-repo my-repo-0
twt create https://github.com/jpugliesi/my-repo my-repo-1
twt create --with-shared https://github.com/jpugliesi/another-repo another-repo-0Each repository is cloned once. Each command creates a branch, worktree, and
tmux session with the supplied name, then switches to it. I run one agent and
task per session while tmux keeps everything alive. --with-shared enables
shared project files before the first worktree is checked out.
Once I pick a ticket, I create its branch and rename the current session:
twt start home-bugThis runs git switch -c and renames the session from its stable slot name,
such as core-4, to core-4-home-bug. twt remembers the slot name so later
branch changes do not stack session names.
My on_session_create hook creates three panes in each session. I use them
for:
- Neovim
- A shell
- A coding agent TUI
/Users/jpugliesi/code/firetiger/.core.git/shared/.lazy.lua
That shared file customizes LazyVim for the Firetiger project and is symlinked into all of its worktrees. See Shared files.
When the task is done and its work is pushed, I reset the current workspace:
twt resetThis restores the stable branch and session name, such as core-4, respawns
the other panes, and hard-resets tracked files to the origin default branch.
It does not remove untracked files.
I use tmux-resurrect to save and restore the sessions, windows, and pane layouts across tmux server restarts.
Install the twt skill for Claude Code, Codex, and other compatible agents:
npx skills add jpugliesi/tmux-worktree --skill twtOnly needed if you want a custom tmux layout or a different data directory.
mkdir -p ~/.config/tmux-worktree
curl -fsSL https://raw.githubusercontent.com/jpugliesi/tmux-worktree/main/share/config.example.sh \
> ~/.config/tmux-worktree/config.shThe example ships a three-pane work window. Edit to taste.
Available knobs:
| Variable / hook | Purpose | Default |
|---|---|---|
TMUX_WORKTREE_DIR |
Where bare repos and worktrees live | ${XDG_DATA_HOME:-$HOME/.local/share}/tmux-worktree |
on_session_create session path |
Build the tmux layout | One window, one pane |
on_worktree_create path |
Run after worktree is created | No-op |
Each bare repo can opt into a symlink-based "shared files" mechanism: any file
under <bare>.git/shared/ is symlinked into each worktree's matching path when
the worktree is checked out. Existing non-symlink files in the worktree are
never overwritten.
Useful for:
.env.local, secrets, credentials- Editor project config (e.g. LazyVim
.lazy.lua) .rgignore,.claude/settings.local.json, etc.
Enable while creating the first worktree for a repo:
twt create --with-shared git@github.com:org/repo.git repo-0Or enable it later from the bare repo:
cd "$TMUX_WORKTREE_DIR/.repo.git"
twt shared enableThen drop files into shared/. Optionally cd shared && git init to version
them in their own (separate) repo.
Disable with twt shared disable.
MIT

