Skip to content

Releases: shhac/git-wt

v0.13.1

22 Jun 12:05
4bb068d

Choose a tag to compare

v0.13.0

13 Jun 12:55
a735dc3

Choose a tag to compare

  • feat[rm]: fast, robust worktree removal with progress
  • refactor[cli]: extract loadRepoAndWorktrees + cover rm/wrapper gaps
  • docs: refresh branches/history after Go migration landed

v0.12.0

14 May 21:48
60cabfe

Choose a tag to compare

Highlights

Shell tab-completion. Cobra-generated completion scripts for bash, zsh, fish and powershell, plus dynamic candidate completion on the commands where it actually helps:

gwt go <TAB>     # existing worktree branches (current excluded)
gwt rm <TAB>     # removable worktrees (main + already-typed args excluded)
gwt add <TAB>    # local + <remote>/<rest> refs not already in a worktree

Candidates carry descriptions matching gwt ls — location and recency, formatted with the same column layout. Shells that support completion-with-descriptions (zsh, fish, bash-v2, powershell) show e.g.:

feat-x      -- #feat-x      2h   3m
paul/auth   -- #paul/auth   1d   4h

right next to each branch. bash-v1 falls back to plain branch names.

One-line setup (homebrew users)

Already on brew install shhac/tap/git-wt? Just brew upgrade git-wt — the formula now installs completion scripts automatically alongside the binary. zsh and fish pick them up via the standard brew paths; bash users need brew install bash-completion@2.

Source-build setup

git-wt completion bash > ~/.local/share/bash-completion/completions/git-wt
git-wt completion zsh  > "${fpath[1]}/_git-wt"
git-wt completion fish > ~/.config/fish/completions/git-wt.fish

The shell function generated by git-wt alias <name> now appends a self-binding line, so eval "$(git-wt alias gwt)" wires both the wrapper AND tab-completion on the alias in one step. Opt out with git-wt alias gwt --no-completion.

Under the hood

  • internal/cli/completion.go — new git-wt completion <shell> subcommand
  • internal/cli/completion_helpers.go — pure candidate builders + 3 ValidArgsFunctions
  • internal/cli/alias.go — completion-binding template + --no-completion flag
  • Reuses the existing columnWidths + padRight + ui.HumanSince so completion descriptions stay in lockstep with gwt ls output

Install

brew install shhac/tap/git-wt        # new
brew upgrade shhac/tap/git-wt        # existing — picks up completions

v0.11.0

14 May 19:16
50f129b

Choose a tag to compare

Highlights

New git-wt config command + ${...} templating. Persistent settings stored under git config wt.* with type validation, scope precedence (--local > --global), and template-variable resolution.

Headline use case:

git config --global wt.parentDir '${repoParent}/${repo}.worktrees'

Every repo now uses sibling <reponame>.worktrees/ directories — one global setting, per-repo result.

Breaking change

Default parentDir renamed from .gwt to .worktrees. Pre-1.0 so we just made the change. Existing users can pin the old path with one line:

git config --global wt.parentDir '${repoPath}/.gwt'

Old worktrees in .gwt/ remain tracked by git and visible in gwt list — only the default destination for new worktrees moves.

What's in git-wt config

git-wt config                                      # list all keys + effective values
git-wt config parentDir                            # show one key (raw + resolved)
git-wt config parentDir '../wt-${repo}'            # set --local (current repo)
git-wt config --global parentDir '${repoParent}/${repo}.worktrees'
git-wt config --unset parentDir                    # idempotent

Three keys ship:

  • wt.parentDir (string, templated) — parent directory for new worktrees
  • wt.plain (bool) — always run with --plain (also honors NO_COLOR)
  • wt.fd (int, 3-9) — default fd for the wrapper protocol

Template variables: ${repo}, ${repoPath}, ${repoParent}, ${home}. Unknown vars error at set time AND at use time (no silent fallback).

Precedence: CLI flag > git config --local wt.* > git config --global wt.* > built-in default.

