# limb

A focused CLI for git worktree management. Limb runs with zero
configuration in any git repository. Templates, hooks, and cross-repository
workflows become available when configured.

[![CI](https://github.com/ss0923/limb/actions/workflows/ci.yml/badge.svg)](https://github.com/ss0923/limb/actions/workflows/ci.yml)
[![Crates.io](https://img.shields.io/crates/v/limb.svg)](https://crates.io/crates/limb)
[![License](https://img.shields.io/crates/l/limb.svg)](https://crates.io/crates/limb)

```console
$ limb list
NAME         BRANCH         PATH
development  development    ~/dev/myrepo/development
staging      staging        ~/dev/myrepo/staging
feat-auth    feat-auth      ~/dev/myrepo/feat-auth
```

## Install

### Homebrew (macOS / Linux)

```sh
brew install ss0923/tap/limb
```

### Cargo

```sh
cargo install limb
```

### Shell installer (macOS / Linux)

```sh
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/ss0923/limb/releases/latest/download/limb-installer.sh | sh
```

### PowerShell installer (Windows)

```pwsh
powershell -c "irm https://github.com/ss0923/limb/releases/latest/download/limb-installer.ps1 | iex"
```

### Prebuilt binaries

macOS (Intel + ARM), Linux (x86_64 + aarch64), and Windows archives on the
[releases page](https://github.com/ss0923/limb/releases).

## Quick start

```sh
cd ~/src/myrepo              # any git repo
limb add feat-auth           # create a worktree at ./feat-auth
limb list                    # list every worktree
limb status                  # dirty / ahead / behind per worktree
limb pick                    # TUI picker; prints the chosen path to stdout
cd "$(limb pick)"            # shell round-trip
limb remove feat-auth        # remove it when done
```

## Commands

| Command       | What it does                                                                                          |
| ------------- | ----------------------------------------------------------------------------------------------------- |
| `list`        | List worktrees (`--all` crosses every repo in `projects.roots`; `-v` shows lock and prune reasons).   |
| `add`         | Create a new worktree. Flags: `--from`, `-B/--force-branch`, `--detach`, `--orphan`, `--lock [--reason]`, `--template`, `--dry-run`. |
| `remove`      | Remove a worktree (`--dry-run`).                                                                      |
| `rename`      | Rename a worktree; moves the directory and updates git refs.                                          |
| `cd`          | Print a worktree's path (for `cd "$(limb cd <name>)"` round-trips).                                   |
| `pick`        | Interactive TUI picker; prints the selected path on exit. `--fetch` refreshes remote state first; `r` / `R` keys refresh in place. |
| `status`      | Per-worktree status: dirty, ahead/behind, upstream, last fetch age. `--fetch` refreshes first.        |
| `update`      | Fetch + fast-forward worktrees. `--all` crosses every repo in `projects.roots` in parallel. Flags: `--fetch-only`, `--ff-only`, `--dry-run`. |
| `lock`        | Lock a worktree against prune and remove (`--dry-run`).                                               |
| `unlock`      | Reverse `lock` (`--dry-run`).                                                                         |
| `repair`      | Repair worktree admin files; pass `[<path>...]` to target specific worktrees.                         |
| `prune`       | Drop admin entries for worktrees that no longer exist.                                                |
| `clean`       | Remove worktrees whose upstream branch is gone.                                                       |
| `setup`       | Symlink files from `.shared/` into every worktree.                                                    |
| `migrate`     | Convert a plain clone into the bare-clone + worktrees layout.                                         |
| `doctor`      | Diagnose setup; emit actionable fixes.                                                                |
| `config`      | Print resolved configuration as JSON.                                                                 |
| `init`        | Emit shell integration (`eval` in your rc).                                                           |
| `completions` | Emit a shell completion script.                                                                       |

Most commands accept `--json` for structured output where applicable.
`limb --json doctor` emits `{ok, summary: {problems, notes}, items: [...]}` —
useful for composing with other tools (e.g. dashboards, CI checks).

## Configuration

Per-repo (optional): `.limb.toml` at the bare-clone root or any worktree root.

```toml
[worktrees]
shared = [".env", ".tool-versions"]       # symlinked into every worktree

[templates.feature]
name_pattern = "feat-{slug}"
base_branch = "development"

[hooks]
post_add = "scripts/post-add.sh"
pre_remove = "scripts/pre-remove.sh"
```

Global (optional): `~/.config/limb/config.toml`.

```toml
[projects]
roots = ["~/dev/work", "~/dev/personal"]  # enables --all + cross-repo pick

[ui]
theme = "vesper"                           # vesper | default | nord | gruvbox | solarized | plain

[shell]
prefix = "gw"

[git]
default_base = "main"
default_remote = "origin"

[zoxide]
enabled = true                             # opt-in: register/unregister worktrees with zoxide on add/remove
```

When `[zoxide] enabled = true`, `limb add` calls `zoxide add <path>` after
the worktree is created (and after `post_add`) and `limb remove` calls
`zoxide remove <path>` after the worktree is gone. Both calls are
best-effort: a missing or failing `zoxide` binary logs a warning and never
blocks the underlying worktree operation.

Run `limb doctor` to verify your setup.

## Shell integration

Adds wrapper functions (`gw`, `gwa`, `gwp`, ...) and a precmd hook so editor-
driven worktree switches propagate back to the shell:

```sh
# zsh
eval "$(limb init zsh)"

# bash
eval "$(limb init bash)"

# fish
limb init fish | source

# pwsh
Invoke-Expression (& limb init pwsh)

# custom prefix
eval "$(limb init zsh --prefix wt)"
```

## Editor integrations

- [limb.nvim](https://github.com/ss0923/limb.nvim). Adds `:LimbPick` and
  `:LimbStatus`. When Neovim runs inside tmux, directory changes
  propagate to the parent shell on the next prompt.
- [limb.tmux](https://github.com/ss0923/limb.tmux). Binds `prefix + W` to
  a popup worktree picker. If any tmux window already has its working
  directory set to the selected worktree, focus that window; otherwise
  open a new window there.

## Hooks

`.limb.toml` may declare four hooks: `pre_add`, `post_add`, `pre_remove`,
`post_remove`. Each receives:

- `$LIMB_WORKTREE_PATH`. Absolute path of the worktree.
- `$LIMB_WORKTREE_NAME`. Worktree name.

Scripts are resolved relative to the declaring repo root; paths containing
`..` are rejected. `pre_*` failures abort the operation; `post_*` failures
log a warning and proceed.

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md). CI enforces `cargo fmt`,
`cargo clippy` pedantic with `-D warnings`, `cargo test` on Linux,
macOS, and Windows, MSRV 1.88, `cargo doc`, and `cargo-deny` for
supply-chain auditing.

## License

Licensed under either of

- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
  <http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
license, shall be dual licensed as above, without any additional terms or
conditions.
