Skip to content
/ wt Public

An extensible CLI tool for worktree management

Notifications You must be signed in to change notification settings

jescalan/wt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

wt

A CLI tool for managing git worktrees with a plugin system for extensibility.

Installation

# Install globally
npm install -g @jescalan/wt

# Or run directly with npx
npx @jescalan/wt <command>

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

wt create <name> (alias: c)

Create a new worktree with a branch.

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

wt merge (alias: m)

Merge the current worktree's branch into the default branch and clean up.

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 hooks

On merge failure (conflicts, uncommitted changes), you'll be returned to your original worktree with a clear error message.

wt search (alias: s)

Interactively select and switch between worktrees.

wt search
wt s  # Short form

Use arrow keys to navigate, Enter to select, q/Escape to cancel.

wt list (alias: l)

List all worktrees with status information.

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

wt remove [name] (alias: rm)

Remove a worktree with confirmation.

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 prompt

The default branch worktree cannot be removed.

wt status (alias: st)

Show a detailed overview of all worktrees.

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):

eval "$(wt init zsh)"

Bash (~/.bashrc):

eval "$(wt init bash)"

Fish (~/.config/fish/config.fish):

wt init fish | source

Configuration

Create a wt.config.ts file in your project root (or any parent directory):

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;

Worktree Path Pattern

Customize where worktrees are created using these variables:

  • {repo} - Repository name
  • {branch} - Branch name
  • {parent} - Parent directory of the repository root

Examples:

// 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.

Hook Formats

Hooks support three formats:

// 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.

Available Hooks

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

Hook Context

Every hook receives a context object:

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<ExecResult>; // Run shell commands
}

Writing a Plugin

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}`);
      },
    },
  };
}

Using Plugins

// wt.config.ts
import { myPlugin } from "./plugins/my-plugin";

export default {
  plugins: [
    myPlugin({
      /* options */
    }),
  ],
};

Example Plugins

Neon Database Branching

Automatically create/delete Neon database branches with worktrees:

// 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 worktree

Parent 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 branch

Requires the Neon CLI to be installed.

PlanetScale Database Branching

Automatically create/delete PlanetScale database branches with worktrees:

// wt.config.ts
import { planetscalePlugin } from "@jescalan/wt/plugins/planetscale";

export default {
  plugins: [
    planetscalePlugin({
      databaseEnvVar: "PLANETSCALE_DATABASE", // env var or .env key for database name
      orgEnvVar: "PLANETSCALE_ORG", // env var or .env key for org (optional)
      envFile: ".env", // path to .env file
      parentBranch: "current", // 'main', 'current', or branch name
    }),
  ],
};

The plugin will:

  • Create a PlanetScale branch when you create a worktree
  • Generate a password and update DATABASE_URL in the new worktree's .env
  • Delete the PlanetScale branch when you merge/remove the worktree

Parent branch options:

  • 'main' (default): Branch from PlanetScale's primary branch
  • 'current': Branch from the current git branch's PlanetScale branch (inherits schema/data)
  • 'branch-name': Branch from a specific named PlanetScale branch

Requires the PlanetScale CLI to be installed and authenticated.

Codex Session Migration

Automatically update Codex session paths when worktrees are removed:

// wt.config.ts
import { codexPlugin } from "@jescalan/wt/plugins/codex";

export default {
  plugins: [
    codexPlugin({
      codexHome: "~/.codex", // optional, defaults to $CODEX_HOME or ~/.codex
    }),
  ],
};

Claude Code Session Migration

Automatically migrate Claude Code sessions when worktrees are removed:

// 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

# Install dependencies
bun install

# Build
bun run build

# Run tests
bun test

# Type check
bun run typecheck

License

MIT

About

An extensible CLI tool for worktree management

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published