mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
Rework the worktrees-panel 'n' into a branch picker
The old 'n' flow opened a "normal vs detached" menu (the same meaningless gate the 'w' flow used to have), then asked for a base ref, a path typed from scratch, and a branch name in three separate prompts. Replace it with a single picker prompt titled "New worktree for branch", suggesting local branches not already checked out anywhere, plus remote branches that don't yet have a local branch of the same name. The entered value is classified on confirm: an existing local branch checks out into a new worktree, a remote branch creates a new local tracking branch, and anything else creates a new branch off the current ref. All three then feed the same location menu the 'w' flow uses, so paths are chosen from candidates rather than typed blind. Picking a remote or new branch needs no separate name prompt — the picker value already is the name. Checked-out branches are filtered from the suggestions, and a verbatim type-in of one is rejected with an error. createWorktree now takes the context to switch focus to once the worktree is created, so 'n' lands back in the worktrees panel while 'w' still lands in the branches panel. This deletes the old NewWorktree / NewWorktreeCheckout core and the now- orphaned i18n (CreateWorktreeFrom, CreateWorktreeFromDetached, NewWorktreeBase, NewBranchNameLeaveBlank), completing the migration started for 'w'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
23d01ac1bd
commit
768d9f1a3f
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/jesseduffield/generics/set"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
|
||||
|
|
@ -84,6 +85,28 @@ func (self *SuggestionsHelper) GetBranchNameSuggestionsFunc() func(string) []*ty
|
|||
}
|
||||
}
|
||||
|
||||
// GetWorktreeBranchNameSuggestionsFunc suggests branches you can base a new
|
||||
// worktree on: local branches that aren't checked out in any worktree (you can't
|
||||
// make a second worktree for them), plus remote branches that don't yet have a
|
||||
// local branch of the same name. Picking a remote branch creates a new local
|
||||
// tracking branch, which would fail if that local branch already existed (whether
|
||||
// or not it's checked out), so we leave those out and you reach the branch via its
|
||||
// local entry instead.
|
||||
func (self *SuggestionsHelper) GetWorktreeBranchNameSuggestionsFunc() func(string) []*types.Suggestion {
|
||||
localBranchNames := lo.FilterMap(self.c.Model().Branches, func(branch *models.Branch, _ int) (string, bool) {
|
||||
_, checkedOut := git_commands.WorktreeForBranch(branch, self.c.Model().Worktrees)
|
||||
return branch.Name, !checkedOut
|
||||
})
|
||||
|
||||
existingLocalBranches := set.NewFromSlice(self.getBranchNames())
|
||||
remoteBranchNames := lo.Filter(self.getRemoteBranchNames("/"), func(remoteBranchName string, _ int) bool {
|
||||
_, branchName, _ := strings.Cut(remoteBranchName, "/")
|
||||
return !existingLocalBranches.Includes(branchName)
|
||||
})
|
||||
|
||||
return FilterFunc(append(localBranchNames, remoteBranchNames...), self.c.UserConfig().Gui.UseFuzzySearch())
|
||||
}
|
||||
|
||||
// here we asynchronously fetch the latest set of paths in the repo and store in
|
||||
// self.c.Model().FilesTrie. On the main thread we'll be doing a fuzzy search via
|
||||
// self.c.Model().FilesTrie. So if we've looked for a file previously, we'll start with
|
||||
|
|
|
|||
|
|
@ -57,105 +57,58 @@ func (self *WorktreeHelper) GetLinkedWorktreeName() string {
|
|||
}
|
||||
|
||||
func (self *WorktreeHelper) NewWorktree() error {
|
||||
branch := self.refsHelper.GetCheckedOutRef()
|
||||
currentBranchName := branch.RefName()
|
||||
|
||||
f := func(detached bool) {
|
||||
self.c.Prompt(types.PromptOpts{
|
||||
Title: self.c.Tr.NewWorktreeBase,
|
||||
InitialContent: currentBranchName,
|
||||
FindSuggestionsFunc: self.suggestionsHelper.GetRefsSuggestionsFunc(),
|
||||
HandleConfirm: func(base string) error {
|
||||
// we assume that the base can be checked out
|
||||
canCheckoutBase := true
|
||||
return self.NewWorktreeCheckout(base, canCheckoutBase, detached, context.WORKTREES_CONTEXT_KEY)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
placeholders := map[string]string{"ref": "ref"}
|
||||
|
||||
return self.c.Menu(types.CreateMenuOptions{
|
||||
Title: self.c.Tr.WorktreeTitle,
|
||||
Items: []*types.MenuItem{
|
||||
{
|
||||
LabelColumns: []string{utils.ResolvePlaceholderString(self.c.Tr.CreateWorktreeFrom, placeholders)},
|
||||
OnPress: func() error {
|
||||
f(false)
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
LabelColumns: []string{utils.ResolvePlaceholderString(self.c.Tr.CreateWorktreeFromDetached, placeholders)},
|
||||
OnPress: func() error {
|
||||
f(true)
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (self *WorktreeHelper) NewWorktreeCheckout(base string, canCheckoutBase bool, detached bool, contextKey types.ContextKey) error {
|
||||
opts := git_commands.NewWorktreeOpts{
|
||||
Base: base,
|
||||
Detach: detached,
|
||||
}
|
||||
|
||||
f := func() error {
|
||||
return self.c.WithWaitingStatus(self.c.Tr.AddingWorktree, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.AddWorktree)
|
||||
if err := self.c.Git().Worktree.New(opts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.reposHelper.DispatchSwitchTo(opts.Path, self.c.Tr.ErrWorktreeMovedOrRemoved, contextKey)
|
||||
})
|
||||
}
|
||||
|
||||
self.c.Prompt(types.PromptOpts{
|
||||
Title: self.c.Tr.NewWorktreePath,
|
||||
HandleConfirm: func(path string) error {
|
||||
opts.Path = path
|
||||
|
||||
if detached {
|
||||
return f()
|
||||
}
|
||||
|
||||
if canCheckoutBase {
|
||||
title := utils.ResolvePlaceholderString(self.c.Tr.NewBranchNameLeaveBlank, map[string]string{"default": base})
|
||||
// prompt for the new branch name where a blank means we just check out the branch
|
||||
self.c.Prompt(types.PromptOpts{
|
||||
Title: title,
|
||||
HandleConfirm: func(branchName string) error {
|
||||
opts.Branch = branchName
|
||||
|
||||
return f()
|
||||
},
|
||||
AllowEmptyInput: true,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// prompt for the new branch name
|
||||
self.c.Prompt(types.PromptOpts{
|
||||
Title: self.c.Tr.NewBranchName,
|
||||
HandleConfirm: func(branchName string) error {
|
||||
opts.Branch = branchName
|
||||
|
||||
return f()
|
||||
},
|
||||
AllowEmptyInput: false,
|
||||
})
|
||||
|
||||
return nil
|
||||
Title: self.c.Tr.NewWorktreeForBranchTitle,
|
||||
FindSuggestionsFunc: self.suggestionsHelper.GetWorktreeBranchNameSuggestionsFunc(),
|
||||
HandleConfirm: func(value string) error {
|
||||
return self.newWorktreeForPickerValue(value)
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// newWorktreeForPickerValue classifies the value the user picked or typed in the
|
||||
// worktrees-panel picker and routes to the matching creation flow:
|
||||
// - an existing local branch -> a worktree that checks it out;
|
||||
// - a remote branch -> a new local tracking branch + worktree;
|
||||
// - anything else -> a new branch off the current ref + worktree.
|
||||
//
|
||||
// All three then feed the shared location menu. The picker filters out branches
|
||||
// already checked out somewhere, but a verbatim type-in is still guarded here.
|
||||
func (self *WorktreeHelper) newWorktreeForPickerValue(value string) error {
|
||||
if branch, ok := lo.Find(self.c.Model().Branches, func(branch *models.Branch) bool {
|
||||
return branch.Name == value
|
||||
}); ok {
|
||||
if worktree, ok := git_commands.WorktreeForBranch(branch, self.c.Model().Worktrees); ok {
|
||||
return errors.New(utils.ResolvePlaceholderString(self.c.Tr.BranchCheckedOutByWorktree,
|
||||
map[string]string{"branchName": branch.Name, "worktreeName": worktree.Name}))
|
||||
}
|
||||
|
||||
prompt := utils.ResolvePlaceholderString(self.c.Tr.WorktreeLocationPromptCheckout,
|
||||
map[string]string{"branchName": branch.Name})
|
||||
return self.promptForWorktreeLocation(branch.Name, prompt, func(path string) error {
|
||||
return self.createWorktree(git_commands.NewWorktreeOpts{Path: path, Base: branch.RefName()}, context.WORKTREES_CONTEXT_KEY)
|
||||
})
|
||||
}
|
||||
|
||||
if _, branchName, ok := self.refsHelper.ParseRemoteBranchName(value); ok {
|
||||
prompt := utils.ResolvePlaceholderString(self.c.Tr.WorktreeLocationPromptTrackingBranch,
|
||||
map[string]string{"name": branchName, "ref": value})
|
||||
return self.promptForWorktreeLocation(branchName, prompt, func(path string) error {
|
||||
return self.createWorktree(git_commands.NewWorktreeOpts{Path: path, Base: value, Branch: branchName}, context.WORKTREES_CONTEXT_KEY)
|
||||
})
|
||||
}
|
||||
|
||||
name := SanitizedBranchName(value)
|
||||
base := self.refsHelper.GetCheckedOutRef().RefName()
|
||||
prompt := utils.ResolvePlaceholderString(self.c.Tr.WorktreeLocationPromptNewBranch,
|
||||
map[string]string{"name": name, "base": base})
|
||||
return self.promptForWorktreeLocation(name, prompt, func(path string) error {
|
||||
return self.createWorktree(git_commands.NewWorktreeOpts{Path: path, Base: base, Branch: name}, context.WORKTREES_CONTEXT_KEY)
|
||||
})
|
||||
}
|
||||
|
||||
func (self *WorktreeHelper) Switch(worktree *models.Worktree, contextKey types.ContextKey) error {
|
||||
if worktree.IsCurrent {
|
||||
return errors.New(self.c.Tr.AlreadyInWorktree)
|
||||
|
|
@ -339,7 +292,7 @@ func (self *WorktreeHelper) newLocalBranchAndWorktreeItem(remoteBranch *models.R
|
|||
func (self *WorktreeHelper) startNewBranchWorktree(nameInitialContent string, base string, locationPrompt func(name string) string) error {
|
||||
return self.promptForName(self.c.Tr.NewBranchAndWorktreeName, nameInitialContent, func(name string) error {
|
||||
return self.promptForWorktreeLocation(name, locationPrompt(name), func(path string) error {
|
||||
return self.createWorktree(git_commands.NewWorktreeOpts{Path: path, Base: base, Branch: name})
|
||||
return self.createWorktree(git_commands.NewWorktreeOpts{Path: path, Base: base, Branch: name}, context.LOCAL_BRANCHES_CONTEXT_KEY)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -354,7 +307,7 @@ func (self *WorktreeHelper) worktreeForBranchItem(branch *models.Branch) *types.
|
|||
prompt := utils.ResolvePlaceholderString(self.c.Tr.WorktreeLocationPromptCheckout,
|
||||
map[string]string{"branchName": branch.Name})
|
||||
return self.promptForWorktreeLocation(branch.Name, prompt, func(path string) error {
|
||||
return self.createWorktree(git_commands.NewWorktreeOpts{Path: path, Base: branch.RefName()})
|
||||
return self.createWorktree(git_commands.NewWorktreeOpts{Path: path, Base: branch.RefName()}, context.LOCAL_BRANCHES_CONTEXT_KEY)
|
||||
})
|
||||
},
|
||||
DisabledReason: self.branchCheckedOutDisabledReason(branch),
|
||||
|
|
@ -368,7 +321,7 @@ func (self *WorktreeHelper) worktreeForBranchItem(branch *models.Branch) *types.
|
|||
func (self *WorktreeHelper) detachedWorktreeItem(ref string, base string, defaultDirName string) *types.MenuItem {
|
||||
prompt := utils.ResolvePlaceholderString(self.c.Tr.WorktreeLocationPromptDetached, map[string]string{"ref": ref})
|
||||
create := func(path string) error {
|
||||
return self.createWorktree(git_commands.NewWorktreeOpts{Path: path, Base: base, Detach: true})
|
||||
return self.createWorktree(git_commands.NewWorktreeOpts{Path: path, Base: base, Detach: true}, context.LOCAL_BRANCHES_CONTEXT_KEY)
|
||||
}
|
||||
|
||||
return &types.MenuItem{
|
||||
|
|
@ -458,13 +411,13 @@ func (self *WorktreeHelper) promptForWorktreeLocation(dirName string, prompt str
|
|||
})
|
||||
}
|
||||
|
||||
func (self *WorktreeHelper) createWorktree(opts git_commands.NewWorktreeOpts) error {
|
||||
func (self *WorktreeHelper) createWorktree(opts git_commands.NewWorktreeOpts, contextKey types.ContextKey) error {
|
||||
return self.c.WithWaitingStatus(self.c.Tr.AddingWorktree, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.AddWorktree)
|
||||
if err := self.c.Git().Worktree.New(opts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.reposHelper.DispatchSwitchTo(opts.Path, self.c.Tr.ErrWorktreeMovedOrRemoved, context.LOCAL_BRANCHES_CONTEXT_KEY)
|
||||
return self.reposHelper.DispatchSwitchTo(opts.Path, self.c.Tr.ErrWorktreeMovedOrRemoved, contextKey)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -890,13 +890,10 @@ type TranslationSet struct {
|
|||
MainWorktree string
|
||||
NewWorktree string
|
||||
NewWorktreePath string
|
||||
NewWorktreeBase string
|
||||
RemoveWorktreeTooltip string
|
||||
NewBranchName string
|
||||
NewBranchNameLeaveBlank string
|
||||
CreateWorktreeFrom string
|
||||
CreateWorktreeFromDetached string
|
||||
NewWorktreeName string
|
||||
NewWorktreeForBranchTitle string
|
||||
NewBranchAndWorktreeName string
|
||||
NewBranchAndWorktreeFromRef string
|
||||
NewLocalBranchAndWorktreeFromRef string
|
||||
|
|
@ -2035,13 +2032,10 @@ func EnglishTranslationSet() *TranslationSet {
|
|||
MainWorktree: "(main worktree)",
|
||||
NewWorktree: "New worktree",
|
||||
NewWorktreePath: "New worktree path",
|
||||
NewWorktreeBase: "New worktree base ref",
|
||||
RemoveWorktreeTooltip: "Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory.",
|
||||
NewBranchName: "New branch name",
|
||||
NewBranchNameLeaveBlank: "New branch name (leave blank to checkout {{.default}})",
|
||||
CreateWorktreeFrom: "Create worktree from {{.ref}}",
|
||||
CreateWorktreeFromDetached: "Create worktree from {{.ref}} (detached)",
|
||||
NewWorktreeName: "New worktree name",
|
||||
NewWorktreeForBranchTitle: "New worktree for branch",
|
||||
NewBranchAndWorktreeName: "New branch and worktree name",
|
||||
NewBranchAndWorktreeFromRef: "New branch and worktree from '{{.ref}}'",
|
||||
NewLocalBranchAndWorktreeFromRef: "New local branch and worktree from '{{.ref}}'",
|
||||
|
|
|
|||
|
|
@ -517,6 +517,8 @@ var tests = []*components.IntegrationTest{
|
|||
worktree.ForceRemoveWorktree,
|
||||
worktree.ForceRemoveWorktreeWithSubmodules,
|
||||
worktree.LocationCandidates,
|
||||
worktree.NewWorktreePicker,
|
||||
worktree.NewWorktreePickerRemote,
|
||||
worktree.RemoveWorktreeFromBranch,
|
||||
worktree.ResetWindowTabs,
|
||||
worktree.SymlinkIntoRepoSubdir,
|
||||
|
|
|
|||
|
|
@ -33,25 +33,23 @@ var Crud = NewIntegrationTest(NewIntegrationTestArgs{
|
|||
).
|
||||
Press(keys.Universal.New).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("Worktree")).
|
||||
Select(Contains(`Create worktree from ref`).DoesNotContain(("detached"))).
|
||||
// a name that isn't an existing branch creates a new branch off
|
||||
// the current one
|
||||
t.ExpectPopup().Prompt().
|
||||
Title(Equals("New worktree for branch")).
|
||||
Type("newbranch").
|
||||
Confirm()
|
||||
|
||||
t.ExpectPopup().Prompt().
|
||||
Title(Equals("New worktree base ref")).
|
||||
InitialText(Equals("mybranch")).
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("Worktree location")).
|
||||
Select(Contains("Other…")).
|
||||
Confirm()
|
||||
|
||||
t.ExpectPopup().Prompt().
|
||||
Title(Equals("New worktree path")).
|
||||
Clear().
|
||||
Type("../linked-worktree").
|
||||
Confirm()
|
||||
|
||||
t.ExpectPopup().Prompt().
|
||||
Title(Equals("New branch name (leave blank to checkout mybranch)")).
|
||||
Type("newbranch").
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Contains("linked-worktree").IsSelected(),
|
||||
|
|
|
|||
64
pkg/integration/tests/worktree/new_worktree_picker.go
Normal file
64
pkg/integration/tests/worktree/new_worktree_picker.go
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
package worktree
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var NewWorktreePicker = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "From the worktrees panel, the picker suggests only branches not already checked out, guards verbatim type-ins, and checks out an existing branch",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.NewBranch("mybranch")
|
||||
shell.CreateFileAndAdd("README.md", "hello world")
|
||||
shell.Commit("initial commit")
|
||||
shell.NewBranchFrom("feature", "mybranch")
|
||||
shell.Checkout("mybranch")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Worktrees().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("(main worktree)"),
|
||||
).
|
||||
Press(keys.Universal.New).
|
||||
Tap(func() {
|
||||
// mybranch is checked out by the current worktree, so it's not
|
||||
// suggested; feature is
|
||||
t.ExpectPopup().Prompt().
|
||||
Title(Equals("New worktree for branch")).
|
||||
SuggestionLines(Contains("feature")).
|
||||
// typing a checked-out branch verbatim is still rejected
|
||||
Type("mybranch").
|
||||
Confirm()
|
||||
|
||||
t.ExpectPopup().Alert().
|
||||
Title(Equals("Error")).
|
||||
Content(Contains("Branch mybranch is checked out by worktree repo")).
|
||||
Confirm()
|
||||
}).
|
||||
Press(keys.Universal.New).
|
||||
Tap(func() {
|
||||
// picking an existing branch checks it out (no new branch)
|
||||
t.ExpectPopup().Prompt().
|
||||
Title(Equals("New worktree for branch")).
|
||||
Type("feature").
|
||||
Confirm()
|
||||
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("Worktree location")).
|
||||
Confirm()
|
||||
}).
|
||||
// we stay in the worktrees panel, now switched into the new worktree
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("feature").IsSelected(),
|
||||
Contains("(main worktree)"),
|
||||
)
|
||||
|
||||
t.Views().Status().
|
||||
Content(Contains("repo(feature) → feature"))
|
||||
},
|
||||
})
|
||||
60
pkg/integration/tests/worktree/new_worktree_picker_remote.go
Normal file
60
pkg/integration/tests/worktree/new_worktree_picker_remote.go
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
package worktree
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var NewWorktreePickerRemote = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "From the worktrees panel, picking a remote branch creates a new local tracking branch and worktree; remote branches whose local branch already exists are filtered out",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.CreateFileAndAdd("README.md", "hello world")
|
||||
shell.Commit("initial commit")
|
||||
shell.NewBranch("feature")
|
||||
shell.NewBranch("existing")
|
||||
shell.CloneIntoRemote("origin")
|
||||
shell.Checkout("master")
|
||||
// "feature" now exists only on the remote; "existing" stays as a local
|
||||
// branch (not checked out) that also has a remote counterpart
|
||||
shell.RunCommand([]string{"git", "branch", "-D", "feature"})
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Worktrees().
|
||||
Focus().
|
||||
Press(keys.Universal.New).
|
||||
Tap(func() {
|
||||
// master is checked out, so neither it nor origin/master is
|
||||
// offered; "existing" already has a local branch, so
|
||||
// origin/existing is left out too (you'd reach it via the local
|
||||
// entry); origin/feature has no local branch, so it's offered
|
||||
t.ExpectPopup().Prompt().
|
||||
Title(Equals("New worktree for branch")).
|
||||
SuggestionLines(
|
||||
Contains("existing"),
|
||||
Contains("origin/feature"),
|
||||
).
|
||||
Type("origin/feature").
|
||||
Confirm()
|
||||
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("Worktree location")).
|
||||
Confirm()
|
||||
}).
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("feature").IsSelected(),
|
||||
Contains("(main worktree)"),
|
||||
)
|
||||
|
||||
// the new worktree is on a local branch that tracks the remote one (the
|
||||
// ✓ confirms tracking is set up)
|
||||
t.Views().Branches().
|
||||
Focus().
|
||||
ContainsLines(
|
||||
Contains("feature").Contains("✓").IsSelected(),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
|
@ -28,25 +28,21 @@ var WorktreeInRepo = NewIntegrationTest(NewIntegrationTestArgs{
|
|||
).
|
||||
Press(keys.Universal.New).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("Worktree")).
|
||||
Select(Contains(`Create worktree from ref`).DoesNotContain(("detached"))).
|
||||
t.ExpectPopup().Prompt().
|
||||
Title(Equals("New worktree for branch")).
|
||||
Type("newbranch").
|
||||
Confirm()
|
||||
|
||||
t.ExpectPopup().Prompt().
|
||||
Title(Equals("New worktree base ref")).
|
||||
InitialText(Equals("mybranch")).
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("Worktree location")).
|
||||
Select(Contains("Other…")).
|
||||
Confirm()
|
||||
|
||||
t.ExpectPopup().Prompt().
|
||||
Title(Equals("New worktree path")).
|
||||
Clear().
|
||||
Type("linked-worktree").
|
||||
Confirm()
|
||||
|
||||
t.ExpectPopup().Prompt().
|
||||
Title(Equals("New branch name (leave blank to checkout mybranch)")).
|
||||
Type("newbranch").
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Contains("linked-worktree").IsSelected(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue