diff --git a/README.md b/README.md index 6d60793..36374ff 100644 --- a/README.md +++ b/README.md @@ -1,379 +1,136 @@ -# Worktree CLI - -A modern CLI for managing git worktrees that enables parallel AI coding assistants and simultaneous multi-branch development. - -## Why Git Worktrees? +[![npm version](https://img.shields.io/npm/v/@fnebenfuehr/worktree-cli.svg)](https://www.npmjs.com/package/@fnebenfuehr/worktree-cli) +[![license](https://img.shields.io/npm/l/@fnebenfuehr/worktree-cli.svg)](https://github.com/fnebenfuehr/worktree-cli/blob/main/LICENSE) -Git worktrees allow you to have multiple working directories for a single repository, making it easy to: - -- Work on multiple branches simultaneously without switching contexts -- Isolate AI agent environments for safe parallel development without context conflicts -- Run tests on one branch while developing on another -- Review pull requests without disrupting your current work -- Keep your main branch clean and always deployable +# Worktree CLI -## Features +Git worktree management for AI coding assistants. Enables parallel development across multiple branches without context switching. -- **Easy Setup**: Clone repos directly into worktree-ready structure or convert existing repos -- **Simple Workflow**: Create, switch, and manage worktrees with intuitive commands -- **Smart Defaults**: Automatically detects default branches and handles edge cases -- **Lifecycle Hooks**: Automate setup/teardown with configurable post-create, pre-remove, and post-remove hooks -- **File Management**: Copy files from main worktree (env files, configs, etc.) -- **Safety First**: Prevents data loss with uncommitted change detection and unmerged branch warnings -- **AI Integration**: MCP server support - let AI assistants manage worktrees for parallel development +## Why? -## Installation +AI coding assistants work best with isolated contexts. Git worktrees give each task its own directory—no stashing, no branch switching, no conflicts. Your AI can work on a feature while you review a PR in another worktree. -### Global Installation (npm) +## Quick Start ```bash +# Install npm install -g @fnebenfuehr/worktree-cli -``` - -### Global Installation (Bun) - -```bash -bun install -g @fnebenfuehr/worktree-cli -``` - -## Usage - -### Repository Setup - -#### Clone a New Repository - -Clone a repository directly into a worktree-ready structure: - -```bash -worktree clone git@github.com:user/my-app.git -``` - -This creates a directory structure like: - -``` -my-app/ -└── main/ # or whatever the default branch is - ├── .git/ - ├── src/ - └── ... -``` - -#### Convert Existing Repository - -Convert an existing cloned repository to use worktrees: - -```bash -cd my-existing-repo -worktree setup -``` - -This reorganizes your repository into: - -``` -parent-dir/ -└── main/ # your existing clone - ├── .git/ - ├── src/ - └── ... -``` - -### Branch Management - -#### Create a New Worktree - -Create a new worktree for a branch: - -```bash -worktree create feature/new-feature -``` - -This: -1. Creates the branch if it doesn't exist (from `origin/main`) -2. Creates a new worktree directory -3. Copies configured files (if `.worktreerc` exists) -4. Runs post-create hooks (if configured) +# Convert existing repo to worktree structure +cd your-project && worktree setup -Your structure becomes: - -``` -my-app/ -├── main/ -└── feature-new-feature/ # slashes converted to dashes +# Create a feature worktree +worktree create feat/new-feature ``` -#### Switch Between Worktrees - -Quickly switch to an existing worktree: - -```bash -worktree switch feature/new-feature -# Shows the cd command to navigate to the worktree -``` - -**Interactive mode:** -```bash -worktree switch -# Shows a list of all worktrees to choose from -``` - -#### Remove a Worktree - -Remove a worktree when you're done: - -```bash -worktree remove feature/new-feature -``` +See [docs/QUICKSTART.md](./docs/QUICKSTART.md) for detailed setup guide. -#### List All Worktrees +## MCP Integration -See all active worktrees: +Add to your Claude Code or AI assistant config: -```bash -worktree list +```json +{ + "mcpServers": { + "worktree": { + "command": "npx", + "args": ["-y", "@fnebenfuehr/worktree-cli", "mcp"] + } + } +} ``` -## Configuration & Hooks - -A `.worktree.json` config file is automatically created when you run `worktree clone` or `worktree setup`. You can also create one manually: +Your AI assistant can now: +- Check worktree status before modifications +- Create isolated worktrees for features/fixes +- Switch between work contexts +- Checkout PRs for review +- Clean up merged branches + +### MCP Tools + +| Tool | Description | +|------|-------------| +| `worktree_status` | Check if repo uses worktrees, current branch, default branch | +| `worktree_list` | List all worktrees with branches and paths | +| `worktree_create` | Create new worktree with branch | +| `worktree_checkout` | Intelligent checkout: switch/create from local/remote | +| `worktree_pr` | Checkout GitHub PR by number or URL | +| `worktree_switch` | Switch to existing worktree | +| `worktree_remove` | Remove worktree (with merge safety checks) | +| `worktree_setup` | Convert repo to worktree structure | + +## CLI Commands + +| Command | Description | +|---------|-------------| +| `worktree clone ` | Clone repo into worktree-ready structure | +| `worktree setup` | Convert existing repo to worktrees | +| `worktree create ` | Create worktree and branch | +| `worktree checkout ` | Smart checkout: switch or create from local/remote | +| `worktree pr ` | Checkout PR branch | +| `worktree switch [branch]` | Switch to worktree (interactive if no branch) | +| `worktree list` | List all worktrees | +| `worktree remove ` | Remove worktree | +| `worktree update` | Update CLI to latest version | + +## Configuration + +Create `.worktree.json` in your repo root (auto-generated by `setup`/`clone`): ```json { "defaultBranch": "main", - "post_create": ["bun install"], + "post_create": ["npm install"], "pre_remove": ["docker compose down"], - "copy_files": [".env", "apps/web/.env.local"] + "copy_files": [".env", ".env.local"] } ``` -**Configuration options:** -- `defaultBranch` - The default branch name (auto-detected during setup) -- `post_create` - Commands to run after creating a worktree -- `pre_remove` - Commands to run before removing a worktree -- `post_remove` - Commands to run after removing a worktree -- `copy_files` - Files to copy from main worktree when creating new worktrees - -**See [docs/hooks.md](./docs/hooks.md) for complete configuration guide and examples.** - -## AI Assistant Integration - -Enable AI assistants to manage worktrees via MCP: - -```bash -worktree mcp config # Show config for Claude Desktop/Cody/Cursor -worktree mcp test # Verify setup -``` - -After adding the config to your AI assistant and restarting, your AI can create isolated worktrees for features, experiments, or parallel work. - -## Command Reference - -### `worktree clone ` - -Clone a repository into a worktree-ready structure. - -**Arguments:** - -- `git-url` - The git repository URL (SSH or HTTPS) - -**Example:** - -```bash -worktree clone git@github.com:vercel/next.js.git -``` - -### `worktree setup` - -Convert an existing git repository to use worktrees. - -**Requirements:** - -- Must be run from the root of a git repository -- Repository must not already be in worktree structure - -**Example:** - -```bash -cd my-project -worktree setup -cd main # your repository is now in the 'main' subdirectory -``` - -### `worktree create ` - -Create a new git worktree and branch. - -**Arguments:** - -- `branch` - The branch name (can include slashes, e.g., `feature/login`) - -**Behavior:** - -- Creates the branch from `origin/main` (or detected default branch) if it doesn't exist -- Creates worktree directory with slashes replaced by dashes -- Copies configured files and runs post-create hooks (if configured) - -**Options:** -- `-i, --interactive` - Interactive mode with prompts -- `--no-hooks` - Skip running lifecycle hooks - -**Example:** - -```bash -worktree create feature/user-auth -# Creates: ../feature-user-auth/ -``` - -### `worktree remove ` - -Remove an existing git worktree. - -**Arguments:** - -- `branch` - The branch name to remove - -**Behavior:** -- Runs pre-remove hooks before deletion (if configured) -- Removes the worktree and cleans up git references -- Runs post-remove hooks after deletion (if configured) - -**Options:** -- `-i, --interactive` - Interactive mode with confirmation prompt -- `--no-hooks` - Skip running lifecycle hooks -- `-f, --force` - Force removal, bypass safety checks - -**Safety:** - -- Cannot remove main worktree (first worktree in list) -- Prevents removal if worktree has uncommitted changes (unless `--force`) -- Prevents removal if branch is not merged to default branch (unless `--force`) - - Interactive mode: warns and prompts for confirmation - - Non-interactive mode: fails with error - -**Examples:** - -```bash -# Remove a worktree -worktree remove feature/user-auth - -# Force remove even with uncommitted changes or unmerged branch -worktree remove feature/user-auth --force -``` - -### `worktree switch [branch]` - -Switch to an existing worktree. - -**Arguments:** -- `branch` - The branch name to switch to (optional - interactive mode if omitted) - -**Behavior:** -- Shows the `cd` command to navigate to the worktree directory - -**Example:** -```bash -worktree switch feature/user-auth -# Shows: cd /path/to/feature-user-auth - -worktree switch -# Opens interactive selection menu -``` - -### `worktree list` - -List all active worktrees for the current repository. - -**Example:** - -```bash -worktree list -# Output: -# /path/to/project/main abc123 [main] -# /path/to/project/feature def456 [feature/new-feature] -``` - -### Global Flags +| Option | Description | +|--------|-------------| +| `defaultBranch` | Base branch for new worktrees | +| `post_create` | Commands to run after creating worktree | +| `pre_remove` | Commands to run before removing worktree | +| `post_remove` | Commands to run after removing worktree | +| `copy_files` | Files to copy from main worktree | -- `--verbose` - Enable verbose/debug output -- `--help`, `-h` - Show help message -- `--version`, `-v` - Show version number +Hooks receive environment variables: `WORKTREE_PATH`, `WORKTREE_BRANCH`, `WORKTREE_MAIN_PATH`. -## Workflow Examples +## Comparison -### Starting Fresh +| Task | Manual Git | Worktree CLI | +|------|------------|--------------| +| Create feature branch | `git worktree add -b feat/x ../feat-x origin/main` | `worktree create feat/x` | +| Switch context | `cd ../other-worktree` | `worktree switch other` | +| Setup new repo | Multiple commands + directory management | `worktree clone ` | +| Post-create setup | Manual: install deps, copy .env | Automatic via hooks | +| PR review | Stash → checkout → review → checkout → pop | `worktree pr 123` | +| AI integration | Manual git commands | Native MCP server | -```bash -# Clone a new project -worktree clone git@github.com:user/amazing-app.git -cd amazing-app/main - -# Create a feature branch -worktree create feature/authentication -cd ../feature-authentication - -# Do your work... -git add . -git commit -m "Add authentication" -git push +## Directory Structure -# Switch back to main -worktree switch main -cd /path/shown/by/switch +After setup, your repo looks like: -# When done with feature, remove the worktree -worktree remove feature/authentication ``` - -### Converting Existing Repo - -```bash -# You have an existing project -cd ~/projects/my-app - -# Convert it to use worktrees -worktree setup - -# Move into the main worktree -cd main - -# Create a feature branch -worktree create feature/new-ui -cd ../feature-new-ui +project/ +├── main/ # default branch worktree +├── feat-auth/ # feature worktree +└── fix-bug/ # bugfix worktree ``` -### Multiple Features Simultaneously +Each directory is a complete working copy with shared git history. -```bash -# Work on multiple features at once -worktree create feature/frontend -worktree create feature/backend -worktree create feature/tests - -# Switch between them easily -worktree switch feature/frontend # Work on UI -worktree switch feature/backend # Work on API -worktree switch feature/tests # Run tests - -# Or use interactive mode to choose -worktree switch - -# View all your worktrees -worktree list -``` - -## Contributing +## Documentation -Contributions are welcome! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines. +- [Quick Start Guide](./docs/QUICKSTART.md) +- [AI Coding Workflows](./docs/AI_WORKFLOWS.md) +- [Hooks Configuration](./docs/HOOKS.md) ## License -MIT License - see [LICENSE](LICENSE) file for details - -## Support - -- **Issues**: [GitHub Issues](https://github.com/fnebenfuehr/worktree-cli/issues) -- **Discussions**: [GitHub Discussions](https://github.com/fnebenfuehr/worktree-cli/discussions) +MIT ---- +## Links -Made with 🤖 for Reco +- [Issues](https://github.com/fnebenfuehr/worktree-cli/issues) +- [Discussions](https://github.com/fnebenfuehr/worktree-cli/discussions) diff --git a/docs/AI_WORKFLOWS.md b/docs/AI_WORKFLOWS.md new file mode 100644 index 0000000..5bfb3f0 --- /dev/null +++ b/docs/AI_WORKFLOWS.md @@ -0,0 +1,92 @@ +# AI Coding Workflows + +Common patterns for using worktrees with AI coding assistants. + +## Parallel Feature Development + +Work on related features in separate worktrees without conflicts. + +``` +project/ +├── main/ +├── feat-auth/ # Session 1: authentication +├── feat-dashboard/ # Session 2: dashboard UI +└── feat-api/ # Session 3: API endpoints +``` + +**Claude Code:** +> "Create a worktree for the authentication feature" + +Each session has complete isolation. No merge conflicts until you're ready. + +## PR Review Workflow + +Review PRs without disrupting current work. + +```bash +# You're working on a feature +worktree pr 123 +# Review the PR in its own worktree +# Switch back when done +worktree switch feat/my-feature +``` + +**Claude Code:** +> "Checkout PR #123 for review" + +Claude fetches PR info and creates a worktree automatically. + +## Bug Hotfix + +Quick fixes without losing context. + +```bash +# Working on a feature, urgent bug reported +worktree create fix/critical-bug +# Fix, commit, push +# Return to feature work +worktree switch feat/my-feature +``` + +Your feature work remains untouched. + +## Experimentation + +Try risky changes safely. + +```bash +worktree create experiment/new-architecture +# Try radical changes +# If it works: merge +# If not: worktree remove experiment/new-architecture +``` + +No impact on main development. + +## Multi-Agent Workflow + +Different AI sessions in different worktrees. + +**Session 1 (Claude Code):** Frontend work in `feat-ui` +**Session 2 (Cursor):** Backend work in `feat-api` +**Session 3 (Claude Code):** Tests in `feat-tests` + +Each agent has its own context. No stepping on each other's changes. + +## Best Practices + +1. **One task per worktree** - Keep contexts clean +2. **Use conventional branch names** - `feat/`, `fix/`, `chore/` +3. **Clean up after merge** - `worktree remove` merged branches +4. **Configure hooks** - Auto-install deps, copy .env files +5. **Let AI manage worktrees** - MCP tools handle the complexity + +## MCP Tool Selection + +| Task | Tool | +|------|------| +| Start new work | `worktree_status` → `worktree_create` | +| Continue existing | `worktree_list` → `worktree_switch` | +| Review PR | `worktree_pr` | +| Existing branch | `worktree_checkout` | +| Done with work | `worktree_remove` | diff --git a/docs/HOOKS.md b/docs/HOOKS.md new file mode 100644 index 0000000..1c59b1f --- /dev/null +++ b/docs/HOOKS.md @@ -0,0 +1,107 @@ +# Lifecycle Hooks + +Automate worktree setup and teardown. + +## Configuration + +Create `.worktree.json` in your project root: + +```json +{ + "defaultBranch": "main", + "post_create": ["npm install"], + "pre_remove": ["docker compose down"], + "copy_files": [".env", ".env.local"] +} +``` + +## Hooks + +| Hook | When | Working Directory | +|------|------|-------------------| +| `post_create` | After creating worktree | New worktree | +| `pre_remove` | Before removing worktree | Worktree being removed | +| `post_remove` | After removing worktree | Main worktree | + +`copy_files` copies files from main worktree to new worktree. + +## Environment Variables + +Hooks receive context via environment variables: + +| Variable | Description | +|----------|-------------| +| `WORKTREE_PATH` | Path to the worktree | +| `WORKTREE_BRANCH` | Branch name | +| `WORKTREE_MAIN_PATH` | Path to main worktree | +| `WORKTREE_PROJECT` | Project name | + +## Examples + +### Node.js + +```json +{ + "post_create": ["npm install"], + "copy_files": [".env"] +} +``` + +### Monorepo + +```json +{ + "post_create": ["bun install"], + "copy_files": [".env", "apps/web/.env.local", "apps/api/.env.local"] +} +``` + +### Docker + Database + +```json +{ + "post_create": [ + "docker compose up -d --wait", + "npm install", + "npm run db:migrate" + ], + "pre_remove": ["docker compose down"], + "copy_files": [".env"] +} +``` + +### Delegate to npm scripts + +```json +{ + "post_create": ["npm run worktree:setup"], + "pre_remove": ["npm run worktree:cleanup"] +} +``` + +## CLI Flags + +| Flag | Description | +|------|-------------| +| `--no-hooks` | Skip all hooks | +| `--trust-hooks` | Skip security validation | +| `--verbose` | Show detailed output | + +## Security + +Hooks execute shell commands with your user permissions. + +**Review `.worktree.json` in untrusted repositories before creating worktrees.** + +Dangerous patterns are blocked by default: +- `rm -rf` (except safe paths like node_modules) +- `curl | bash`, `wget | bash` +- `sudo`, `eval` + +Use `--trust-hooks` to bypass validation. + +## Behavior + +- Commands run sequentially in order listed +- Failed commands warn but don't stop execution +- Config loaded from main worktree root diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md new file mode 100644 index 0000000..6764fc5 --- /dev/null +++ b/docs/QUICKSTART.md @@ -0,0 +1,71 @@ +# Quick Start + +Get up and running in 2 minutes. + +## Prerequisites + +- Git 2.5+ +- Node.js 18+ or Bun 1.0+ +- GitHub CLI (`gh`) for PR checkout feature + +## Install + +```bash +npm install -g @fnebenfuehr/worktree-cli +# or +bun install -g @fnebenfuehr/worktree-cli +``` + +## Setup Worktrees + +### New Repository + +```bash +worktree clone git@github.com:user/repo.git +cd repo/main +``` + +### Existing Repository + +```bash +cd your-project +worktree setup +cd main +``` + +## Create Your First Worktree + +```bash +worktree create feat/my-feature +cd ../feat-my-feature +``` + +## Configure MCP for Claude Code + +Add to `~/.config/claude/mcp_settings.json`: + +```json +{ + "mcpServers": { + "worktree": { + "command": "npx", + "args": ["-y", "@fnebenfuehr/worktree-cli", "mcp"] + } + } +} +``` + +Restart Claude Code. + +## First AI-Assisted Worktree + +In Claude Code, try: + +> "Create a worktree for adding dark mode" + +Claude will use `worktree_create` to set up an isolated workspace. + +## Next Steps + +- Add hooks to `.worktree.json` for auto-setup (npm install, etc.) +- See [AI_WORKFLOWS.md](./AI_WORKFLOWS.md) for common patterns diff --git a/docs/hooks.md b/docs/hooks.md deleted file mode 100644 index 5688355..0000000 --- a/docs/hooks.md +++ /dev/null @@ -1,213 +0,0 @@ -# Worktree Lifecycle Hooks - -Configure automated setup and teardown for your worktrees using lifecycle hooks. - -## Security Warning - -⚠️ **Config files execute shell commands with your user permissions.** Always review `.worktreerc` files in repositories before creating worktrees, especially in projects from untrusted sources. - -Like `npm install` or `Makefile`, worktree hooks execute arbitrary commands. Treat config files from cloned repositories with the same caution you would apply to any executable code. - -## Quick Start - -Create a `.worktreerc` file in your project root: - -```json -{ - "$schema": "https://raw.githubusercontent.com/fnebenfuehr/worktree-cli/main/schema.json", - "post_create": ["bun install"], - "copy_files": [".env"] -} -``` - -Now when you create a worktree, dependencies install automatically and `.env` is copied. - -### IDE Support - -Add the `$schema` property to enable autocomplete and validation in your editor: - -```json -{ - "$schema": "https://raw.githubusercontent.com/fnebenfuehr/worktree-cli/main/schema.json" -} -``` - -## Configuration - -### Supported Formats - -- `.worktreerc` (JSON or YAML) -- `.worktreerc.json` -- `.worktreerc.yaml` / `.worktreerc.yml` -- `.worktree.yml` -- `worktree.config.js` / `worktree.config.cjs` - -### Available Hooks - -#### `post_create` (string[]) -Commands run **after** creating a worktree. Executed in the new worktree directory. - -#### `pre_remove` (string[]) -Commands run **before** removing a worktree. Executed in the worktree being removed. - -#### `post_remove` (string[]) -Commands run **after** removing a worktree. Executed in the main worktree directory. - -#### `copy_files` (string[]) -Files/directories to copy from main worktree. Full paths preserved (e.g., `apps/web/.env`). - -## Examples - -### Basic Node.js Project - -**.worktreerc** -```json -{ - "post_create": ["npm install"], - "copy_files": [".env"] -} -``` - -### Monorepo with Multiple Env Files - -**.worktree.yml** -```yaml -post_create: - - bun install - -copy_files: - - .env - - apps/web/.env.local - - apps/api/.env.local -``` - -### Python Project - -**.worktreerc** -```json -{ - "post_create": [ - "python -m venv venv", - "source venv/bin/activate && pip install -r requirements.txt" - ], - "copy_files": [".env"] -} -``` - -### Using Package.json Scripts - -Delegate complexity to your existing scripts: - -**.worktreerc** -```json -{ - "post_create": ["npm run worktree:setup"], - "pre_remove": ["npm run worktree:cleanup"] -} -``` - -**package.json** -```json -{ - "scripts": { - "worktree:setup": "npm install && npm run db:migrate", - "worktree:cleanup": "docker compose down" - } -} -``` - -### Docker with Database - -**.worktreerc** -```json -{ - "post_create": [ - "docker compose up -d --wait", - "npm install", - "npm run db:migrate" - ], - "pre_remove": ["docker compose down"], - "copy_files": [".env", "docker-compose.override.yml"] -} -``` - -**Note**: Use `--wait` flag to ensure services are ready before continuing. - -### Dynamic Configuration - -**worktree.config.js** -```javascript -module.exports = { - post_create: [ - 'npm install', - process.env.CI ? 'npm test' : 'npm run dev:setup' - ], - copy_files: ['.env'] -}; -``` - -## CLI Flags - -### `--no-hooks` -Skip running all lifecycle hooks: -```bash -worktree create feature/test --no-hooks -worktree remove feature/test --no-hooks -``` - -### `--verbose` -Show detailed output including command results: -```bash -worktree create feature/test --verbose -``` - -## How It Works - -- Commands run **sequentially** in the order listed -- Failed commands show a warning but don't stop execution -- Hooks are optional (no config = no hooks) -- Config loaded from main worktree root (where `.git` lives) - -## Environment Variables - -Hooks receive these environment variables for context: - -| Variable | Description | -|----------|-------------| -| `WORKTREE_PATH` | Path to the worktree being operated on | -| `WORKTREE_BRANCH` | Branch name of the worktree | -| `WORKTREE_MAIN_PATH` | Path to the main worktree | -| `WORKTREE_PROJECT` | Project/repository name | - -### Example Usage - -**.worktreerc** -```json -{ - "post_create": ["echo \"Created worktree at $WORKTREE_PATH for branch $WORKTREE_BRANCH\""], - "pre_remove": ["echo \"Cleaning up $WORKTREE_PROJECT worktree...\""] -} -``` - -**Note**: For `post_remove` hooks, `WORKTREE_PATH` contains the path of the removed worktree (for reference), while the hook runs in `WORKTREE_MAIN_PATH`. - -## Best Practices - -1. **Keep hooks simple** - Delegate complex logic to npm/bun scripts -2. **Use --wait for services** - Docker/DB services need time to start -3. **Test with --verbose** - See exactly what's happening -4. **Fail gracefully** - Don't assume hooks always succeed - -## Troubleshooting - -**Hooks not running?** -- Check config file is in main worktree root -- Validate JSON/YAML syntax -- Use `--verbose` to see what's happening - -**Command fails but doesn't stop?** -- By design - hooks warn but continue -- Critical failures should be in your CI, not hooks - -**Need to skip hooks temporarily?** -- Use `--no-hooks` flag