Skip to content

Repository files navigation

wktree

git worktree + Kitty or tmux for one or multiple repos.

Motivation

  • I work in Kitty + neovim. Terminal is my IDE. I like to use git worktree to isolate work across features and PRs.
  • More than often, I need to work across multiple repos for one feature (e.g. backend + frontend).
  • Inspired by workmux, but I needed multi-repo support.

Disclaimer

  • Looks like vibe coded? : Yes. Good vibes only.

  • Do you even use this? : Yes, daily.

Install

Homebrew (recommended)

brew tap alienxp03/tap
brew install wktree

Go

go install github.com/alienxp03/wktree/cmd/wktree@latest

Setup

wktree init

Creates .wktree.yaml in the current directory. wktree searches from cwd up to the Git root and uses the nearest config.

Single-repo

worktree_dir: ~/worktree
terminal:
  session_name: "${repo}/${branch}"
workspace_mode: single

workspaces:
  - name: backend
    files:
      copy:
        - .env.backend
      symlink:
        - .tool-versions
    hooks:
      post_create:
        - direnv allow
    panes:
      - command: nvim
        focus: true
      - commands:
          - pnpm install
          - pnpm run dev
        split: horizontal
      - command: codex
        split: vertical

Multi-repo

worktree_dir: ~/worktree
workspace_mode: all

defaults:
  files:
    copy:
      - .env
    symlink:
      - AGENTS.override.md

workspaces:
  - name: backend
    files:
      copy:
        - .env.backend
    hooks:
      post_create:
        - direnv allow
    randomize_ports:
      - file: .env.local
        vars:
          - PORT
          - APP_PORT
    set_env:
      - file: .env.local
        vars:
          API_URL: "http://localhost:${backend:.env.local:PORT}/api"
    open:
      - "http://localhost:${backend:.env.local:PORT}/api"
    panes:
      - command: nvim
        focus: true
      - commands:
          - pnpm install
          - pnpm run dev
        split: horizontal

  - name: frontend
    repo: ~/workspace/frontend
    files:
      copy:
        - .env.frontend
    hooks:
      post_create:
        - pnpm install
    panes:
      - command: nvim
        focus: true
      - command: pnpm run dev
        split: horizontal

Default workspace subset

Use selected to target only named workspaces by default. The workspace order still comes from workspaces; --workspaces overrides this selection and targets all configured workspaces.

workspace_mode: selected
default_workspaces:
  - backend
  - worker

workspaces:
  - name: backend
  - name: frontend
    repo: ~/workspace/frontend
  - name: worker
    repo: ~/workspace/worker

Config reference

Top-level

Key Description
worktree_dir Where worktrees are stored. Default ~/workspace/worktrees.
terminal.provider Terminal provider: kitty (default) or tmux. Set provider: tmux to opt in to tmux layouts.
terminal.mode Tmux-only: window (default) creates a window in the current session; session creates a tmux session.
terminal.session_name Layout/session name template. Supports ${owner}, ${repo}, ${branch}, ${dir}, and ${dir:N}. Default ${repo}/${branch}.
integrations.zoxide When true, adds every selected worktree path to zoxide during new and switch.
workspace_mode single uses the first workspace, all uses every workspace, and selected uses default_workspaces. --workspaces always targets all configured workspaces.
default_workspaces Workspace names targeted by default when workspace_mode is selected.
defaults Shared config applied to every workspace before workspace-level config.
workspaces Ordered list of workspaces.

${dir} is the directory containing .wktree.yaml; ${dir:1} is its parent, ${dir:2} is the next parent, and so on.

Workspace

