From d5a64a1d791fa1cbc42969164146e9520ec7c5b6 Mon Sep 17 00:00:00 2001 From: Nathan Nutter Date: Wed, 15 Jul 2026 00:09:16 -0500 Subject: [PATCH 1/3] Upgrade the zsh function to be a full wrapper + switch subcommand --- README.md | 57 ++++++++++---- go.mod | 1 + go.sum | 2 + internal/gitwt/gitwt_shell.go | 2 +- internal/gitwt/gitwt_shell_zsh.go | 122 ++++++++++++++++++++---------- internal/gitwt/gitwt_test.go | 102 ++++++++++++++++++++++--- 6 files changed, 222 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index b88c69a..efeef1a 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,31 @@ Install using Go, go install github.com/nnutter/git-wt@latest ``` +## Shell integration + +Generate a zsh function that wraps the CLI (default name `gt`): + +```bash +git-wt shell zsh +# or: git-wt shell zsh --name gt --out $XDG_DATA_HOME/zsh/site-functions --force +``` + +Ensure the output directory is on `fpath`, then restart zsh or run `compinit`. + +The generated function: + +- routes most commands to `git-wt` (`gt create`, `gt list`, `gt prune`, …) +- provides a shell-only `switch` that `cd`s into a worktree +- after a successful `gt remove`, `cd`s to the main worktree + +```bash +gt switch main +gt switch feature/login +gt create feature/login +gt remove feature/login # then cd main +gt list +``` + ## Commands ### `git-wt create ` @@ -77,6 +102,8 @@ When `name` is omitted, removes the managed worktree that contains the current d It refuses to remove the main worktree, and refuses dirty or unmerged worktrees by default. Use `--force` | `-f` to force (destructive) removal. +When invoked through the shell wrapper (`gt remove`), the shell also switches to the main worktree after a successful removal. + Example: ```bash @@ -85,23 +112,25 @@ git-wt remove feature/login git-wt remove --force feature/login ``` -## Typical Flow +### `git-wt shell zsh` -Checkout [git-cd](https://github.com/nnutter/dotfiles/blob/master/bin/git-cd) to generate shell functions to easily cd to worktrees. +Generate a zsh wrapper function and completion (see [Shell integration](#shell-integration)). -Create a shell function, `nn`, to switch between the repos under my GitHub path, +## Typical Flow ```bash -git-cd --name nn --repos ~/src/github.com/nnutter +# once: install wrapper +git-wt shell zsh + +# in a repo +gt create feature/login +gt switch feature/login +# ... work ... +gt switch main +gt prune +# or: +gt remove feature/login ``` -Then a typical flow might look like, - -```bash -nn some-repo -git-wt create feature/login -... -nn some-repo.feature.login -nn some-repo -git-wt prune -``` +For jumping between repositories under a path, you can still use something like +[git-cd](https://github.com/nnutter/dotfiles/blob/master/bin/git-cd). diff --git a/go.mod b/go.mod index 191dca8..74e0ae4 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( dario.cat/mergo v1.0.2 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProtonMail/go-crypto v1.4.1 // indirect + github.com/adrg/xdg v0.5.3 // indirect github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/catppuccin/go v0.3.0 // indirect diff --git a/go.sum b/go.sum index 62bcd56..5e725e7 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/ProtonMail/go-crypto v1.4.1 h1:9RfcZHqEQUvP8RzecWEUafnZVtEvrBVL9BiF67IQOfM= github.com/ProtonMail/go-crypto v1.4.1/go.mod h1:e1OaTyu5SYVrO9gKOEhTc+5UcXtTUa+P3uLudwcgPqo= +github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78= +github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= diff --git a/internal/gitwt/gitwt_shell.go b/internal/gitwt/gitwt_shell.go index 9621e8f..68e7c95 100644 --- a/internal/gitwt/gitwt_shell.go +++ b/internal/gitwt/gitwt_shell.go @@ -11,7 +11,7 @@ func NewShellCommand() *cobra.Command { command := &cobra.Command{ Use: `shell`, - Short: `Generate shell integration for worktrees`, + Short: `Generate shell integration wrapping git-wt`, Args: cobra.NoArgs, RunE: options.Execute, } diff --git a/internal/gitwt/gitwt_shell_zsh.go b/internal/gitwt/gitwt_shell_zsh.go index 784165e..f858c07 100644 --- a/internal/gitwt/gitwt_shell_zsh.go +++ b/internal/gitwt/gitwt_shell_zsh.go @@ -19,7 +19,7 @@ func NewZshCommand() *cobra.Command { command := &cobra.Command{ Use: `zsh`, - Short: `Generate zsh function and completion for worktree switching`, + Short: `Generate zsh function and completion wrapping git-wt`, Args: cobra.NoArgs, RunE: options.Execute, } @@ -77,45 +77,67 @@ func (x *zshCommandOptions) writeFunctionFile(target string) error { # DO NOT EDIT. Regenerate with git-wt shell zsh ` + x.name + `() { - if [[ -z "$1" ]]; then - echo "Usage: ` + x.name + ` " - return 1 - fi - - local main_dir=$(git worktree list --porcelain | head -n1 | sed "s/^worktree //") - local parent_dir=$(dirname $main_dir) - local repo_name=$(basename $main_dir) + case "$1" in + switch) + shift + if [[ -z "$1" ]]; then + echo "Usage: ` + x.name + ` switch " >&2 + return 1 + fi - local arg=$1 + local main_dir + main_dir=$(git worktree list --porcelain | head -n1 | sed "s/^worktree //") + if [[ -z "$main_dir" ]]; then + echo "Main worktree not found" >&2 + return 1 + fi - # Strip repository prefix from arg if used - if [[ $arg == $repo_name.* ]]; then - arg=${arg#$repo_name.} - fi + local parent_dir=$(dirname "$main_dir") + local repo_name=$(basename "$main_dir") + local arg=$1 - case "$1" in - main) - if [[ $(pwd) == $main_dir ]]; then - echo "Already in main worktree" - return 0 + if [[ $arg == $repo_name.* ]]; then + arg=${arg#$repo_name.} fi - if ! [[ -d $main_dir ]]; then + + case "$arg" in + main) + if [[ $(pwd) == "$main_dir" ]]; then + echo "Already in main worktree" + return 0 + fi + if ! [[ -d "$main_dir" ]]; then + echo "Main worktree not found" >&2 + return 1 + fi + cd "$main_dir" + ;; + *) + local target_dir=$parent_dir/${repo_name}.${arg//\//.} + if [[ $(pwd) == "$target_dir" ]]; then + echo "Already in $arg" + return 0 + fi + if ! [[ -d "$target_dir" ]]; then + echo "Worktree $arg not found at $target_dir" >&2 + return 1 + fi + cd "$target_dir" + ;; + esac + ;; + remove) + local main_dir + main_dir=$(git worktree list --porcelain | head -n1 | sed "s/^worktree //") + if [[ -z "$main_dir" ]]; then echo "Main worktree not found" >&2 return 1 fi - cd $main_dir + command git-wt "$@" || return $? + cd "$main_dir" ;; *) - local target_dir=$parent_dir/${repo_name}.${arg//\//.} - if [[ $(pwd) == $target_dir ]]; then - echo "Already in $arg" - return 0 - fi - if ! [[ -d $target_dir ]]; then - echo "Worktree $arg not found at $target_dir" >&2 - return 1 - fi - cd $target_dir + command git-wt "$@" ;; esac } @@ -131,18 +153,40 @@ func (x *zshCommandOptions) writeCompletionFile(target string) error { # DO NOT EDIT. Regenerate with git-wt shell zsh _` + x.name + `() { - if ! git rev-parse --is-inside-work-tree 1>/dev/null 2>/dev/null; then - return 1 + local -a subcommands + subcommands=( + 'create:Create a managed Git worktree' + 'list:List managed Git worktrees' + 'migrate:Bring existing worktrees under management' + 'prune:Remove clean merged managed worktrees' + 'remove:Remove a managed Git worktree' + 'shell:Generate shell integration' + 'switch:Switch to a worktree' + ) + + if (( CURRENT == 2 )); then + _describe 'command' subcommands + return fi - local main_dir - main_dir=$(git worktree list --porcelain | head -n1 | sed "s/^worktree //") + case $words[2] in + switch|remove) + if ! git rev-parse --is-inside-work-tree 1>/dev/null 2>/dev/null; then + return 1 + fi + + local main_dir + main_dir=$(git worktree list --porcelain | head -n1 | sed "s/^worktree //") - local -a worktrees - worktrees=(main) - worktrees+=($(git worktree list --porcelain 2>/dev/null | grep '^worktree ' | tail -n +2 | sed 's|^worktree '"$main_dir"'\.||')) + local -a worktrees + if [[ $words[2] == switch ]]; then + worktrees=(main) + fi + worktrees+=($(git worktree list --porcelain 2>/dev/null | grep '^worktree ' | tail -n +2 | sed 's|^worktree '"$main_dir"'\.||')) - _describe 'worktrees' worktrees + _describe 'worktrees' worktrees + ;; + esac } ` diff --git a/internal/gitwt/gitwt_test.go b/internal/gitwt/gitwt_test.go index 87fb53f..1bdf5f0 100644 --- a/internal/gitwt/gitwt_test.go +++ b/internal/gitwt/gitwt_test.go @@ -333,6 +333,82 @@ func TestRemoveCompletionOffersManagedWorktreeNames(t *testing.T) { } } +func TestShellZshGeneratesWrapperFunctionAndCompletion(t *testing.T) { + outDir := t.TempDir() + const functionName = "gt" + + result := runGitWTCommand(t, "shell", "zsh", "--name", functionName, "--out", outDir) + if result.err != nil { + t.Fatalf("shell zsh failed: %v\n%s", result.err, result.stderr) + } + + functionPath := filepath.Join(outDir, functionName) + completionPath := filepath.Join(outDir, "_"+functionName) + + functionContent, err := os.ReadFile(functionPath) + if err != nil { + t.Fatalf("read function file: %v", err) + } + completionContent, err := os.ReadFile(completionPath) + if err != nil { + t.Fatalf("read completion file: %v", err) + } + + functionText := string(functionContent) + for _, want := range []string{ + functionName + "() {", + "case \"$1\" in", + "switch)", + "remove)", + "command git-wt \"$@\"", + "cd \"$main_dir\"", + "git worktree list --porcelain", + "Usage: " + functionName + " switch ", + } { + if !strings.Contains(functionText, want) { + t.Fatalf("function missing %q:\n%s", want, functionText) + } + } + if strings.Contains(functionText, "Usage: "+functionName+" ") { + t.Fatalf("function still uses bare worktree usage:\n%s", functionText) + } + + completionText := string(completionContent) + for _, want := range []string{ + "#compdef " + functionName, + "switch:Switch to a worktree", + "remove:Remove a managed Git worktree", + "create:Create a managed Git worktree", + "case $words[2] in", + "switch|remove)", + "worktrees=(main)", + } { + if !strings.Contains(completionText, want) { + t.Fatalf("completion missing %q:\n%s", want, completionText) + } + } +} + +func TestShellZshRefusesOverwriteWithoutForce(t *testing.T) { + outDir := t.TempDir() + const functionName = "gt" + + first := runGitWTCommand(t, "shell", "zsh", "--name", functionName, "--out", outDir) + if first.err != nil { + t.Fatalf("first shell zsh failed: %v\n%s", first.err, first.stderr) + } + + second := runGitWTCommand(t, "shell", "zsh", "--name", functionName, "--out", outDir) + if second.err == nil { + t.Fatal("expected second shell zsh without --force to fail") + } + + forced := runGitWTCommand(t, "shell", "zsh", "--name", functionName, "--out", outDir, "--force") + if forced.err != nil { + t.Fatalf("shell zsh --force failed: %v\n%s", forced.err, forced.stderr) + } +} + func TestPruneRemovesOnlyMergedCleanWorktrees(t *testing.T) { const mergedBranchName = "feature/merged" const unmergedBranchName = "feature/unmerged" @@ -577,15 +653,6 @@ func (x testRepository) runGitWT(t *testing.T, args ...string) commandResult { func (x testRepository) runGitWTFrom(t *testing.T, directory string, args ...string) commandResult { t.Helper() - command := NewRootCommand() - command.SetArgs(args) - command.SetIn(bytes.NewBuffer(nil)) - - var stdout bytes.Buffer - var stderr bytes.Buffer - command.SetOut(&stdout) - command.SetErr(&stderr) - currentDirectory, err := os.Getwd() if err != nil { t.Fatalf("get current directory: %v", err) @@ -599,7 +666,22 @@ func (x testRepository) runGitWTFrom(t *testing.T, directory string, args ...str } }() - err = command.Execute() + return runGitWTCommand(t, args...) +} + +func runGitWTCommand(t *testing.T, args ...string) commandResult { + t.Helper() + + command := NewRootCommand() + command.SetArgs(args) + command.SetIn(bytes.NewBuffer(nil)) + + var stdout bytes.Buffer + var stderr bytes.Buffer + command.SetOut(&stdout) + command.SetErr(&stderr) + + err := command.Execute() return commandResult{stdout: stdout.String(), stderr: stderr.String(), err: err} } From 7f6b497be6d0a3e6ffd8dab1421f25d921fa127e Mon Sep 17 00:00:00 2001 From: Nathan Nutter Date: Wed, 15 Jul 2026 00:11:29 -0500 Subject: [PATCH 2/3] Rename the shell subcommand to generate --- README.md | 8 ++++---- internal/gitwt/gitwt.go | 2 +- .../{gitwt_shell.go => gitwt_generate.go} | 10 +++++----- ...twt_shell_zsh.go => gitwt_generate_zsh.go} | 10 +++++----- internal/gitwt/gitwt_test.go | 20 +++++++++---------- 5 files changed, 25 insertions(+), 25 deletions(-) rename internal/gitwt/{gitwt_shell.go => gitwt_generate.go} (58%) rename internal/gitwt/{gitwt_shell_zsh.go => gitwt_generate_zsh.go} (95%) diff --git a/README.md b/README.md index efeef1a..dd63076 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,8 @@ go install github.com/nnutter/git-wt@latest Generate a zsh function that wraps the CLI (default name `gt`): ```bash -git-wt shell zsh -# or: git-wt shell zsh --name gt --out $XDG_DATA_HOME/zsh/site-functions --force +git-wt generate zsh +# or: git-wt generate zsh --name gt --out $XDG_DATA_HOME/zsh/site-functions --force ``` Ensure the output directory is on `fpath`, then restart zsh or run `compinit`. @@ -112,7 +112,7 @@ git-wt remove feature/login git-wt remove --force feature/login ``` -### `git-wt shell zsh` +### `git-wt generate zsh` Generate a zsh wrapper function and completion (see [Shell integration](#shell-integration)). @@ -120,7 +120,7 @@ Generate a zsh wrapper function and completion (see [Shell integration](#shell-i ```bash # once: install wrapper -git-wt shell zsh +git-wt generate zsh # in a repo gt create feature/login diff --git a/internal/gitwt/gitwt.go b/internal/gitwt/gitwt.go index 4a91b46..8846e11 100644 --- a/internal/gitwt/gitwt.go +++ b/internal/gitwt/gitwt.go @@ -18,7 +18,7 @@ func NewRootCommand() *cobra.Command { rootCommand.AddCommand(NewMigrateCommand()) rootCommand.AddCommand(NewPruneCommand()) rootCommand.AddCommand(NewRemoveCommand()) - rootCommand.AddCommand(NewShellCommand()) + rootCommand.AddCommand(NewGenerateCommand()) return rootCommand } diff --git a/internal/gitwt/gitwt_shell.go b/internal/gitwt/gitwt_generate.go similarity index 58% rename from internal/gitwt/gitwt_shell.go rename to internal/gitwt/gitwt_generate.go index 68e7c95..4bccf99 100644 --- a/internal/gitwt/gitwt_shell.go +++ b/internal/gitwt/gitwt_generate.go @@ -4,13 +4,13 @@ import ( "github.com/spf13/cobra" ) -type shellCommandOptions struct{} +type generateCommandOptions struct{} -func NewShellCommand() *cobra.Command { - options := &shellCommandOptions{} +func NewGenerateCommand() *cobra.Command { + options := &generateCommandOptions{} command := &cobra.Command{ - Use: `shell`, + Use: `generate`, Short: `Generate shell integration wrapping git-wt`, Args: cobra.NoArgs, RunE: options.Execute, @@ -22,6 +22,6 @@ func NewShellCommand() *cobra.Command { return command } -func (x *shellCommandOptions) Execute(command *cobra.Command, args []string) error { +func (x *generateCommandOptions) Execute(command *cobra.Command, args []string) error { return command.Help() } diff --git a/internal/gitwt/gitwt_shell_zsh.go b/internal/gitwt/gitwt_generate_zsh.go similarity index 95% rename from internal/gitwt/gitwt_shell_zsh.go rename to internal/gitwt/gitwt_generate_zsh.go index f858c07..d1a65b4 100644 --- a/internal/gitwt/gitwt_shell_zsh.go +++ b/internal/gitwt/gitwt_generate_zsh.go @@ -73,8 +73,8 @@ func (x *zshCommandOptions) Execute(command *cobra.Command, args []string) error } func (x *zshCommandOptions) writeFunctionFile(target string) error { - content := `# Generated by git-wt shell zsh -# DO NOT EDIT. Regenerate with git-wt shell zsh + content := `# Generated by git-wt generate zsh +# DO NOT EDIT. Regenerate with git-wt generate zsh ` + x.name + `() { case "$1" in @@ -149,8 +149,8 @@ func (x *zshCommandOptions) writeFunctionFile(target string) error { func (x *zshCommandOptions) writeCompletionFile(target string) error { content := `#compdef ` + x.name + ` -# Generated by git-wt shell zsh -# DO NOT EDIT. Regenerate with git-wt shell zsh +# Generated by git-wt generate zsh +# DO NOT EDIT. Regenerate with git-wt generate zsh _` + x.name + `() { local -a subcommands @@ -160,7 +160,7 @@ _` + x.name + `() { 'migrate:Bring existing worktrees under management' 'prune:Remove clean merged managed worktrees' 'remove:Remove a managed Git worktree' - 'shell:Generate shell integration' + 'generate:Generate shell integration' 'switch:Switch to a worktree' ) diff --git a/internal/gitwt/gitwt_test.go b/internal/gitwt/gitwt_test.go index 1bdf5f0..1fc33ec 100644 --- a/internal/gitwt/gitwt_test.go +++ b/internal/gitwt/gitwt_test.go @@ -333,13 +333,13 @@ func TestRemoveCompletionOffersManagedWorktreeNames(t *testing.T) { } } -func TestShellZshGeneratesWrapperFunctionAndCompletion(t *testing.T) { +func TestGenerateZshGeneratesWrapperFunctionAndCompletion(t *testing.T) { outDir := t.TempDir() const functionName = "gt" - result := runGitWTCommand(t, "shell", "zsh", "--name", functionName, "--out", outDir) + result := runGitWTCommand(t, "generate", "zsh", "--name", functionName, "--out", outDir) if result.err != nil { - t.Fatalf("shell zsh failed: %v\n%s", result.err, result.stderr) + t.Fatalf("generate zsh failed: %v\n%s", result.err, result.stderr) } functionPath := filepath.Join(outDir, functionName) @@ -389,23 +389,23 @@ func TestShellZshGeneratesWrapperFunctionAndCompletion(t *testing.T) { } } -func TestShellZshRefusesOverwriteWithoutForce(t *testing.T) { +func TestGenerateZshRefusesOverwriteWithoutForce(t *testing.T) { outDir := t.TempDir() const functionName = "gt" - first := runGitWTCommand(t, "shell", "zsh", "--name", functionName, "--out", outDir) + first := runGitWTCommand(t, "generate", "zsh", "--name", functionName, "--out", outDir) if first.err != nil { - t.Fatalf("first shell zsh failed: %v\n%s", first.err, first.stderr) + t.Fatalf("first generate zsh failed: %v\n%s", first.err, first.stderr) } - second := runGitWTCommand(t, "shell", "zsh", "--name", functionName, "--out", outDir) + second := runGitWTCommand(t, "generate", "zsh", "--name", functionName, "--out", outDir) if second.err == nil { - t.Fatal("expected second shell zsh without --force to fail") + t.Fatal("expected second generate zsh without --force to fail") } - forced := runGitWTCommand(t, "shell", "zsh", "--name", functionName, "--out", outDir, "--force") + forced := runGitWTCommand(t, "generate", "zsh", "--name", functionName, "--out", outDir, "--force") if forced.err != nil { - t.Fatalf("shell zsh --force failed: %v\n%s", forced.err, forced.stderr) + t.Fatalf("generate zsh --force failed: %v\n%s", forced.err, forced.stderr) } } From 2b0a7c5ee586ec47729296f12d2bcc66909f5c5a Mon Sep 17 00:00:00 2001 From: Nathan Nutter Date: Wed, 15 Jul 2026 00:14:56 -0500 Subject: [PATCH 3/3] Change default function name to wt --- README.md | 38 +++++++++++++++++----------- internal/gitwt/gitwt_generate_zsh.go | 2 +- internal/gitwt/gitwt_test.go | 4 +-- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index dd63076..e5c3dbf 100644 --- a/README.md +++ b/README.md @@ -22,29 +22,37 @@ go install github.com/nnutter/git-wt@latest ## Shell integration -Generate a zsh function that wraps the CLI (default name `gt`): +Generate a zsh function that wraps the CLI (default name `wt`): ```bash git-wt generate zsh -# or: git-wt generate zsh --name gt --out $XDG_DATA_HOME/zsh/site-functions --force +# or: git-wt generate zsh --name wt --out $XDG_DATA_HOME/zsh/site-functions --force ``` Ensure the output directory is on `fpath`, then restart zsh or run `compinit`. The generated function: -- routes most commands to `git-wt` (`gt create`, `gt list`, `gt prune`, …) +- routes most commands to `git-wt` (`wt create`, `wt list`, `wt prune`, …) - provides a shell-only `switch` that `cd`s into a worktree -- after a successful `gt remove`, `cd`s to the main worktree +- after a successful `wt remove`, `cd`s to the main worktree ```bash -gt switch main -gt switch feature/login -gt create feature/login -gt remove feature/login # then cd main -gt list +wt switch main +wt switch feature/login +wt create feature/login +wt remove feature/login # then cd main +wt list ``` +If you use [carapace](https://carapace.sh), exclude its built-in `wt` completer (worktrunk) so zsh uses the generated completion instead: + +```bash +export CARAPACE_EXCLUDES=wt +``` + +Set this **before** `source <(carapace _carapace)`. You may need `carapace --clear-cache` after changing excludes. + ## Commands ### `git-wt create ` @@ -102,7 +110,7 @@ When `name` is omitted, removes the managed worktree that contains the current d It refuses to remove the main worktree, and refuses dirty or unmerged worktrees by default. Use `--force` | `-f` to force (destructive) removal. -When invoked through the shell wrapper (`gt remove`), the shell also switches to the main worktree after a successful removal. +When invoked through the shell wrapper (`wt remove`), the shell also switches to the main worktree after a successful removal. Example: @@ -123,13 +131,13 @@ Generate a zsh wrapper function and completion (see [Shell integration](#shell-i git-wt generate zsh # in a repo -gt create feature/login -gt switch feature/login +wt create feature/login +wt switch feature/login # ... work ... -gt switch main -gt prune +wt switch main +wt prune # or: -gt remove feature/login +wt remove feature/login ``` For jumping between repositories under a path, you can still use something like diff --git a/internal/gitwt/gitwt_generate_zsh.go b/internal/gitwt/gitwt_generate_zsh.go index d1a65b4..e76a078 100644 --- a/internal/gitwt/gitwt_generate_zsh.go +++ b/internal/gitwt/gitwt_generate_zsh.go @@ -24,7 +24,7 @@ func NewZshCommand() *cobra.Command { RunE: options.Execute, } - command.Flags().StringVarP(&options.name, `name`, `n`, `gt`, `name of generated zsh function`) + command.Flags().StringVarP(&options.name, `name`, `n`, `wt`, `name of generated zsh function`) command.Flags().StringVarP(&options.out, `out`, `o`, xdgDataHome()+`/zsh/site-functions`, `output directory for generated files`) command.Flags().BoolVarP(&options.force, `force`, `f`, false, `overwrite existing generated files`) diff --git a/internal/gitwt/gitwt_test.go b/internal/gitwt/gitwt_test.go index 1fc33ec..502330b 100644 --- a/internal/gitwt/gitwt_test.go +++ b/internal/gitwt/gitwt_test.go @@ -335,7 +335,7 @@ func TestRemoveCompletionOffersManagedWorktreeNames(t *testing.T) { func TestGenerateZshGeneratesWrapperFunctionAndCompletion(t *testing.T) { outDir := t.TempDir() - const functionName = "gt" + const functionName = "wt" result := runGitWTCommand(t, "generate", "zsh", "--name", functionName, "--out", outDir) if result.err != nil { @@ -391,7 +391,7 @@ func TestGenerateZshGeneratesWrapperFunctionAndCompletion(t *testing.T) { func TestGenerateZshRefusesOverwriteWithoutForce(t *testing.T) { outDir := t.TempDir() - const functionName = "gt" + const functionName = "wt" first := runGitWTCommand(t, "generate", "zsh", "--name", functionName, "--out", outDir) if first.err != nil {