A CLI tool for managing git worktrees with plugin support
npm install @jescalan/wtA CLI tool for managing git worktrees with a plugin system for extensibility.
``bashInstall globally
npm install -g @jescalan/wt
Commands
All commands have short aliases for faster typing:
| Command | Alias | Description |
| -------- | ----- | ----------------------------- |
|
create | c | Create a new worktree |
| merge | m | Merge and clean up |
| search | s | Interactive worktree selector |
| list | l | List all worktrees |
| remove | rm | Remove a worktree |
| status | st | Show worktree overview |$3
Create a new worktree with a branch.
`bash
wt create feature-auth
wt c feature-auth # Short form
`This will:
1. Create a new worktree at the configured path (default:
../{repo}-{branch})
2. Create a new branch (or use existing if it exists)
3. Copy gitignored files from the current worktree (configurable)
4. Run any configured beforeCreate/afterCreate hooks$3
Merge the current worktree's branch into the default branch and clean up.
`bash
wt merge # Merge, remove worktree, delete branch
wt merge -k # Merge but keep worktree and branch
wt m # Short form
`This will:
1. Switch to the main worktree
2. Merge the current branch
3. Remove the worktree and delete the branch (unless
--keep)
4. Run any configured hooksOn merge failure (conflicts, uncommitted changes), you'll be returned to your original worktree with a clear error message.
$3
Interactively select and switch between worktrees.
`bash
wt search
wt s # Short form
`Use arrow keys to navigate, Enter to select, q/Escape to cancel.
$3
List all worktrees with status information.
`bash
wt list
wt l # Short form
`Output example:
`
* main /path/to/repo (default)
feature-auth /path/to/repo-feature 2 ahead, 1 behind
bugfix-xyz /path/to/repo-bugfix 3 uncommitted
`Shows:
- Current worktree marked with
*
- Default branch marked with (default)
- Ahead/behind count compared to default branch
- Count of uncommitted changes$3
Remove a worktree with confirmation.
`bash
wt remove feature-auth # Remove specific worktree
wt remove # Interactive selection
wt rm -f feature-auth # Skip confirmation prompt
`Options:
-
-f, --force: Skip the confirmation promptThe default branch worktree cannot be removed.
$3
Show a detailed overview of all worktrees.
`bash
wt status
wt st # Short form
`Output example:
`
Repository: my-project
Default branch: main (3 worktrees)┌─────────────────┬──────────────────────────────┬─────────────┐
│ Branch │ Path │ Status │
├─────────────────┼──────────────────────────────┼─────────────┤
│ main │ ~/code/my-project │ clean │
│ feature-auth │ ~/code/my-project-feature │ 2 modified │
│ bugfix-xyz │ ~/code/my-project-bugfix │ 1 ahead │
└─────────────────┴──────────────────────────────┴─────────────┘
`Shell Integration
Add one line to your shell config to enable automatic directory changing:
Zsh (
~/.zshrc):`bash
eval "$(wt init zsh)"
`Bash (
~/.bashrc):`bash
eval "$(wt init bash)"
`Fish (
~/.config/fish/config.fish):`fish
wt init fish | source
`Configuration
Create a
wt.config.ts file in your project root (or any parent directory):`typescript
import type { WtConfig } from "@jescalan/wt/types";export default {
// Copy gitignored files when creating worktrees (default: true)
copyGitIgnoredFiles: true,
// Worktree path pattern (default: "../{repo}-{branch}")
// Variables: {repo}, {branch}, {parent}
worktreePath: "../{repo}-{branch}",
// Plugins to load
plugins: [],
// Hooks - can be commands, functions, or arrays of both
hooks: {
// Run npm install after creating a worktree
afterCreate: "npm install",
// Run tests before merging
beforeMerge: "npm test",
},
} satisfies WtConfig;
`$3
Customize where worktrees are created using these variables:
-
{repo} - Repository name
- {branch} - Branch name
- {parent} - Parent directory of the repository rootExamples:
`typescript
// Default: ../my-project-feature-auth
worktreePath: '../{repo}-{branch}',// All worktrees in a dedicated folder: ../worktrees/feature-auth
worktreePath: '../worktrees/{branch}',
// In parent's parent directory: ../../my-project-feature-auth
worktreePath: '../../{repo}-{branch}',
`You can also use
wt.config.js or wt.config.mjs.$3
Hooks support three formats:
`typescript
// 1. Shell command string
afterCreate: 'npm install',// 2. Function
afterCreate: async (ctx) => {
ctx.logger.info('Installing dependencies...');
await ctx.exec('npm install');
},
// 3. Array of commands and/or functions (run in sequence)
afterCreate: [
'npm install',
'npm run db:migrate',
async (ctx) => ctx.logger.success('Ready!'),
],
`Commands run in the worktree directory and log their output. If a command fails, subsequent items in the array are skipped, but other hooks continue.
Plugin System
Plugins can hook into the worktree lifecycle to perform custom actions.
$3
| Hook | When it runs |
| -------------- | ---------------------------------------------- |
|
beforeCreate | Before creating a new worktree |
| afterCreate | After worktree is created and files are copied |
| beforeMerge | Before merging into the default branch |
| afterMerge | After successful merge |
| beforeRemove | Before removing a worktree |
| afterRemove | After worktree and branch are removed |$3
Every hook receives a context object:
`typescript
interface HookContext {
repoRoot: string; // Git repository root
defaultBranch: string; // e.g., 'main' or 'master'
branchName: string; // Branch being operated on
worktreePath: string; // Path to the worktree
sourceWorktree?: string; // Source worktree (for create)
targetWorktree?: string; // Target worktree (for merge)
logger: Logger; // Logging utilities
exec: (cmd: string) => Promise; // Run shell commands
}
`$3
`typescript
import type { WtPlugin } from "@jescalan/wt/types";export function myPlugin(options = {}): WtPlugin {
return {
name: "my-plugin",
hooks: {
afterCreate: async (ctx) => {
ctx.logger.info("Worktree created!");
// Run a command
const result = await ctx.exec("npm install", { cwd: ctx.worktreePath });
if (result.exitCode !== 0) {
ctx.logger.warn("npm install failed");
}
},
beforeRemove: async (ctx) => {
ctx.logger.info(
Cleaning up ${ctx.branchName});
},
},
};
}
`$3
`typescript
// wt.config.ts
import { myPlugin } from "./plugins/my-plugin";export default {
plugins: [
myPlugin({
/ options /
}),
],
};
`Example Plugins
$3
Automatically create/delete Neon database branches with worktrees:
`typescript
// wt.config.ts
import { neonPlugin } from "@jescalan/wt/plugins/neon";export default {
plugins: [
neonPlugin({
projectIdEnvVar: "NEON_PROJECT_ID", // env var or .env key
envFile: ".env", // path to .env file
parentBranch: "current", // 'main', 'current', or branch name
}),
],
};
`The plugin will:
- Create a Neon branch when you create a worktree
- Update
DATABASE_URL in the new worktree's .env
- Delete the Neon branch when you merge/remove the worktreeParent branch options:
-
'main' (default): Branch from Neon's primary branch
- 'current': Branch from the current git branch's Neon branch (inherits migrations/data)
- 'branch-name': Branch from a specific named Neon branchRequires the Neon CLI to be installed.
$3
Automatically update Codex session paths when worktrees are removed:
`typescript
// wt.config.ts
import { codexPlugin } from "@jescalan/wt/plugins/codex";export default {
plugins: [
codexPlugin({
codexHome: "~/.codex", // optional, defaults to $CODEX_HOME or ~/.codex
}),
],
};
`$3
Automatically migrate Claude Code sessions when worktrees are removed:
`typescript
// wt.config.ts
import { claudePlugin } from "@jescalan/wt/plugins/claude";export default {
plugins: [
claudePlugin({
claudeHome: "~/.claude", // optional, defaults to ~/.claude
}),
],
};
`Claude Code stores conversation history in
~/.claude/projects/ using encoded paths as directory names (e.g., /Users/jeff/Sites/wt becomes -Users-jeff-Sites-wt). When you remove a worktree, those sessions would become orphaned.This plugin moves session files from the worktree's project directory to the target worktree's directory, preserving your conversation history. If there are filename collisions, the migrated files are renamed with a branch suffix.
Requirements
- Git 2.5+ (for worktree support)
- Node.js 18+
Development
`bash
Install dependencies
bun installBuild
bun run buildRun tests
bun testType check
bun run typecheck
``MIT