Key Description
name Workspace identifier. Used for tmux window / Kitty tab names and env variable names.
repo Path to the Git repo. Omit to use the directory containing .wktree.yaml.
files.copy Copy files into the new worktree (isolated per worktree).
files.symlink Symlink files from the source repo (shared across worktrees).
hooks.post_create Commands to run after worktree creation, before the terminal layout opens.
randomize_ports Replaces named env vars with available localhost ports.
set_env Sets env variables with template references like ${workspace:file:VAR}.
open Opens URLs after setup completes. Uses the same template references as set_env.
panes Terminal panes/windows. Each has command or commands, optional split (horizontal/vertical), percentage, and focus. Each new pane splits the immediately preceding pane. Kitty maps horizontal to vsplit, vertical to hsplit, and percentage to bias; Kitty rejects tmux-only size and zoom.

Workspace env

When a workspace is created or switched, wktree writes .wktree.env with one variable per workspace:

export WKTREE_BACKEND_DIR='/Users/stan/worktree/org/backend/feature-example'
export WKTREE_FRONTEND_DIR='/Users/stan/worktree/org/frontend/feature-example'

Pane commands and post_create hooks source this file before running. PR worktrees also include WKTREE_PR_NUMBER, WKTREE_PR_URL, WKTREE_PR_HEAD_REF, and WKTREE_PR_HEAD_SHA.

Usage

wktree init                       Create starter config
wktree doctor                     Check repo, config, and configured terminal provider

wktree list                       List worktrees
wktree list --pr                  List worktrees with PR info
wktree cleanup                    Remove merged worktree branches after confirmation
wktree cleanup --dry-run          Preview merged worktree branch cleanup

wktree new <branch>               Create branch + worktree + terminal layout
wktree new --from <ref> <branch>  Create from a specific ref
wktree new --workspaces <branch>  Create across all workspaces

wktree switch <branch>            Open existing worktree in the configured terminal
wktree switch --pr <number|url>   Open a GitHub PR locally

wktree close <branch>             Close terminal layout (keeps worktree)
wktree remove <branch>            Close layout + remove worktree + delete branch
wktree remove --pr <number|url>   Remove by GitHub PR head branch

Common flags: --dry-run to preview, --force to override safety checks, --workspaces to target all configured workspaces (including those excluded by default_workspaces). When removing across all workspaces, --force skips workspaces where the local branch is already gone. Use wktree cleanup --yes to skip the confirmation prompt after reviewing the cleanup behavior.

Worktree paths follow <worktree_dir>/<owner>/<repo>/<branch>. For GitHub remotes, owner and repo come from the remote URL. wktree switch <branch> reuses an existing worktree at that path even if you changed the checked-out branch inside it after creation.

Terminal providers

Kitty is the default and requires no provider setting:

terminal:
  session_name: "${repo}/${branch}"

Kitty creates one generated session per branch, with each workspace as a tab and each configured pane as a Kitty window. Run wktree inside Kitty, or set KITTY_LISTEN_ON to a Kitty remote-control socket. Existing generated sessions are focused instead of duplicated. Session files are stored under the user cache directory; no Kitty dotfiles or socket paths are modified.

Opt in to tmux explicitly:

terminal:
  provider: tmux
  mode: window
  session_name: "${repo}/${branch}"

To make worktrees available to zoxide-backed project pickers such as Cmd+Shift+O:

integrations:
  zoxide: true

This runs zoxide add -- <workspace-path>... after setup on both new and switch.

Shell integration

Completion-only:

eval "$(wktree completion zsh)"   # or bash

Development

make build                        # build to dist/
make install                      # install to ~/.local/bin/wktree
make lint test                    # lint and test

Troubleshooting

  • tmux window mode requires running inside tmux — start tmux first or use terminal.mode: session.
  • Kitty remote-control errors — run inside Kitty, or configure Kitty remote control and pass its socket through KITTY_LISTEN_ON.
  • gh is required for --pr — install and authenticate the GitHub CLI.
  • branch is not merged — merge first, check whether the local branch has commits beyond the merged PR head, or use --force. For merged GitHub PRs, wktree may fetch the PR head ref to verify local branches that do not have the merged PR commit locally yet.
  • wktree doctor — run this first when something looks wrong.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages