2022-02-06 06:54:26 +02:00
|
|
|
package controllers
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"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/utils"
|
|
|
|
)
|
|
|
|
|
|
|
|
type BranchesController struct {
|
|
|
|
baseController
|
2023-03-23 09:47:29 +02:00
|
|
|
c *ControllerCommon
|
2022-02-06 06:54:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ types.IController = &BranchesController{}
|
|
|
|
|
|
|
|
func NewBranchesController(
|
2023-03-23 09:47:29 +02:00
|
|
|
common *ControllerCommon,
|
2022-02-06 06:54:26 +02:00
|
|
|
) *BranchesController {
|
|
|
|
return &BranchesController{
|
2023-03-23 09:47:29 +02:00
|
|
|
baseController: baseController{},
|
|
|
|
c: common,
|
2022-02-06 06:54:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
|
|
|
return []*types.Binding{
|
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Universal.Select),
|
2022-02-26 10:06:22 +02:00
|
|
|
Handler: self.checkSelected(self.press),
|
2022-02-06 06:54:26 +02:00
|
|
|
Description: self.c.Tr.LcCheckout,
|
|
|
|
},
|
2022-02-27 07:21:58 +02:00
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Universal.New),
|
|
|
|
Handler: self.checkSelected(self.newBranch),
|
|
|
|
Description: self.c.Tr.LcNewBranch,
|
|
|
|
},
|
2022-02-06 06:54:26 +02:00
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Branches.CreatePullRequest),
|
2022-02-26 10:06:22 +02:00
|
|
|
Handler: self.checkSelected(self.handleCreatePullRequest),
|
2022-02-06 06:54:26 +02:00
|
|
|
Description: self.c.Tr.LcCreatePullRequest,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Branches.ViewPullRequestOptions),
|
|
|
|
Handler: self.checkSelected(self.handleCreatePullRequestMenu),
|
|
|
|
Description: self.c.Tr.LcCreatePullRequestOptions,
|
|
|
|
OpensMenu: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Branches.CopyPullRequestURL),
|
2022-02-26 10:06:22 +02:00
|
|
|
Handler: self.copyPullRequestURL,
|
2022-02-06 06:54:26 +02:00
|
|
|
Description: self.c.Tr.LcCopyPullRequestURL,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Branches.CheckoutBranchByName),
|
2022-02-26 10:06:22 +02:00
|
|
|
Handler: self.checkoutByName,
|
2022-02-06 06:54:26 +02:00
|
|
|
Description: self.c.Tr.LcCheckoutByName,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Branches.ForceCheckoutBranch),
|
2022-02-26 10:06:22 +02:00
|
|
|
Handler: self.forceCheckout,
|
2022-02-06 06:54:26 +02:00
|
|
|
Description: self.c.Tr.LcForceCheckout,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Universal.Remove),
|
2022-02-26 10:06:22 +02:00
|
|
|
Handler: self.checkSelectedAndReal(self.delete),
|
2022-02-06 06:54:26 +02:00
|
|
|
Description: self.c.Tr.LcDeleteBranch,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Branches.RebaseBranch),
|
2022-02-26 10:06:22 +02:00
|
|
|
Handler: opts.Guards.OutsideFilterMode(self.rebase),
|
2022-02-06 06:54:26 +02:00
|
|
|
Description: self.c.Tr.LcRebaseBranch,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Branches.MergeIntoCurrentBranch),
|
2022-02-26 10:06:22 +02:00
|
|
|
Handler: opts.Guards.OutsideFilterMode(self.merge),
|
2022-02-06 06:54:26 +02:00
|
|
|
Description: self.c.Tr.LcMergeIntoCurrentBranch,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Branches.FastForward),
|
2022-02-26 10:06:22 +02:00
|
|
|
Handler: self.checkSelectedAndReal(self.fastForward),
|
2022-02-06 06:54:26 +02:00
|
|
|
Description: self.c.Tr.FastForward,
|
|
|
|
},
|
2023-02-08 15:40:18 +02:00
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Branches.CreateTag),
|
|
|
|
Handler: self.checkSelected(self.createTag),
|
|
|
|
Description: self.c.Tr.LcCreateTag,
|
|
|
|
},
|
2022-02-06 06:54:26 +02:00
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Commits.ViewResetOptions),
|
2022-02-26 10:06:22 +02:00
|
|
|
Handler: self.checkSelected(self.createResetMenu),
|
2022-02-06 06:54:26 +02:00
|
|
|
Description: self.c.Tr.LcViewResetOptions,
|
|
|
|
OpensMenu: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Branches.RenameBranch),
|
2022-02-26 10:06:22 +02:00
|
|
|
Handler: self.checkSelectedAndReal(self.rename),
|
2022-02-06 06:54:26 +02:00
|
|
|
Description: self.c.Tr.LcRenameBranch,
|
|
|
|
},
|
2022-04-08 17:06:07 +02:00
|
|
|
{
|
|
|
|
Key: opts.GetKey(opts.Config.Branches.SetUpstream),
|
|
|
|
Handler: self.checkSelected(self.setUpstream),
|
|
|
|
Description: self.c.Tr.LcSetUnsetUpstream,
|
|
|
|
OpensMenu: true,
|
|
|
|
},
|
2022-02-06 06:54:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-30 14:24:24 +02:00
|
|
|
func (self *BranchesController) GetOnRenderToMain() func() error {
|
|
|
|
return func() error {
|
2023-03-23 09:47:29 +02:00
|
|
|
return self.c.Helpers().Diff.WithDiffModeCheck(func() error {
|
2022-12-30 14:24:24 +02:00
|
|
|
var task types.UpdateTask
|
|
|
|
branch := self.context().GetSelected()
|
|
|
|
if branch == nil {
|
|
|
|
task = types.NewRenderStringTask(self.c.Tr.NoBranchesThisRepo)
|
|
|
|
} else {
|
|
|
|
cmdObj := self.c.Git().Branch.GetGraphCmdObj(branch.FullRefName())
|
|
|
|
|
|
|
|
task = types.NewRunPtyTask(cmdObj.GetCmd())
|
|
|
|
}
|
|
|
|
|
|
|
|
return self.c.RenderToMainViews(types.RefreshMainOpts{
|
|
|
|
Pair: self.c.MainViewPairs().Normal,
|
|
|
|
Main: &types.ViewUpdateOpts{
|
|
|
|
Title: self.c.Tr.LogTitle,
|
|
|
|
Task: task,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-08 17:06:07 +02:00
|
|
|
func (self *BranchesController) setUpstream(selectedBranch *models.Branch) error {
|
|
|
|
return self.c.Menu(types.CreateMenuOptions{
|
|
|
|
Title: self.c.Tr.Actions.SetUnsetUpstream,
|
|
|
|
Items: []*types.MenuItem{
|
|
|
|
{
|
2022-05-08 06:23:32 +02:00
|
|
|
LabelColumns: []string{self.c.Tr.LcUnsetUpstream},
|
2022-04-08 17:06:07 +02:00
|
|
|
OnPress: func() error {
|
2023-03-23 04:04:57 +02:00
|
|
|
if err := self.c.Git().Branch.UnsetUpstream(selectedBranch.Name); err != nil {
|
2022-04-08 17:06:07 +02:00
|
|
|
return self.c.Error(err)
|
|
|
|
}
|
2022-04-13 15:46:12 +02:00
|
|
|
if err := self.c.Refresh(types.RefreshOptions{
|
|
|
|
Mode: types.SYNC,
|
|
|
|
Scope: []types.RefreshableView{
|
|
|
|
types.BRANCHES,
|
|
|
|
types.COMMITS,
|
|
|
|
},
|
|
|
|
}); err != nil {
|
|
|
|
return self.c.Error(err)
|
|
|
|
}
|
2022-04-08 17:06:07 +02:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
Key: 'u',
|
|
|
|
},
|
|
|
|
{
|
2022-05-08 06:23:32 +02:00
|
|
|
LabelColumns: []string{self.c.Tr.LcSetUpstream},
|
2022-04-08 17:06:07 +02:00
|
|
|
OnPress: func() error {
|
2023-03-23 09:47:29 +02:00
|
|
|
return self.c.Helpers().Upstream.PromptForUpstreamWithoutInitialContent(selectedBranch, func(upstream string) error {
|
|
|
|
upstreamRemote, upstreamBranch, err := self.c.Helpers().Upstream.ParseUpstream(upstream)
|
2022-04-08 17:06:07 +02:00
|
|
|
if err != nil {
|
|
|
|
return self.c.Error(err)
|
|
|
|
}
|
|
|
|
|
2023-03-23 04:04:57 +02:00
|
|
|
if err := self.c.Git().Branch.SetUpstream(upstreamRemote, upstreamBranch, selectedBranch.Name); err != nil {
|
2022-04-08 17:06:07 +02:00
|
|
|
return self.c.Error(err)
|
|
|
|
}
|
2022-04-13 15:46:12 +02:00
|
|
|
if err := self.c.Refresh(types.RefreshOptions{
|
|
|
|
Mode: types.SYNC,
|
|
|
|
Scope: []types.RefreshableView{
|
|
|
|
types.BRANCHES,
|
|
|
|
types.COMMITS,
|
|
|
|
},
|
|
|
|
}); err != nil {
|
|
|
|
return self.c.Error(err)
|
|
|
|
}
|
2022-04-08 17:06:07 +02:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
},
|
|
|
|
Key: 's',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-02-06 06:54:26 +02:00
|
|
|
func (self *BranchesController) Context() types.Context {
|
|
|
|
return self.context()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *BranchesController) context() *context.BranchesContext {
|
2023-03-23 04:04:57 +02:00
|
|
|
return self.c.Contexts().Branches
|
2022-02-06 06:54:26 +02:00
|
|
|
}
|
|
|
|
|
2022-02-26 10:06:22 +02:00
|
|
|
func (self *BranchesController) press(selectedBranch *models.Branch) error {
|
2023-03-23 09:47:29 +02:00
|
|
|
if selectedBranch == self.c.Helpers().Refs.GetCheckedOutRef() {
|
2022-02-06 06:54:26 +02:00
|
|
|
return self.c.ErrorMsg(self.c.Tr.AlreadyCheckedOutBranch)
|
|
|
|
}
|
|
|
|
|
|
|
|
self.c.LogAction(self.c.Tr.Actions.CheckoutBranch)
|
2023-03-23 09:47:29 +02:00
|
|
|
return self.c.Helpers().Refs.CheckoutRef(selectedBranch.Name, types.CheckoutRefOptions{})
|
2022-02-06 06:54:26 +02:00
|
|
|
}
|
|
|
|
|
2022-02-26 10:06:22 +02:00
|
|
|
func (self *BranchesController) handleCreatePullRequest(selectedBranch *models.Branch) error {
|
|
|
|
return self.createPullRequest(selectedBranch.Name, "")
|
2022-02-06 06:54:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (self *BranchesController) handleCreatePullRequestMenu(selectedBranch *models.Branch) error {
|
2023-03-23 09:47:29 +02:00
|
|
|
checkedOutBranch := self.c.Helpers().Refs.GetCheckedOutRef()
|
2022-02-06 06:54:26 +02:00
|
|
|
|
|
|
|
return self.createPullRequestMenu(selectedBranch, checkedOutBranch)
|
|
|
|
}
|
|
|
|
|
2022-02-26 10:06:22 +02:00
|
|
|
func (self *BranchesController) copyPullRequestURL() error {
|
2022-02-06 06:54:26 +02:00
|
|
|
branch := self.context().GetSelected()
|
|
|
|
|
2023-03-23 04:04:57 +02:00
|
|
|
branchExistsOnRemote := self.c.Git().Remote.CheckRemoteBranchExists(branch.Name)
|
2022-02-06 06:54:26 +02:00
|
|
|
|
|
|
|
if !branchExistsOnRemote {
|
|
|
|
return self.c.Error(errors.New(self.c.Tr.NoBranchOnRemote))
|
|
|
|
}
|
|
|
|
|
2023-03-23 09:47:29 +02:00
|
|
|
url, err := self.c.Helpers().Host.GetPullRequestURL(branch.Name, "")
|
2022-02-06 06:54:26 +02:00
|
|
|
if err != nil {
|
|
|
|
return self.c.Error(err)
|
|
|
|
}
|
|
|
|
self.c.LogAction(self.c.Tr.Actions.CopyPullRequestURL)
|
2023-03-23 04:04:57 +02:00
|
|
|
if err := self.c.OS().CopyToClipboard(url); err != nil {
|
2022-02-06 06:54:26 +02:00
|
|
|
return self.c.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
self.c.Toast(self.c.Tr.PullRequestURLCopiedToClipboard)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-02-26 10:06:22 +02:00
|
|
|
func (self *BranchesController) forceCheckout() error {
|
2022-02-06 06:54:26 +02:00
|
|
|
branch := self.context().GetSelected()
|
|
|
|
message := self.c.Tr.SureForceCheckout
|
|
|
|
title := self.c.Tr.ForceCheckoutBranch
|
|
|
|
|
2022-03-30 08:48:29 +02:00
|
|
|
return self.c.Confirm(types.ConfirmOpts{
|
2022-02-06 06:54:26 +02:00
|
|
|
Title: title,
|
|
|
|
Prompt: message,
|
|
|
|
HandleConfirm: func() error {
|
|
|
|
self.c.LogAction(self.c.Tr.Actions.ForceCheckoutBranch)
|
2023-03-23 04:04:57 +02:00
|
|
|
if err := self.c.Git().Branch.Checkout(branch.Name, git_commands.CheckoutOptions{Force: true}); err != nil {
|
2022-02-06 06:54:26 +02:00
|
|
|
_ = self.c.Error(err)
|
|
|
|
}
|
|
|
|
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-02-26 10:06:22 +02:00
|
|
|
func (self *BranchesController) checkoutByName() error {
|
2022-02-06 06:54:26 +02:00
|
|
|
return self.c.Prompt(types.PromptOpts{
|
|
|
|
Title: self.c.Tr.BranchName + ":",
|
2023-03-23 09:47:29 +02:00
|
|
|
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetRefsSuggestionsFunc(),
|
2022-02-06 06:54:26 +02:00
|
|
|
HandleConfirm: func(response string) error {
|
|
|
|
self.c.LogAction("Checkout branch")
|
2023-03-23 09:47:29 +02:00
|
|
|
return self.c.Helpers().Refs.CheckoutRef(response, types.CheckoutRefOptions{
|
2022-02-06 06:54:26 +02:00
|
|
|
OnRefNotFound: func(ref string) error {
|
2022-03-30 08:48:29 +02:00
|
|
|
return self.c.Confirm(types.ConfirmOpts{
|
2022-02-06 06:54:26 +02:00
|
|
|
Title: self.c.Tr.BranchNotFoundTitle,
|
|
|
|
Prompt: fmt.Sprintf("%s %s%s", self.c.Tr.BranchNotFoundPrompt, ref, "?"),
|
|
|
|
HandleConfirm: func() error {
|
|
|
|
return self.createNewBranchWithName(ref)
|
|
|
|
},
|
|
|
|
})
|
|
|
|
},
|
|
|
|
})
|
2022-03-19 00:38:49 +02:00
|
|
|
},
|
|
|
|
},
|
2022-02-06 06:54:26 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *BranchesController) createNewBranchWithName(newBranchName string) error {
|
|
|
|
branch := self.context().GetSelected()
|
|
|
|
if branch == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-03-23 04:04:57 +02:00
|
|
|
if err := self.c.Git().Branch.New(newBranchName, branch.FullRefName()); err != nil {
|
2022-02-06 06:54:26 +02:00
|
|
|
return self.c.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
self.context().SetSelectedLineIdx(0)
|
|
|
|
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
|
|
|
}
|
|
|
|
|
2022-02-26 10:06:22 +02:00
|
|
|
func (self *BranchesController) delete(branch *models.Branch) error {
|
2023-03-23 09:47:29 +02:00
|
|
|
checkedOutBranch := self.c.Helpers().Refs.GetCheckedOutRef()
|
2022-02-06 06:54:26 +02:00
|
|
|
if checkedOutBranch.Name == branch.Name {
|
|
|
|
return self.c.ErrorMsg(self.c.Tr.CantDeleteCheckOutBranch)
|
|
|
|
}
|
2022-02-26 10:06:22 +02:00
|
|
|
return self.deleteWithForce(branch, false)
|
2022-02-06 06:54:26 +02:00
|
|
|
}
|
|
|
|
|
2022-02-26 10:06:22 +02:00
|
|
|
func (self *BranchesController) deleteWithForce(selectedBranch *models.Branch, force bool) error {
|
2022-02-06 06:54:26 +02:00
|
|
|
title := self.c.Tr.DeleteBranch
|
|
|
|
var templateStr string
|
|
|
|
if force {
|
|
|
|
templateStr = self.c.Tr.ForceDeleteBranchMessage
|
|
|
|
} else {
|
|
|
|
templateStr = self.c.Tr.DeleteBranchMessage
|
|
|
|
}
|
|
|
|
message := utils.ResolvePlaceholderString(
|
|
|
|
templateStr,
|
|
|
|
map[string]string{
|
|
|
|
"selectedBranchName": selectedBranch.Name,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
2022-03-30 08:48:29 +02:00
|
|
|
return self.c.Confirm(types.ConfirmOpts{
|
2022-02-06 06:54:26 +02:00
|
|
|
Title: title,
|
|
|
|
Prompt: message,
|
|
|
|
HandleConfirm: func() error {
|
|
|
|
self.c.LogAction(self.c.Tr.Actions.DeleteBranch)
|
2023-03-23 04:04:57 +02:00
|
|
|
if err := self.c.Git().Branch.Delete(selectedBranch.Name, force); err != nil {
|
2022-02-06 06:54:26 +02:00
|
|
|
errMessage := err.Error()
|
|
|
|
if !force && strings.Contains(errMessage, "git branch -D ") {
|
2022-02-26 10:06:22 +02:00
|
|
|
return self.deleteWithForce(selectedBranch, true)
|
2022-02-06 06:54:26 +02:00
|
|
|
}
|
|
|
|
return self.c.ErrorMsg(errMessage)
|
|
|
|
}
|
|
|
|
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-02-26 10:06:22 +02:00
|
|
|
func (self *BranchesController) merge() error {
|
2022-02-06 06:54:26 +02:00
|
|
|
selectedBranchName := self.context().GetSelected().Name
|
2023-03-23 09:47:29 +02:00
|
|
|
return self.c.Helpers().MergeAndRebase.MergeRefIntoCheckedOutBranch(selectedBranchName)
|
2022-02-06 06:54:26 +02:00
|
|
|
}
|
|
|
|
|
2022-02-26 10:06:22 +02:00
|
|
|
func (self *BranchesController) rebase() error {
|
2022-02-06 06:54:26 +02:00
|
|
|
selectedBranchName := self.context().GetSelected().Name
|
2023-03-23 09:47:29 +02:00
|
|
|
return self.c.Helpers().MergeAndRebase.RebaseOntoRef(selectedBranchName)
|
2022-02-06 06:54:26 +02:00
|
|
|
}
|
|
|
|
|
2022-02-26 10:06:22 +02:00
|
|
|
func (self *BranchesController) fastForward(branch *models.Branch) error {
|
2022-02-06 06:54:26 +02:00
|
|
|
if !branch.IsTrackingRemote() {
|
|
|
|
return self.c.ErrorMsg(self.c.Tr.FwdNoUpstream)
|
|
|
|
}
|
|
|
|
if !branch.RemoteBranchStoredLocally() {
|
|
|
|
return self.c.ErrorMsg(self.c.Tr.FwdNoLocalUpstream)
|
|
|
|
}
|
|
|
|
if branch.HasCommitsToPush() {
|
|
|
|
return self.c.ErrorMsg(self.c.Tr.FwdCommitsToPush)
|
|
|
|
}
|
|
|
|
|
|
|
|
action := self.c.Tr.Actions.FastForwardBranch
|
|
|
|
|
|
|
|
message := utils.ResolvePlaceholderString(
|
|
|
|
self.c.Tr.Fetching,
|
|
|
|
map[string]string{
|
|
|
|
"from": fmt.Sprintf("%s/%s", branch.UpstreamRemote, branch.UpstreamBranch),
|
|
|
|
"to": branch.Name,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
return self.c.WithLoaderPanel(message, func() error {
|
2023-03-23 09:47:29 +02:00
|
|
|
if branch == self.c.Helpers().Refs.GetCheckedOutRef() {
|
2022-02-06 06:54:26 +02:00
|
|
|
self.c.LogAction(action)
|
|
|
|
|
2023-03-23 04:04:57 +02:00
|
|
|
err := self.c.Git().Sync.Pull(
|
2022-02-06 06:54:26 +02:00
|
|
|
git_commands.PullOptions{
|
|
|
|
RemoteName: branch.UpstreamRemote,
|
2022-06-01 20:30:13 +02:00
|
|
|
BranchName: branch.UpstreamBranch,
|
2022-02-06 06:54:26 +02:00
|
|
|
FastForwardOnly: true,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
_ = self.c.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
|
|
|
} else {
|
|
|
|
self.c.LogAction(action)
|
2023-03-23 04:04:57 +02:00
|
|
|
err := self.c.Git().Sync.FastForward(branch.Name, branch.UpstreamRemote, branch.UpstreamBranch)
|
2022-02-06 06:54:26 +02:00
|
|
|
if err != nil {
|
|
|
|
_ = self.c.Error(err)
|
|
|
|
}
|
|
|
|
_ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-02-08 15:40:18 +02:00
|
|
|
func (self *BranchesController) createTag(branch *models.Branch) error {
|
2023-03-23 09:47:29 +02:00
|
|
|
return self.c.Helpers().Tags.CreateTagMenu(branch.FullRefName(), func() {})
|
2023-02-08 15:40:18 +02:00
|
|
|
}
|
|
|
|
|
2022-02-26 10:06:22 +02:00
|
|
|
func (self *BranchesController) createResetMenu(selectedBranch *models.Branch) error {
|
2023-03-23 09:47:29 +02:00
|
|
|
return self.c.Helpers().Refs.CreateGitResetMenu(selectedBranch.Name)
|
2022-02-06 06:54:26 +02:00
|
|
|
}
|
|
|
|
|
2022-02-26 10:06:22 +02:00
|
|
|
func (self *BranchesController) rename(branch *models.Branch) error {
|
2022-02-06 06:54:26 +02:00
|
|
|
promptForNewName := func() error {
|
|
|
|
return self.c.Prompt(types.PromptOpts{
|
|
|
|
Title: self.c.Tr.NewBranchNamePrompt + " " + branch.Name + ":",
|
|
|
|
InitialContent: branch.Name,
|
|
|
|
HandleConfirm: func(newBranchName string) error {
|
|
|
|
self.c.LogAction(self.c.Tr.Actions.RenameBranch)
|
2023-03-23 04:04:57 +02:00
|
|
|
if err := self.c.Git().Branch.Rename(branch.Name, newBranchName); err != nil {
|
2022-02-06 06:54:26 +02:00
|
|
|
return self.c.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// need to find where the branch is now so that we can re-select it. That means we need to refetch the branches synchronously and then find our branch
|
|
|
|
_ = self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
|
|
|
|
|
|
|
// now that we've got our stuff again we need to find that branch and reselect it.
|
2023-03-23 04:04:57 +02:00
|
|
|
for i, newBranch := range self.c.Model().Branches {
|
2022-02-06 06:54:26 +02:00
|
|
|
if newBranch.Name == newBranchName {
|
|
|
|
self.context().SetSelectedLineIdx(i)
|
|
|
|
if err := self.context().HandleRender(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// I could do an explicit check here for whether the branch is tracking a remote branch
|
|
|
|
// but if we've selected it we'll already know that via Pullables and Pullables.
|
|
|
|
// Bit of a hack but I'm lazy.
|
|
|
|
if !branch.IsTrackingRemote() {
|
|
|
|
return promptForNewName()
|
|
|
|
}
|
|
|
|
|
2022-03-30 08:48:29 +02:00
|
|
|
return self.c.Confirm(types.ConfirmOpts{
|
2022-02-06 06:54:26 +02:00
|
|
|
Title: self.c.Tr.LcRenameBranch,
|
|
|
|
Prompt: self.c.Tr.RenameBranchWarning,
|
|
|
|
HandleConfirm: promptForNewName,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-02-26 10:06:22 +02:00
|
|
|
func (self *BranchesController) newBranch(selectedBranch *models.Branch) error {
|
2023-03-23 09:47:29 +02:00
|
|
|
return self.c.Helpers().Refs.NewBranch(selectedBranch.FullRefName(), selectedBranch.RefName(), "")
|
2022-02-06 06:54:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (self *BranchesController) createPullRequestMenu(selectedBranch *models.Branch, checkedOutBranch *models.Branch) error {
|
|
|
|
menuItems := make([]*types.MenuItem, 0, 4)
|
|
|
|
|
2022-05-08 06:23:32 +02:00
|
|
|
fromToLabelColumns := func(from string, to string) []string {
|
2022-02-06 06:54:26 +02:00
|
|
|
return []string{fmt.Sprintf("%s → %s", from, to)}
|
|
|
|
}
|
|
|
|
|
|
|
|
menuItemsForBranch := func(branch *models.Branch) []*types.MenuItem {
|
|
|
|
return []*types.MenuItem{
|
|
|
|
{
|
2022-05-08 06:23:32 +02:00
|
|
|
LabelColumns: fromToLabelColumns(branch.Name, self.c.Tr.LcDefaultBranch),
|
2022-02-06 06:54:26 +02:00
|
|
|
OnPress: func() error {
|
|
|
|
return self.createPullRequest(branch.Name, "")
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2022-05-08 06:23:32 +02:00
|
|
|
LabelColumns: fromToLabelColumns(branch.Name, self.c.Tr.LcSelectBranch),
|
2022-02-06 06:54:26 +02:00
|
|
|
OnPress: func() error {
|
|
|
|
return self.c.Prompt(types.PromptOpts{
|
|
|
|
Title: branch.Name + " →",
|
2023-03-23 09:47:29 +02:00
|
|
|
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetBranchNameSuggestionsFunc(),
|
2022-02-06 06:54:26 +02:00
|
|
|
HandleConfirm: func(targetBranchName string) error {
|
|
|
|
return self.createPullRequest(branch.Name, targetBranchName)
|
2022-03-19 00:38:49 +02:00
|
|
|
},
|
|
|
|
})
|
2022-02-06 06:54:26 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if selectedBranch != checkedOutBranch {
|
|
|
|
menuItems = append(menuItems,
|
|
|
|
&types.MenuItem{
|
2022-05-08 06:23:32 +02:00
|
|
|
LabelColumns: fromToLabelColumns(checkedOutBranch.Name, selectedBranch.Name),
|
2022-02-06 06:54:26 +02:00
|
|
|
OnPress: func() error {
|
|
|
|
return self.createPullRequest(checkedOutBranch.Name, selectedBranch.Name)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
menuItems = append(menuItems, menuItemsForBranch(checkedOutBranch)...)
|
|
|
|
}
|
|
|
|
|
|
|
|
menuItems = append(menuItems, menuItemsForBranch(selectedBranch)...)
|
|
|
|
|
|
|
|
return self.c.Menu(types.CreateMenuOptions{Title: fmt.Sprintf(self.c.Tr.CreatePullRequestOptions), Items: menuItems})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *BranchesController) createPullRequest(from string, to string) error {
|
2023-03-23 09:47:29 +02:00
|
|
|
url, err := self.c.Helpers().Host.GetPullRequestURL(from, to)
|
2022-02-06 06:54:26 +02:00
|
|
|
if err != nil {
|
|
|
|
return self.c.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
self.c.LogAction(self.c.Tr.Actions.OpenPullRequest)
|
|
|
|
|
2023-03-23 04:04:57 +02:00
|
|
|
if err := self.c.OS().OpenLink(url); err != nil {
|
2022-02-06 06:54:26 +02:00
|
|
|
return self.c.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *BranchesController) checkSelected(callback func(*models.Branch) error) func() error {
|
|
|
|
return func() error {
|
|
|
|
selectedItem := self.context().GetSelected()
|
|
|
|
if selectedItem == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return callback(selectedItem)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *BranchesController) checkSelectedAndReal(callback func(*models.Branch) error) func() error {
|
|
|
|
return func() error {
|
|
|
|
selectedItem := self.context().GetSelected()
|
|
|
|
if selectedItem == nil || !selectedItem.IsRealBranch() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return callback(selectedItem)
|
|
|
|
}
|
|
|
|
}
|