Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Ensure the output directory is on `fpath`, then restart zsh or run `compinit`.
The generated function:

- routes most commands to `git-wt` (`wt create`, `wt list`, `wt prune`, …)
- after a successful `wt create`, `cd`s into the new worktree (`--no-cd` to stay put)
- after a successful `wt create`, `cd`s into the new worktree (`--no-cd` or `-r` | `--herdr` to stay put)
- provides a shell-only `switch` that `cd`s into a worktree
- after a successful `wt remove`, `cd`s to the main worktree

Expand Down Expand Up @@ -66,15 +66,15 @@ Set this **before** `source <(carapace _carapace)`. You may need `carapace --cle
Create a managed worktree for a branch.

- If the branch already exists, the worktree is created from that branch.
- If the branch does not exist, it is created from the upstream branch; which defaults to the default origin branch but can be set explicity with `--upstream` | `-u`.
- With `--herdr`, also create a [Herdr](https://herdr.dev) workspace whose `--cwd` is the new worktree and whose `--label` is the worktree name (branch name). Requires `herdr` on `PATH` and a running Herdr server.
- If the branch does not exist, it is created from the branch pointed at by `origin/HEAD`; set it explicitly with `--upstream` | `-u`.
- With `-r` | `--herdr`, also create a [Herdr](https://herdr.dev) workspace whose `--cwd` is the new worktree and whose `--label` is the worktree name (branch name). `wt create -r` implies `--no-cd`. Requires `herdr` on `PATH` and a running Herdr server.

Example:

```bash
git-wt create feature/login
git-wt create -u origin/v1.2 hotfix/1.2.1
git-wt create --herdr feature/login
git-wt create -r feature/login
```

### `git-wt list`
Expand Down
2 changes: 1 addition & 1 deletion internal/gitwt/gitwt_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func NewCreateCommand() *cobra.Command {
}

command.Flags().StringVarP(&options.upstream, "upstream", "u", "", "Upstream branch")
command.Flags().BoolVar(&options.herdr, "herdr", false, "Also create a Herdr workspace for the new worktree")
command.Flags().BoolVarP(&options.herdr, "herdr", "r", false, "Also create a Herdr workspace for the new worktree")

return command
}
Expand Down
14 changes: 14 additions & 0 deletions internal/gitwt/gitwt_generate_zsh.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ func (x *zshCommandOptions) writeFunctionFile(target string) error {
--no-cd)
no_cd=1
;;
-r|--herdr)
no_cd=1
forward+=("$arg")
;;
-u|--upstream)
forward+=("$arg")
skip_next=1
Expand Down Expand Up @@ -216,6 +220,16 @@ _` + x.name + `() {
fi

case $words[2] in
create)
shift words
(( CURRENT-- ))
_arguments \
'--no-cd[Create without changing directories]' \
'(-r --herdr)'{-r,--herdr}'[Also create a Herdr workspace for the new worktree]' \
'(-u --upstream)'{-u,--upstream}'[Upstream branch]:upstream branch:' \
'(-h --help)'{-h,--help}'[help for create]' \
'1:worktree name:'
;;
switch|remove)
if ! git rev-parse --is-inside-work-tree 1>/dev/null 2>/dev/null; then
return 1
Expand Down
45 changes: 43 additions & 2 deletions internal/gitwt/gitwt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,48 @@ func TestCreateSucceedsWithWorktreeConfig(t *testing.T) {
}
}

func TestCreateUsesOriginHeadAsDefaultUpstream(t *testing.T) {
const defaultBranch = "default"
const branchName = "feature/origin-head"
const fileName = "default.txt"
const fileContents = "default branch\n"

testRepository := newTestRepository(t)
runGitCommand(t, testRepository.mainPath, "checkout", "-b", defaultBranch, remoteName+"/main")
testRepository.writeFile(t, filepath.Join(testRepository.mainPath, fileName), fileContents)
runGitCommand(t, testRepository.mainPath, "add", fileName)
runGitCommand(t, testRepository.mainPath, "commit", "-m", "default branch")
runGitCommand(t, testRepository.mainPath, "push", "-u", remoteName, defaultBranch)
runGitCommand(t, testRepository.mainPath, "checkout", "main")
runGitCommand(t, testRepository.mainPath, "remote", "set-head", remoteName, defaultBranch)

result := testRepository.runGitWT(t, "create", branchName)
if result.err != nil {
t.Fatalf("create failed: %v\n%s", result.err, result.stderr)
}

createdCommit := strings.TrimSpace(runGitCommand(t, testRepository.mainPath, "rev-parse", branchName))
upstreamCommit := strings.TrimSpace(runGitCommand(t, testRepository.mainPath, "rev-parse", remoteName+"/"+defaultBranch))
if createdCommit != upstreamCommit {
t.Fatalf("created branch commit = %s, want %s", createdCommit, upstreamCommit)
}

upstream := strings.TrimSpace(runGitCommand(t, testRepository.mainPath, "rev-parse", "--abbrev-ref", branchName+"@{upstream}"))
if upstream != remoteName+"/"+defaultBranch {
t.Fatalf("created branch upstream = %q, want %q", upstream, remoteName+"/"+defaultBranch)
}
}

func TestCreateWithHerdrInvokesHerdrWorkspaceCreate(t *testing.T) {
const branchName = "feature/herdr"

testRepository := newTestRepository(t)
logPath := filepath.Join(t.TempDir(), "herdr.log")
installFakeHerdr(t, logPath, 0)

result := testRepository.runGitWT(t, "create", "--herdr", branchName)
result := testRepository.runGitWT(t, "create", "-r", branchName)
if result.err != nil {
t.Fatalf("create --herdr failed: %v\n%s", result.err, result.stderr)
t.Fatalf("create -r failed: %v\n%s", result.err, result.stderr)
}
testRepository.assertPathPresent(t, testRepository.worktreePath(branchName))
if !strings.Contains(result.stderr, "created herdr workspace "+branchName) {
Expand Down Expand Up @@ -462,6 +494,8 @@ func TestGenerateZshGeneratesWrapperFunctionAndCompletion(t *testing.T) {
"case \"$1\" in",
"create)",
"--no-cd)",
"-r|--herdr)",
"no_cd=1",
"command git-wt create \"${forward[@]}\"",
"switch)",
"remove)",
Expand All @@ -483,6 +517,9 @@ func TestGenerateZshGeneratesWrapperFunctionAndCompletion(t *testing.T) {
if strings.Contains(functionText, "${name//\\//.}") || strings.Contains(functionText, "${arg//\\//.}") {
t.Fatalf("function still normalizes slashes in paths:\n%s", functionText)
}
if !strings.Contains(functionText, "-r|--herdr)\n no_cd=1\n forward+=(\"$arg\")") {
t.Fatalf("function does not make --herdr imply --no-cd:\n%s", functionText)
}

completionText := string(completionContent)
for _, want := range []string{
Expand All @@ -491,6 +528,10 @@ func TestGenerateZshGeneratesWrapperFunctionAndCompletion(t *testing.T) {
"remove:Remove a managed Git worktree",
"create:Create a managed Git worktree",
"case $words[2] in",
"create)",
"--no-cd[Create without changing directories]",
"'(-r --herdr)'{-r,--herdr}'[Also create a Herdr workspace for the new worktree]'",
"'(-u --upstream)'{-u,--upstream}'[Upstream branch]:upstream branch:'",
"switch|remove)",
"worktrees=(main)",
"/.git/wt/",
Expand Down
Loading