Quality

  • New internal/config/ package + per-Key Validator field (per-key constraints like FD's 3-9 range live with their key, not in a generic switch).
  • New typed *git.ExitError with ExitCode() / Unwrap()Unset and GetScoped branch on exit codes instead of string-matching.
  • applyConfigDefaults decomposed into small per-flag helpers (applyBoolFlagDefault, applyIntFlagDefault, readUnchangedFlagConfig).
  • wt.ResolveParentDir now resolves relative --parent-dir paths against the repo root (was: against CWD — surprising when run from a subdir).
  • ~25 new unit tests + 11 new E2E tests covering the new surface.

Install

brew install shhac/tap/git-wt        # new users
brew upgrade shhac/tap/git-wt        # existing

v0.10.0

13 May 14:38
2474b78

Choose a tag to compare

Features

  • New eject command. Moves the currently-checked-out branch from the main working tree into a new worktree. Stashes uncommitted changes (including untracked files), switches the main tree to main/master (or --base), creates the worktree, and restores the stashed changes inside it.
    • gwt eject — eject current branch using its name as the leaf
    • gwt eject <leaf> — override the directory name (mirrors add's shape)
    • gwt eject --base <branch> — override the auto-detected main/master
    • gwt eject --parent-dir <path> — override the default .gwt/ parent
    • Interactive confirm by default; --non-interactive skips
    • Refuses cleanly when HEAD is detached, current branch is the base, run from inside an existing worktree, or no main/master exists
  • Shell wrapper (gwt alias) now also cd's after gwt eject.

Internal

  • Stash plumbing (StashPush, StashApply, StashDropBySHA, ShortStashRef) lifted from the eject command into internal/wt/stash.go so it's reusable by future commands. New StashApplyOutcome enum (StashApplied / StashAppliedKeptStash / StashApplyFailed) replaces the previous bool that collapsed three distinguishable cases.
  • Repo-state helpers (CurrentBranch, IsWorkingTreeDirty, DetectBaseBranch) and a NewLocalAddRef constructor moved to internal/wt/.
  • Eject's rollback rewritten as a LIFO compensation stack — each successful mutation registers its inverse, and the failure paths just call rollback() once.
  • Shared defaultedLeaf helper between add and eject (was verbatim duplicated).
  • runEject shrank from 56 lines to 14 via a planEject extraction; executeEject signature collapsed from 7 positional args to a single *ejectPlan.

Fixes

  • Eject rollback was silently broken. git stash pop --index <SHA> only accepts stash@{N} references, not raw SHAs, so the rollback's stash-restore always failed. The error was discarded by _, _ =, leaving the user's dirty state stranded in the stash list. Fixed via apply + drop-by-SHA; rollback errors now surface as warnings.

Tests

  • 3 new E2E tests pinning the rollback paths and by-SHA drop semantics, plus unit tests for the new wt/stash.go helpers including a full push/apply/drop roundtrip.

v0.9.0

13 May 13:39
8707376

Choose a tag to compare

Features

  • New add command for opening an existing branch in a worktree. Pairs with new: new creates the branch, add attaches a worktree to one that already exists.
    • gwt add <branch> — checks out an existing local branch into <repo>/.gwt/<branch>/
    • gwt add origin/<branch> — creates a local branch tracking the remote (DWIM via --track -b)
    • gwt add <leaf> <branch|remote-ref> — overrides the leaf directory name
    • Honours --parent-dir, --no-copy, --copy-file-config (same as new)
  • Shell wrapper (gwt alias) now also cd's after gwt add, alongside go/new/rm.

Internal

  • Refactored the shared pipeline between new and add into a new internal/cli/worktree_create.go (~50 lines of duplication removed). Each command's RunE is now ~25 lines of orchestration.
  • New shared helpers: requireMutableRepo, wt.ResolveParentDir, prepareWorktreeSite, finalizeWorktreeSite.
  • AddRefResolution now owns the git worktree add argv construction via a WorktreeAddArgs method; renamed internal/wt/add.go to refresolve.go since the resolver is command-agnostic.
  • Split warnIfParentNotIgnored into pure (relInsideRepo) + git-wrapper (isPathIgnored) + caller for testability.

Tests

  • Added E2E coverage for previously unverified guards: merge-in-progress refusal, bare-repo refusal, copy-config-failure-is-non-fatal contract, new --parent-dir parity with add, DWIM local-name correctness on add <leaf> origin/<rest>.
  • Pinned bare-repo refusal to its current error path so a future Inspect reorder is loud, not silent.

Docs

  • README and AGENTS.md document the add command.

v0.8.3

12 May 09:20
900ae3f

Choose a tag to compare

  • fix[fd]: require write mode for wrapper-protocol fd

Fixes a crash in Linux container environments (Docker, GitHub Actions
ubuntu runners) where a read-only cgroup fd leaks as fd 3, causing
git-wt go|new|rm to fail with error: write fd3: bad file descriptor.
The wrapper-protocol fd check now requires write mode.

v0.8.2

11 May 12:52
820f979

Choose a tag to compare

Fixes

  • fix[alias]: detect subcommand after leading global flags. gwt --debug go <branch> (and any pre-subcommand flag like --plain, -n, --fd) was falling through to the wrapper's pass-through branch, skipping the cd. The generated shell wrapper now walks $@ to find the real subcommand. The trailing-flag form (gwt go <branch> --debug) still works and is now redundant rather than required.

    Action required for existing users: re-run eval "$(git-wt alias gwt)" (or your usual rc line) after upgrading so your shell picks up the new wrapper.

Improvements

  • feat[debug]: instrument picker sessions and emit-target. Interactive commands (go, rm) now show the full timeline including the picker open/close span (pick.one, pick.many, pick.confirm) and the path emit (emit-target). Useful for distinguishing "the tool is slow" from "I was deciding."

    Awk filter for picker-only durations: awk -F'\t' '$5 ~ /^pick\./'.

v0.8.1

11 May 11:48
005aa5c

Choose a tag to compare

  • feat[debug]: tab-separate columns with - placeholder for empties

The --debug timeline (introduced in v0.8.0) now uses tab-separated columns:

[elapsed]  op#N  status  took  name  detail  [err]

Awk-friendly extraction:

# slowest git invocations
gwt --debug rm <branch> 2>&1 | awk -F'\t' '$3=="done"{print $4,$5,$6}' | sort -h

# only failures
gwt --debug ls 2>&1 | awk -F'\t' '$3=="failed"{print $5,$6,$7}'

Non-trailing empty columns are filled with - so positional default-awk
also stays consistent across start/done/failed rows. The internal lipgloss
dim style was preserving tabs only after setting TabWidth(-1) — lipgloss
otherwise expands embedded tabs to 4 spaces when output goes to a TTY.

v0.8.0

11 May 11:26
24f6bbb

Choose a tag to compare

  • feat: wire --debug flag to operation timeline

The previously dead --debug flag now drives an operation timeline written to
stderr. Every git subprocess prints a paired start/done line with a per-op id
and duration; targeted spans cover rm's chdir bounce and new's
config-copy phase. Useful for diagnosing slow gwt rm runs (typically the
working-tree status scan inside git worktree remove).