Ticket-based worktree lifecycle for git: open, see, close.
One command per phase of the work. git wt 101 creates or resumes an isolated workspace for ticket WTA-101, bare git wt shows every worktree with its divergence and dirt, and git wt close 101 shows the evidence (unmerged commits, dirty files) before it merges, removes, or refuses. Integrates with the MDT (Markdown Ticket) system for automatic project code resolution.
- Lifecycle commands -
git wt(dashboard),git wt open(create/resume),git wt close(merge-aware removal),git wt path(cd handoff) - Dashboard - bare
git wtlists worktrees with branch, ahead/behind vs base, dirty count, and age - Idempotent open - existing worktree resumes with a cd hint (exit 0); a branch without a worktree gets one attached
- Evidence-first close (WTA-003) - unmerged commits trigger a merge prompt before anything is destroyed;
--merge,--merge-to <branch>,--delete-unmerged,--quiet, andworktree.wt.autoMergefor automation - Environment bootstrap - optional
worktree.wt.syncFiles(copy e.g..dev.vars) andworktree.wt.setupCmd(run e.g.bun install) on open - Smart project code detection - reads the project code from
.mdt-config.toml - Configurable ticket prefix and zero-padding - GitHub, JIRA, or custom formats
- Flexible path templates -
{worktree_name}and{project_dir}placeholders, relative or absolute
- Git 2.48+ (for
git worktree add --relative-paths) - Bash or Zsh shell
# Download, install the git-wt script to ~/.git-wt/, and register the aliases
curl -fsSL https://raw.githubusercontent.com/rikby/mdt-git-worktree-alias/main/install_aliases.sh | bashThe installer writes one implementation script to ~/.git-wt/git-wt and registers two thin aliases, git wt and git wt-rm. Re-running the installer upgrades in place.
git wt 101 # open (create or resume) WTA-101
git wt # dashboard: every worktree, divergence, dirt, age
git wt close 101 # evidence-first close with merge protectionNo configuration is required: with nothing configured, worktrees are created outside the repository at ../.git-worktrees/{project_dir}-{worktree_name} (the first run offers to remember it in your global config). To choose a different location:
git config --global worktree.wt.defaultPath ".gitWT/{worktree_name}" # inside the repo
git config --global worktree.wt.defaultPath "~/worktrees/{worktree_name}" # elsewhere, outsidegit wt 101 # open WTA-101 (reads project code from .mdt-config.toml)
git wt open WTA-101 # explicit subcommand form
git wt MDT-205 # full ticket name
# Running the same command again resumes instead of failing:
git wt 101
# ✓ worktree exists: /worktrees/my-repo-WTA-101
# branch: WTA-101
# dirty files: 0
# → cd /worktrees/my-repo-WTA-101A branch that exists without a worktree is resumed too: git wt attaches a worktree to it instead of erroring.
git wt # or: git wt list
# WORKTREE BRANCH VS main DIRTY AGE
# * my-repo main (base) 0 2d
# my-repo-WTA-101 WTA-101 ↓5 ↑1 0 3h
# my-repo-gpde-017 gpde-017-teaching-move ↓2 ↑0 17 3d↓N marks commits the base branch is ahead (stale fork — merge or rebase soon); ↑N marks unmerged work. * marks your current worktree. Stale registrations are pruned automatically.
git wt close 101 # or the legacy alias: git wt-rm 101Close evaluates before it destroys. For a branch with unmerged commits you get the evidence and one question:
Found worktree: /worktrees/my-repo-WTA-101
Branch: WTA-101
unmerged commits: 3 (not in main)
Merge branch "WTA-101" into "main" before closing? [y/N]
- y — merges into the current branch, removes the worktree, deletes the branch (safe
git branch -d) - N — cancels; worktree and branch are preserved untouched
A fully merged branch asks one confirmation (Remove worktree and branch? [y/N]) and closes in one step.
Non-interactive variants:
git wt close --merge 101 # merge into current branch, no prompt
git wt close --merge-to main 101 # merge into a specific branch, switch back
git wt close --delete-unmerged 101 # discard unmerged work (git branch -D)
git wt close --quiet 101 # no prompts; fails if merge needed but not enabled
git wt close --force 101 # remove despite uncommitted changes
git config worktree.wt.autoMerge true # always merge when unmerged commits existExit codes: 0 ok or cancelled · 1 general error · 2 merge conflict (state preserved for manual resolution) · 3 conflicting flags.
git wt path 101 # prints just the absolute path
cd "$(git wt path 101)"
# or a shell wrapper:
wt() { cd "$(git wt path "$1")"; }The default (../.git-worktrees/{project_dir}-{worktree_name}) keeps worktrees outside the repo — no .gitignore entry needed — and prefixes the repo folder name so multiple repos don't collide.
# Keep the default, or switch to:
# Inside repository (requires .gitWT/ in .gitignore)
git config --global worktree.wt.defaultPath ".gitWT/{worktree_name}"
# Outside repository (absolute path)
git config --global worktree.wt.defaultPath "~/worktrees/{worktree_name}"
# Include project directory name
git config --global worktree.wt.defaultPath "/worktrees/{project_dir}-{worktree_name}"# Files copied from the repo you run `git wt` in (if missing in the new worktree)
git config worktree.wt.syncFiles ".dev.vars .env.local"
# Command run inside the freshly created worktree
git config worktree.wt.setupCmd "bun install"Git never propagates untracked or ignored files into a new worktree — this setting does it for the files you name.
# Always fork new worktrees from a specific branch (default: current HEAD)
git config worktree.wt.baseBranch mainWhen the base is behind its upstream, git wt open prints a non-blocking notice suggesting a pull.
bats test/Example output:
137 tests, 0 failures
| Key | Purpose | Default |
|---|---|---|
worktree.wt.defaultPath |
Path template ({worktree_name}, {project_dir}) |
../.git-worktrees/{project_dir}-{worktree_name} |
worktree.wt.prefix |
Prefix for numeric tickets (with .mdt-config.toml fallback) |
— |
worktree.wt.zeroPadDigits |
Zero-padding width for ticket numbers | 3 for MDT projects |
worktree.wt.autoMerge |
true/on/yes/1 — auto-merge on close |
false |
worktree.wt.baseBranch |
Branch to fork new worktrees from | current HEAD |
worktree.wt.syncFiles |
Files copied into new worktrees if missing | — |
worktree.wt.setupCmd |
Command run inside a new worktree | — |
Legacy worktree.defaultPath (without .wt) still works via fallback; the new namespace wins.
# Already prefixed - passes through unchanged
git wt PROJ-123 # Creates PROJ-123
# Pure numeric - applies prefix and zero-padding
git wt 42 # Creates ABC-042 (with prefix="ABC-", zeroPadDigits=3)
# Text input - passes through unchanged (prefix ignored)
git wt feature-login # Creates feature-loginMIT License