<!--
SPDX-FileCopyrightText: Amolith <amolith@secluded.site>

SPDX-License-Identifier: CC0-1.0
-->

# wt

[![REUSE status](https://api.reuse.software/badge/git.secluded.site/wt)](https://api.reuse.software/info/git.secluded.site/wt)
[![Donate using Liberapay](https://img.shields.io/liberapay/receives/Amolith.svg?logo=liberapay)](https://liberapay.com/Amolith/)

Git worktree manager using a bare repository pattern. Clone once, check
out many.

## tl;dr

```
wt c git@git.host:user/project.git     # Clone into bare structure
cd project/{canonical-branch}
wt a feature/auth -b                   # Create worktree + branch
cd ../feaTABTAB                        # Use cd + shell completions
                                       #   to navigate branches
wt l                                   # List worktrees
wt r feature/auth -b                   # Remove worktree + branch
```

## Features

- **Templated remote automation** — configure URL templates, select remotes on
  clone, supports both contributing and own-project workflows
- **Hooks** — copy files, create symlinks, run commands when adding worktrees
- **Optional path styles** — nested (`feature/auth`) or flat (`feature_auth`)
  worktree paths, schemes like `847-do-a-thing` work just fine too
- **Bare repo structure** where `.bare/` holds the repository and worktrees live
  as sibling directories
- **Convert existing repos** — `wt init` migrates a normal clone to bare
  structure

## Installation

Requires Lua 5.2 or later and
[gum](https://github.com/charmbracelet/gum) for interactive prompts

```
curl -o ~/.local/bin/wt https://git.secluded.site/wt/blob/main/dist/wt?raw=1
chmod +x ~/.local/bin/wt
```

## Usage

### Commands

| Command | Description |
| --- | --- |
| `wt c <url> [--remote name]... [--own]` | Clone into bare worktree structure |
| `wt n <name> [--remote name]...` | Initialize fresh project |
| `wt a <branch> [-b [<start-point>]]` | Add worktree, optionally create branch |
| `wt r <branch> [-b] [-f]` | Remove worktree, optionally delete branch |
| `wt l` | List worktrees with status |
| `wt f` | Fetch all remotes |
| `wt init [--dry-run] [-y]` | Convert existing repo to bare structure |

### Clone workflows

**Contributing to others' projects (default):**

```
wt c https://github.com/org/repo.git
# origin → upstream, your remotes added from config
```

**Your own projects:**

```
wt c git@github.com:you/repo.git --own
# First selected remote becomes origin
# Additional remotes added from config
```

### Adding worktrees

From inside an existing worktree, hooks from `.wt.lua` run automatically:

```
cd project/main
wt a feature/new-thing -b              # New branch from current HEAD
wt a bugfix/issue-123 -b origin/main   # New branch from specific start point
wt a existing-branch                   # Checkout existing branch
```

## Configuration

### Global config (`~/.config/wt/config.lua`)

```lua
return {
    branch_path_style = "nested",  -- or "flat"
    flat_separator = "_",          -- separator for flat style

    remotes = {
        github = "git@github.com:myuser/${project}.git",
        gitlab = "git@gitlab.com:myuser/${project}.git",
    },

    default_remotes = "prompt",    -- or {"github", "gitlab"}
}
```

### Project config (`.wt.lua` in project root)

```lua
return {
    hooks = {
        copy = {".env.example", "Makefile.local"},
        symlink = {".env", "node_modules"},
        run = {"make setup", "npm install"},
    }
}
```

Hooks only run when `wt a` is executed from inside an existing worktree.
You'll be prompted once per project to allow hooks; permissions are stored in
`~/.local/share/wt/hook-dirs.lua`.

## Contributions

Patch requests are in
[amolith/catchall](https://pr.pico.sh/r/amolith/catchall) on
[pr.pico.sh](https://pr.pico.sh). You don't need a new account to
contribute, you don't need to fork this repo, you don't need to fiddle
with `git send-email`, you don't need to faff with your email client to
get `git request-pull` working...

You just need:

- Git
- SSH
- An SSH key

```
# Clone this repo, make your changes, and commit them
# Create a new patch request with
git format-patch origin/main --stdout | ssh pr.pico.sh pr create amolith/catchall
# After potential feedback, submit a revision to an existing patch request with
git format-patch origin/main --stdout | ssh pr.pico.sh pr add {prID}
# List patch requests
ssh pr.pico.sh pr ls amolith/catchall
```

See "How do Patch Requests work?" on [pr.pico.sh](https://pr.pico.sh)'s home
page for a more complete example workflow.

---

Some other tools if this one interested you

- [agent-skills](https://git.secluded.site/agent-skills) - collection of Agent Skills for extending LLM capabilities
- [garble](https://git.secluded.site/garble) - transform stdin with an LLM (fix typos, translate, reformat)
- [formatted-commit](https://git.secluded.site/formatted-commit) - CLI that turns LLM input into well-formatted Conventional Commits
