mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-04-25 12:24:47 +02:00
Better local branch delete confirmation
Currently we try to delete a branch normally, and if git returns an error and its output contains the text "branch -D", then we prompt the user to force delete, and try again using -D. Besides just being ugly, this has the disadvantage that git's logic to decide whether a branch is merged is not very good; it only considers a branch merged if it is either reachable from the current head, or from its own upstream. In many cases I want to delete a branch that has been merged to master, but I don't have master checked out, so the current branch is really irrelevant, and it should rather (or in addition) check whether the branch is reachable from one of the main branches. The problem is that git doesn't know what those are. But lazygit does, so make the check on our side, prompt the user if necessary, and always use -D. This is both cleaner, and works better. See this mailing list discussion for more: https://lore.kernel.org/git/bf6308ce-3914-4b85-a04b-4a9716bac538@haller-berlin.de/
This commit is contained in:
parent
c4e5995cb9
commit
c712b1d0fe
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/mgutz/str"
|
"github.com/mgutz/str"
|
||||||
@ -260,3 +261,26 @@ func (self *BranchCommands) AllBranchesLogCmdObj() oscommands.ICmdObj {
|
|||||||
|
|
||||||
return self.cmd.New(str.ToArgv(candidates[i])).DontLog()
|
return self.cmd.New(str.ToArgv(candidates[i])).DontLog()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *BranchCommands) IsBranchMerged(branch *models.Branch, mainBranches *MainBranches) (bool, error) {
|
||||||
|
branchesToCheckAgainst := []string{"HEAD"}
|
||||||
|
if branch.RemoteBranchStoredLocally() {
|
||||||
|
branchesToCheckAgainst = append(branchesToCheckAgainst, fmt.Sprintf("%s@{upstream}", branch.Name))
|
||||||
|
}
|
||||||
|
branchesToCheckAgainst = append(branchesToCheckAgainst, mainBranches.Get()...)
|
||||||
|
|
||||||
|
cmdArgs := NewGitCmd("rev-list").
|
||||||
|
Arg("--max-count=1").
|
||||||
|
Arg(branch.Name).
|
||||||
|
Arg(lo.Map(branchesToCheckAgainst, func(branch string, _ int) string {
|
||||||
|
return fmt.Sprintf("^%s", branch)
|
||||||
|
})...).
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
stdout, _, err := self.cmd.New(cmdArgs).RunWithOutputs()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return stdout == "", nil
|
||||||
|
}
|
||||||
|
@ -107,7 +107,7 @@ func (gui *Gui) resetHelpersAndControllers() {
|
|||||||
Files: helpers.NewFilesHelper(helperCommon),
|
Files: helpers.NewFilesHelper(helperCommon),
|
||||||
WorkingTree: helpers.NewWorkingTreeHelper(helperCommon, refsHelper, commitsHelper, gpgHelper),
|
WorkingTree: helpers.NewWorkingTreeHelper(helperCommon, refsHelper, commitsHelper, gpgHelper),
|
||||||
Tags: helpers.NewTagsHelper(helperCommon, commitsHelper),
|
Tags: helpers.NewTagsHelper(helperCommon, commitsHelper),
|
||||||
BranchesHelper: helpers.NewBranchesHelper(helperCommon),
|
BranchesHelper: helpers.NewBranchesHelper(helperCommon, worktreeHelper),
|
||||||
GPG: helpers.NewGpgHelper(helperCommon),
|
GPG: helpers.NewGpgHelper(helperCommon),
|
||||||
MergeAndRebase: rebaseHelper,
|
MergeAndRebase: rebaseHelper,
|
||||||
MergeConflicts: mergeConflictsHelper,
|
MergeConflicts: mergeConflictsHelper,
|
||||||
|
@ -3,7 +3,6 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||||
@ -521,92 +520,14 @@ func (self *BranchesController) createNewBranchWithName(newBranchName string) er
|
|||||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, KeepBranchSelectionIndex: true})
|
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, KeepBranchSelectionIndex: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BranchesController) checkedOutByOtherWorktree(branch *models.Branch) bool {
|
|
||||||
return git_commands.CheckedOutByOtherWorktree(branch, self.c.Model().Worktrees)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *BranchesController) promptWorktreeBranchDelete(selectedBranch *models.Branch) error {
|
|
||||||
worktree, ok := self.worktreeForBranch(selectedBranch)
|
|
||||||
if !ok {
|
|
||||||
self.c.Log.Error("promptWorktreeBranchDelete out of sync with list of worktrees")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
title := utils.ResolvePlaceholderString(self.c.Tr.BranchCheckedOutByWorktree, map[string]string{
|
|
||||||
"worktreeName": worktree.Name,
|
|
||||||
"branchName": selectedBranch.Name,
|
|
||||||
})
|
|
||||||
return self.c.Menu(types.CreateMenuOptions{
|
|
||||||
Title: title,
|
|
||||||
Items: []*types.MenuItem{
|
|
||||||
{
|
|
||||||
Label: self.c.Tr.SwitchToWorktree,
|
|
||||||
OnPress: func() error {
|
|
||||||
return self.c.Helpers().Worktree.Switch(worktree, context.LOCAL_BRANCHES_CONTEXT_KEY)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Label: self.c.Tr.DetachWorktree,
|
|
||||||
Tooltip: self.c.Tr.DetachWorktreeTooltip,
|
|
||||||
OnPress: func() error {
|
|
||||||
return self.c.Helpers().Worktree.Detach(worktree)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Label: self.c.Tr.RemoveWorktree,
|
|
||||||
OnPress: func() error {
|
|
||||||
return self.c.Helpers().Worktree.Remove(worktree, false)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *BranchesController) localDelete(branch *models.Branch) error {
|
func (self *BranchesController) localDelete(branch *models.Branch) error {
|
||||||
if self.checkedOutByOtherWorktree(branch) {
|
return self.c.Helpers().BranchesHelper.ConfirmLocalDelete(branch)
|
||||||
return self.promptWorktreeBranchDelete(branch)
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(_ gocui.Task) error {
|
|
||||||
self.c.LogAction(self.c.Tr.Actions.DeleteLocalBranch)
|
|
||||||
err := self.c.Git().Branch.LocalDelete(branch.Name, false)
|
|
||||||
if err != nil && strings.Contains(err.Error(), "git branch -D ") {
|
|
||||||
return self.forceDelete(branch)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BranchesController) remoteDelete(branch *models.Branch) error {
|
func (self *BranchesController) remoteDelete(branch *models.Branch) error {
|
||||||
return self.c.Helpers().BranchesHelper.ConfirmDeleteRemote(branch.UpstreamRemote, branch.UpstreamBranch)
|
return self.c.Helpers().BranchesHelper.ConfirmDeleteRemote(branch.UpstreamRemote, branch.UpstreamBranch)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BranchesController) forceDelete(branch *models.Branch) error {
|
|
||||||
title := self.c.Tr.ForceDeleteBranchTitle
|
|
||||||
message := utils.ResolvePlaceholderString(
|
|
||||||
self.c.Tr.ForceDeleteBranchMessage,
|
|
||||||
map[string]string{
|
|
||||||
"selectedBranchName": branch.Name,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
self.c.Confirm(types.ConfirmOpts{
|
|
||||||
Title: title,
|
|
||||||
Prompt: message,
|
|
||||||
HandleConfirm: func() error {
|
|
||||||
if err := self.c.Git().Branch.LocalDelete(branch.Name, true); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *BranchesController) delete(branch *models.Branch) error {
|
func (self *BranchesController) delete(branch *models.Branch) error {
|
||||||
checkedOutBranch := self.c.Helpers().Refs.GetCheckedOutRef()
|
checkedOutBranch := self.c.Helpers().Refs.GetCheckedOutRef()
|
||||||
|
|
||||||
|
@ -4,20 +4,68 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BranchesHelper struct {
|
type BranchesHelper struct {
|
||||||
c *HelperCommon
|
c *HelperCommon
|
||||||
|
worktreeHelper *WorktreeHelper
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBranchesHelper(c *HelperCommon) *BranchesHelper {
|
func NewBranchesHelper(c *HelperCommon, worktreeHelper *WorktreeHelper) *BranchesHelper {
|
||||||
return &BranchesHelper{
|
return &BranchesHelper{
|
||||||
c: c,
|
c: c,
|
||||||
|
worktreeHelper: worktreeHelper,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *BranchesHelper) ConfirmLocalDelete(branch *models.Branch) error {
|
||||||
|
if self.checkedOutByOtherWorktree(branch) {
|
||||||
|
return self.promptWorktreeBranchDelete(branch)
|
||||||
|
}
|
||||||
|
|
||||||
|
isMerged, err := self.c.Git().Branch.IsBranchMerged(branch, self.c.Model().MainBranches)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
doDelete := func() error {
|
||||||
|
return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(_ gocui.Task) error {
|
||||||
|
self.c.LogAction(self.c.Tr.Actions.DeleteLocalBranch)
|
||||||
|
if err := self.c.Git().Branch.LocalDelete(branch.Name, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if isMerged {
|
||||||
|
return doDelete()
|
||||||
|
}
|
||||||
|
|
||||||
|
title := self.c.Tr.ForceDeleteBranchTitle
|
||||||
|
message := utils.ResolvePlaceholderString(
|
||||||
|
self.c.Tr.ForceDeleteBranchMessage,
|
||||||
|
map[string]string{
|
||||||
|
"selectedBranchName": branch.Name,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.c.Confirm(types.ConfirmOpts{
|
||||||
|
Title: title,
|
||||||
|
Prompt: message,
|
||||||
|
HandleConfirm: func() error {
|
||||||
|
return doDelete()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (self *BranchesHelper) ConfirmDeleteRemote(remoteName string, branchName string) error {
|
func (self *BranchesHelper) ConfirmDeleteRemote(remoteName string, branchName string) error {
|
||||||
title := utils.ResolvePlaceholderString(
|
title := utils.ResolvePlaceholderString(
|
||||||
self.c.Tr.DeleteBranchTitle,
|
self.c.Tr.DeleteBranchTitle,
|
||||||
@ -52,3 +100,48 @@ func (self *BranchesHelper) ConfirmDeleteRemote(remoteName string, branchName st
|
|||||||
func ShortBranchName(fullBranchName string) string {
|
func ShortBranchName(fullBranchName string) string {
|
||||||
return strings.TrimPrefix(strings.TrimPrefix(fullBranchName, "refs/heads/"), "refs/remotes/")
|
return strings.TrimPrefix(strings.TrimPrefix(fullBranchName, "refs/heads/"), "refs/remotes/")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *BranchesHelper) checkedOutByOtherWorktree(branch *models.Branch) bool {
|
||||||
|
return git_commands.CheckedOutByOtherWorktree(branch, self.c.Model().Worktrees)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *BranchesHelper) worktreeForBranch(branch *models.Branch) (*models.Worktree, bool) {
|
||||||
|
return git_commands.WorktreeForBranch(branch, self.c.Model().Worktrees)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *BranchesHelper) promptWorktreeBranchDelete(selectedBranch *models.Branch) error {
|
||||||
|
worktree, ok := self.worktreeForBranch(selectedBranch)
|
||||||
|
if !ok {
|
||||||
|
self.c.Log.Error("promptWorktreeBranchDelete out of sync with list of worktrees")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
title := utils.ResolvePlaceholderString(self.c.Tr.BranchCheckedOutByWorktree, map[string]string{
|
||||||
|
"worktreeName": worktree.Name,
|
||||||
|
"branchName": selectedBranch.Name,
|
||||||
|
})
|
||||||
|
return self.c.Menu(types.CreateMenuOptions{
|
||||||
|
Title: title,
|
||||||
|
Items: []*types.MenuItem{
|
||||||
|
{
|
||||||
|
Label: self.c.Tr.SwitchToWorktree,
|
||||||
|
OnPress: func() error {
|
||||||
|
return self.worktreeHelper.Switch(worktree, context.LOCAL_BRANCHES_CONTEXT_KEY)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Label: self.c.Tr.DetachWorktree,
|
||||||
|
Tooltip: self.c.Tr.DetachWorktreeTooltip,
|
||||||
|
OnPress: func() error {
|
||||||
|
return self.worktreeHelper.Detach(worktree)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Label: self.c.Tr.RemoveWorktree,
|
||||||
|
OnPress: func() error {
|
||||||
|
return self.worktreeHelper.Remove(worktree, false)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -15,27 +15,43 @@ var Delete = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
CloneIntoRemote("origin").
|
CloneIntoRemote("origin").
|
||||||
EmptyCommit("blah").
|
EmptyCommit("blah").
|
||||||
NewBranch("branch-one").
|
NewBranch("branch-one").
|
||||||
|
EmptyCommit("on branch-one 01").
|
||||||
PushBranchAndSetUpstream("origin", "branch-one").
|
PushBranchAndSetUpstream("origin", "branch-one").
|
||||||
|
EmptyCommit("on branch-one 02").
|
||||||
|
Checkout("master").
|
||||||
|
Merge("branch-one"). // branch-one is contained in master, so no delete confirmation
|
||||||
NewBranch("branch-two").
|
NewBranch("branch-two").
|
||||||
PushBranchAndSetUpstream("origin", "branch-two").
|
EmptyCommit("on branch-two 01").
|
||||||
EmptyCommit("deletion blocker").
|
PushBranchAndSetUpstream("origin", "branch-two"). // branch-two is contained in its own upstream, so no delete confirmation either
|
||||||
NewBranch("branch-three")
|
NewBranchFrom("branch-three", "master").
|
||||||
|
EmptyCommit("on branch-three 01").
|
||||||
|
NewBranch("current-head"). // branch-three is contained in the current head, so no delete confirmation
|
||||||
|
EmptyCommit("on current-head").
|
||||||
|
NewBranchFrom("branch-four", "master").
|
||||||
|
EmptyCommit("on branch-four 01").
|
||||||
|
PushBranchAndSetUpstream("origin", "branch-four").
|
||||||
|
EmptyCommit("on branch-four 02"). // branch-four is not contained in any of these, so we get a delete confirmation
|
||||||
|
Checkout("current-head")
|
||||||
},
|
},
|
||||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
t.Views().Branches().
|
t.Views().Branches().
|
||||||
Focus().
|
Focus().
|
||||||
Lines(
|
Lines(
|
||||||
MatchesRegexp(`\*.*branch-three`).IsSelected(),
|
Contains("current-head").IsSelected(),
|
||||||
MatchesRegexp(`branch-two`),
|
Contains("branch-four ↑1"),
|
||||||
MatchesRegexp(`branch-one`),
|
Contains("branch-three"),
|
||||||
MatchesRegexp(`master`),
|
Contains("branch-two ✓"),
|
||||||
|
Contains("master"),
|
||||||
|
Contains("branch-one ↑1"),
|
||||||
).
|
).
|
||||||
|
|
||||||
|
// Deleting the current branch is not possible
|
||||||
Press(keys.Universal.Remove).
|
Press(keys.Universal.Remove).
|
||||||
Tap(func() {
|
Tap(func() {
|
||||||
t.ExpectPopup().
|
t.ExpectPopup().
|
||||||
Menu().
|
Menu().
|
||||||
Tooltip(Contains("You cannot delete the checked out branch!")).
|
Tooltip(Contains("You cannot delete the checked out branch!")).
|
||||||
Title(Equals("Delete branch 'branch-three'?")).
|
Title(Equals("Delete branch 'current-head'?")).
|
||||||
Select(Contains("Delete local branch")).
|
Select(Contains("Delete local branch")).
|
||||||
Confirm().
|
Confirm().
|
||||||
Tap(func() {
|
Tap(func() {
|
||||||
@ -43,8 +59,51 @@ var Delete = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
}).
|
}).
|
||||||
Cancel()
|
Cancel()
|
||||||
}).
|
}).
|
||||||
|
|
||||||
|
// Delete branch-four. This is the only branch that is not fully merged, so we get
|
||||||
|
// a confirmation popup.
|
||||||
SelectNextItem().
|
SelectNextItem().
|
||||||
Press(keys.Universal.Remove).
|
Press(keys.Universal.Remove).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectPopup().
|
||||||
|
Menu().
|
||||||
|
Title(Equals("Delete branch 'branch-four'?")).
|
||||||
|
Select(Contains("Delete local branch")).
|
||||||
|
Confirm()
|
||||||
|
t.ExpectPopup().
|
||||||
|
Confirmation().
|
||||||
|
Title(Equals("Force delete branch")).
|
||||||
|
Content(Equals("'branch-four' is not fully merged. Are you sure you want to delete it?")).
|
||||||
|
Confirm()
|
||||||
|
}).
|
||||||
|
Lines(
|
||||||
|
Contains("current-head"),
|
||||||
|
Contains("branch-three").IsSelected(),
|
||||||
|
Contains("branch-two ✓"),
|
||||||
|
Contains("master"),
|
||||||
|
Contains("branch-one ↑1"),
|
||||||
|
).
|
||||||
|
|
||||||
|
// Delete branch-three. This branch is contained in the current head, so this just works
|
||||||
|
// without any confirmation.
|
||||||
|
Press(keys.Universal.Remove).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectPopup().
|
||||||
|
Menu().
|
||||||
|
Title(Equals("Delete branch 'branch-three'?")).
|
||||||
|
Select(Contains("Delete local branch")).
|
||||||
|
Confirm()
|
||||||
|
}).
|
||||||
|
Lines(
|
||||||
|
Contains("current-head"),
|
||||||
|
Contains("branch-two ✓").IsSelected(),
|
||||||
|
Contains("master"),
|
||||||
|
Contains("branch-one ↑1"),
|
||||||
|
).
|
||||||
|
|
||||||
|
// Delete branch-two. This branch is contained in its own upstream, so this just works
|
||||||
|
// without any confirmation.
|
||||||
|
Press(keys.Universal.Remove).
|
||||||
Tap(func() {
|
Tap(func() {
|
||||||
t.ExpectPopup().
|
t.ExpectPopup().
|
||||||
Menu().
|
Menu().
|
||||||
@ -52,18 +111,14 @@ var Delete = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Select(Contains("Delete local branch")).
|
Select(Contains("Delete local branch")).
|
||||||
Confirm()
|
Confirm()
|
||||||
}).
|
}).
|
||||||
Tap(func() {
|
|
||||||
t.ExpectPopup().
|
|
||||||
Confirmation().
|
|
||||||
Title(Equals("Force delete branch")).
|
|
||||||
Content(Equals("'branch-two' is not fully merged. Are you sure you want to delete it?")).
|
|
||||||
Confirm()
|
|
||||||
}).
|
|
||||||
Lines(
|
Lines(
|
||||||
MatchesRegexp(`\*.*branch-three`),
|
Contains("current-head"),
|
||||||
MatchesRegexp(`branch-one`).IsSelected(),
|
Contains("master").IsSelected(),
|
||||||
MatchesRegexp(`master`),
|
Contains("branch-one ↑1"),
|
||||||
).
|
).
|
||||||
|
|
||||||
|
// Delete remote branch of branch-one. We only get the normal remote branch confirmation for this one.
|
||||||
|
SelectNextItem().
|
||||||
Press(keys.Universal.Remove).
|
Press(keys.Universal.Remove).
|
||||||
Tap(func() {
|
Tap(func() {
|
||||||
t.ExpectPopup().
|
t.ExpectPopup().
|
||||||
@ -87,7 +142,10 @@ var Delete = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
|
|
||||||
t.Views().
|
t.Views().
|
||||||
RemoteBranches().
|
RemoteBranches().
|
||||||
Lines(Equals("branch-two")).
|
Lines(
|
||||||
|
Equals("branch-four"),
|
||||||
|
Equals("branch-two"),
|
||||||
|
).
|
||||||
Press(keys.Universal.Return)
|
Press(keys.Universal.Return)
|
||||||
|
|
||||||
t.Views().
|
t.Views().
|
||||||
@ -95,10 +153,13 @@ var Delete = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Focus()
|
Focus()
|
||||||
}).
|
}).
|
||||||
Lines(
|
Lines(
|
||||||
MatchesRegexp(`\*.*branch-three`),
|
Contains("current-head"),
|
||||||
MatchesRegexp(`branch-one \(upstream gone\)`).IsSelected(),
|
Contains("master"),
|
||||||
MatchesRegexp(`master`),
|
Contains("branch-one (upstream gone)").IsSelected(),
|
||||||
).
|
).
|
||||||
|
|
||||||
|
// Delete local branch of branch-one. Even though its upstream is gone, we don't get a confirmation
|
||||||
|
// because it is contained in master.
|
||||||
Press(keys.Universal.Remove).
|
Press(keys.Universal.Remove).
|
||||||
Tap(func() {
|
Tap(func() {
|
||||||
t.ExpectPopup().
|
t.ExpectPopup().
|
||||||
@ -108,8 +169,8 @@ var Delete = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Confirm()
|
Confirm()
|
||||||
}).
|
}).
|
||||||
Lines(
|
Lines(
|
||||||
MatchesRegexp(`\*.*branch-three`),
|
Contains("current-head"),
|
||||||
MatchesRegexp(`master`).IsSelected(),
|
Contains("master").IsSelected(),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user