2022-02-06 15:54:26 +11:00
package controllers
import (
"errors"
"fmt"
"strings"
2023-07-09 11:32:27 +10:00
"github.com/jesseduffield/gocui"
2022-02-06 15:54:26 +11:00
"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 18:47:29 +11:00
c * ControllerCommon
2022-02-06 15:54:26 +11:00
}
var _ types . IController = & BranchesController { }
func NewBranchesController (
2023-03-23 18:47:29 +11:00
common * ControllerCommon ,
2022-02-06 15:54:26 +11:00
) * BranchesController {
return & BranchesController {
2023-03-23 18:47:29 +11:00
baseController : baseController { } ,
c : common ,
2022-02-06 15:54:26 +11:00
}
}
func ( self * BranchesController ) GetKeybindings ( opts types . KeybindingsOpts ) [ ] * types . Binding {
return [ ] * types . Binding {
{
Key : opts . GetKey ( opts . Config . Universal . Select ) ,
2022-02-26 19:06:22 +11:00
Handler : self . checkSelected ( self . press ) ,
2023-05-25 21:11:51 +10:00
Description : self . c . Tr . Checkout ,
2022-02-06 15:54:26 +11:00
} ,
2022-02-27 16:21:58 +11:00
{
Key : opts . GetKey ( opts . Config . Universal . New ) ,
Handler : self . checkSelected ( self . newBranch ) ,
2023-05-25 21:11:51 +10:00
Description : self . c . Tr . NewBranch ,
2022-02-27 16:21:58 +11:00
} ,
2022-02-06 15:54:26 +11:00
{
Key : opts . GetKey ( opts . Config . Branches . CreatePullRequest ) ,
2022-02-26 19:06:22 +11:00
Handler : self . checkSelected ( self . handleCreatePullRequest ) ,
2023-05-25 21:11:51 +10:00
Description : self . c . Tr . CreatePullRequest ,
2022-02-06 15:54:26 +11:00
} ,
{
Key : opts . GetKey ( opts . Config . Branches . ViewPullRequestOptions ) ,
Handler : self . checkSelected ( self . handleCreatePullRequestMenu ) ,
2023-05-25 21:11:51 +10:00
Description : self . c . Tr . CreatePullRequestOptions ,
2022-02-06 15:54:26 +11:00
OpensMenu : true ,
} ,
{
Key : opts . GetKey ( opts . Config . Branches . CopyPullRequestURL ) ,
2022-02-26 19:06:22 +11:00
Handler : self . copyPullRequestURL ,
2023-05-25 21:11:51 +10:00
Description : self . c . Tr . CopyPullRequestURL ,
2022-02-06 15:54:26 +11:00
} ,
{
Key : opts . GetKey ( opts . Config . Branches . CheckoutBranchByName ) ,
2022-02-26 19:06:22 +11:00
Handler : self . checkoutByName ,
2023-05-25 21:11:51 +10:00
Description : self . c . Tr . CheckoutByName ,
2022-02-06 15:54:26 +11:00
} ,
{
Key : opts . GetKey ( opts . Config . Branches . ForceCheckoutBranch ) ,
2022-02-26 19:06:22 +11:00
Handler : self . forceCheckout ,
2023-05-25 21:11:51 +10:00
Description : self . c . Tr . ForceCheckout ,
2022-02-06 15:54:26 +11:00
} ,
{
Key : opts . GetKey ( opts . Config . Universal . Remove ) ,
2022-02-26 19:06:22 +11:00
Handler : self . checkSelectedAndReal ( self . delete ) ,
2023-05-25 21:11:51 +10:00
Description : self . c . Tr . DeleteBranch ,
2022-02-06 15:54:26 +11:00
} ,
{
Key : opts . GetKey ( opts . Config . Branches . RebaseBranch ) ,
2022-02-26 19:06:22 +11:00
Handler : opts . Guards . OutsideFilterMode ( self . rebase ) ,
2023-05-25 21:11:51 +10:00
Description : self . c . Tr . RebaseBranch ,
2022-02-06 15:54:26 +11:00
} ,
{
Key : opts . GetKey ( opts . Config . Branches . MergeIntoCurrentBranch ) ,
2022-02-26 19:06:22 +11:00
Handler : opts . Guards . OutsideFilterMode ( self . merge ) ,
2023-05-25 21:11:51 +10:00
Description : self . c . Tr . MergeIntoCurrentBranch ,
2022-02-06 15:54:26 +11:00
} ,
{
Key : opts . GetKey ( opts . Config . Branches . FastForward ) ,
2022-02-26 19:06:22 +11:00
Handler : self . checkSelectedAndReal ( self . fastForward ) ,
2022-02-06 15:54:26 +11:00
Description : self . c . Tr . FastForward ,
} ,
2023-02-08 22:40:18 +09:00
{
Key : opts . GetKey ( opts . Config . Branches . CreateTag ) ,
Handler : self . checkSelected ( self . createTag ) ,
2023-05-25 21:11:51 +10:00
Description : self . c . Tr . CreateTag ,
2023-02-08 22:40:18 +09:00
} ,
2022-02-06 15:54:26 +11:00
{
Key : opts . GetKey ( opts . Config . Commits . ViewResetOptions ) ,
2022-02-26 19:06:22 +11:00
Handler : self . checkSelected ( self . createResetMenu ) ,
2023-05-25 21:11:51 +10:00
Description : self . c . Tr . ViewResetOptions ,
2022-02-06 15:54:26 +11:00
OpensMenu : true ,
} ,
{
Key : opts . GetKey ( opts . Config . Branches . RenameBranch ) ,
2022-02-26 19:06:22 +11:00
Handler : self . checkSelectedAndReal ( self . rename ) ,
2023-05-25 21:11:51 +10:00
Description : self . c . Tr . RenameBranch ,
2022-02-06 15:54:26 +11:00
} ,
2022-04-08 17:06:07 +02:00
{
Key : opts . GetKey ( opts . Config . Branches . SetUpstream ) ,
Handler : self . checkSelected ( self . setUpstream ) ,
2023-05-25 21:11:51 +10:00
Description : self . c . Tr . SetUnsetUpstream ,
2022-04-08 17:06:07 +02:00
OpensMenu : true ,
} ,
2022-02-06 15:54:26 +11:00
}
}
2022-12-30 23:24:24 +11:00
func ( self * BranchesController ) GetOnRenderToMain ( ) func ( ) error {
return func ( ) error {
2023-03-23 18:47:29 +11:00
return self . c . Helpers ( ) . Diff . WithDiffModeCheck ( func ( ) error {
2022-12-30 23:24:24 +11: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 {
{
2023-05-25 21:11:51 +10:00
LabelColumns : [ ] string { self . c . Tr . UnsetUpstream } ,
2022-04-08 17:06:07 +02:00
OnPress : func ( ) error {
2023-03-23 13:04:57 +11: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' ,
} ,
{
2023-05-25 21:11:51 +10:00
LabelColumns : [ ] string { self . c . Tr . SetUpstream } ,
2022-04-08 17:06:07 +02:00
OnPress : func ( ) error {
2023-03-23 18:47:29 +11: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 13:04:57 +11: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 15:54:26 +11:00
func ( self * BranchesController ) Context ( ) types . Context {
return self . context ( )
}
func ( self * BranchesController ) context ( ) * context . BranchesContext {
2023-03-23 13:04:57 +11:00
return self . c . Contexts ( ) . Branches
2022-02-06 15:54:26 +11:00
}
2022-02-26 19:06:22 +11:00
func ( self * BranchesController ) press ( selectedBranch * models . Branch ) error {
2023-03-23 18:47:29 +11:00
if selectedBranch == self . c . Helpers ( ) . Refs . GetCheckedOutRef ( ) {
2022-02-06 15:54:26 +11:00
return self . c . ErrorMsg ( self . c . Tr . AlreadyCheckedOutBranch )
}
2023-07-17 13:40:26 +10:00
worktreeForRef , ok := self . worktreeForBranch ( selectedBranch )
if ok && ! self . c . Git ( ) . Worktree . IsCurrentWorktree ( worktreeForRef . Path ) {
return self . promptToCheckoutWorktree ( worktreeForRef )
2023-07-16 14:14:09 +10:00
}
2022-02-06 15:54:26 +11:00
self . c . LogAction ( self . c . Tr . Actions . CheckoutBranch )
2023-03-23 18:47:29 +11:00
return self . c . Helpers ( ) . Refs . CheckoutRef ( selectedBranch . Name , types . CheckoutRefOptions { } )
2022-02-06 15:54:26 +11:00
}
2023-07-16 17:52:07 +10:00
func ( self * BranchesController ) worktreeForBranch ( branch * models . Branch ) ( * models . Worktree , bool ) {
2023-07-17 13:40:26 +10:00
return git_commands . WorktreeForBranch ( branch , self . c . Model ( ) . Worktrees )
2023-07-16 14:14:09 +10:00
}
func ( self * BranchesController ) promptToCheckoutWorktree ( worktree * models . Worktree ) error {
return self . c . Confirm ( types . ConfirmOpts {
Title : "Switch to worktree" ,
Prompt : fmt . Sprintf ( "This branch is checked out by worktree %s. Do you want to switch to that worktree?" , worktree . Name ( ) ) ,
HandleConfirm : func ( ) error {
2023-07-16 19:39:53 +10:00
return self . c . Helpers ( ) . Worktree . Switch ( worktree . Path , context . LOCAL_BRANCHES_CONTEXT_KEY )
2023-07-16 14:14:09 +10:00
} ,
} )
}
2022-02-26 19:06:22 +11:00
func ( self * BranchesController ) handleCreatePullRequest ( selectedBranch * models . Branch ) error {
return self . createPullRequest ( selectedBranch . Name , "" )
2022-02-06 15:54:26 +11:00
}
func ( self * BranchesController ) handleCreatePullRequestMenu ( selectedBranch * models . Branch ) error {
2023-03-23 18:47:29 +11:00
checkedOutBranch := self . c . Helpers ( ) . Refs . GetCheckedOutRef ( )
2022-02-06 15:54:26 +11:00
return self . createPullRequestMenu ( selectedBranch , checkedOutBranch )
}
2022-02-26 19:06:22 +11:00
func ( self * BranchesController ) copyPullRequestURL ( ) error {
2022-02-06 15:54:26 +11:00
branch := self . context ( ) . GetSelected ( )
2023-03-23 13:04:57 +11:00
branchExistsOnRemote := self . c . Git ( ) . Remote . CheckRemoteBranchExists ( branch . Name )
2022-02-06 15:54:26 +11:00
if ! branchExistsOnRemote {
return self . c . Error ( errors . New ( self . c . Tr . NoBranchOnRemote ) )
}
2023-03-23 18:47:29 +11:00
url , err := self . c . Helpers ( ) . Host . GetPullRequestURL ( branch . Name , "" )
2022-02-06 15:54:26 +11:00
if err != nil {
return self . c . Error ( err )
}
self . c . LogAction ( self . c . Tr . Actions . CopyPullRequestURL )
2023-03-23 13:04:57 +11:00
if err := self . c . OS ( ) . CopyToClipboard ( url ) ; err != nil {
2022-02-06 15:54:26 +11:00
return self . c . Error ( err )
}
self . c . Toast ( self . c . Tr . PullRequestURLCopiedToClipboard )
return nil
}
2022-02-26 19:06:22 +11:00
func ( self * BranchesController ) forceCheckout ( ) error {
2022-02-06 15:54:26 +11: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 15:54:26 +11:00
Title : title ,
Prompt : message ,
HandleConfirm : func ( ) error {
self . c . LogAction ( self . c . Tr . Actions . ForceCheckoutBranch )
2023-03-23 13:04:57 +11:00
if err := self . c . Git ( ) . Branch . Checkout ( branch . Name , git_commands . CheckoutOptions { Force : true } ) ; err != nil {
2022-02-06 15:54:26 +11:00
_ = self . c . Error ( err )
}
return self . c . Refresh ( types . RefreshOptions { Mode : types . ASYNC } )
} ,
} )
}
2022-02-26 19:06:22 +11:00
func ( self * BranchesController ) checkoutByName ( ) error {
2022-02-06 15:54:26 +11:00
return self . c . Prompt ( types . PromptOpts {
Title : self . c . Tr . BranchName + ":" ,
2023-03-23 18:47:29 +11:00
FindSuggestionsFunc : self . c . Helpers ( ) . Suggestions . GetRefsSuggestionsFunc ( ) ,
2022-02-06 15:54:26 +11:00
HandleConfirm : func ( response string ) error {
self . c . LogAction ( "Checkout branch" )
2023-03-23 18:47:29 +11:00
return self . c . Helpers ( ) . Refs . CheckoutRef ( response , types . CheckoutRefOptions {
2022-02-06 15:54:26 +11:00
OnRefNotFound : func ( ref string ) error {
2022-03-30 08:48:29 +02:00
return self . c . Confirm ( types . ConfirmOpts {
2022-02-06 15:54:26 +11: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 09:38:49 +11:00
} ,
} ,
2022-02-06 15:54:26 +11:00
)
}
func ( self * BranchesController ) createNewBranchWithName ( newBranchName string ) error {
branch := self . context ( ) . GetSelected ( )
if branch == nil {
return nil
}
2023-03-23 13:04:57 +11:00
if err := self . c . Git ( ) . Branch . New ( newBranchName , branch . FullRefName ( ) ) ; err != nil {
2022-02-06 15:54:26 +11:00
return self . c . Error ( err )
}
self . context ( ) . SetSelectedLineIdx ( 0 )
return self . c . Refresh ( types . RefreshOptions { Mode : types . ASYNC } )
}
2022-02-26 19:06:22 +11:00
func ( self * BranchesController ) delete ( branch * models . Branch ) error {
2023-03-23 18:47:29 +11:00
checkedOutBranch := self . c . Helpers ( ) . Refs . GetCheckedOutRef ( )
2022-02-06 15:54:26 +11:00
if checkedOutBranch . Name == branch . Name {
return self . c . ErrorMsg ( self . c . Tr . CantDeleteCheckOutBranch )
}
2023-07-16 17:52:07 +10:00
2023-07-17 13:40:26 +10:00
if self . checkedOutByOtherWorktree ( branch ) {
2023-07-16 17:52:07 +10:00
return self . promptWorktreeBranchDelete ( branch )
}
2022-02-26 19:06:22 +11:00
return self . deleteWithForce ( branch , false )
2022-02-06 15:54:26 +11:00
}
2023-07-17 13:40:26 +10:00
func ( self * BranchesController ) checkedOutByOtherWorktree ( branch * models . Branch ) bool {
return git_commands . CheckedOutByOtherWorktree ( branch , self . c . Model ( ) . Worktrees )
}
2023-07-16 17:52:07 +10:00
func ( self * BranchesController ) promptWorktreeBranchDelete ( selectedBranch * models . Branch ) error {
worktree , ok := self . worktreeForBranch ( selectedBranch )
if ! ok {
self . c . Log . Error ( "CheckedOutByOtherWorktree out of sync with list of worktrees" )
return nil
}
return self . c . Menu ( types . CreateMenuOptions {
Title : fmt . Sprintf ( "Branch %s is checked out by worktree %s" , selectedBranch . Name , worktree . Name ( ) ) ,
Items : [ ] * types . MenuItem {
{
2023-07-16 18:12:26 +10:00
Label : "Switch to worktree" ,
2023-07-16 17:52:07 +10:00
OnPress : func ( ) error {
2023-07-16 19:39:53 +10:00
return self . c . Helpers ( ) . Worktree . Switch ( worktree . Path , context . LOCAL_BRANCHES_CONTEXT_KEY )
2023-07-16 17:52:07 +10:00
} ,
} ,
{
Label : "Detach worktree" ,
Tooltip : "This will run `git checkout --detach` on the worktree so that it stops hogging the branch, but the worktree's working tree will be left alone" ,
OnPress : func ( ) error {
return self . c . Helpers ( ) . Worktree . Detach ( worktree )
} ,
} ,
{
Label : "Remove worktree" ,
OnPress : func ( ) error {
return self . c . Helpers ( ) . Worktree . Remove ( worktree , false )
} ,
} ,
} ,
} )
}
2022-02-26 19:06:22 +11:00
func ( self * BranchesController ) deleteWithForce ( selectedBranch * models . Branch , force bool ) error {
2022-02-06 15:54:26 +11: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 15:54:26 +11:00
Title : title ,
Prompt : message ,
HandleConfirm : func ( ) error {
self . c . LogAction ( self . c . Tr . Actions . DeleteBranch )
2023-03-23 13:04:57 +11:00
if err := self . c . Git ( ) . Branch . Delete ( selectedBranch . Name , force ) ; err != nil {
2022-02-06 15:54:26 +11:00
errMessage := err . Error ( )
if ! force && strings . Contains ( errMessage , "git branch -D " ) {
2022-02-26 19:06:22 +11:00
return self . deleteWithForce ( selectedBranch , true )
2022-02-06 15:54:26 +11:00
}
return self . c . ErrorMsg ( errMessage )
}
return self . c . Refresh ( types . RefreshOptions { Mode : types . ASYNC , Scope : [ ] types . RefreshableView { types . BRANCHES } } )
} ,
} )
}
2022-02-26 19:06:22 +11:00
func ( self * BranchesController ) merge ( ) error {
2022-02-06 15:54:26 +11:00
selectedBranchName := self . context ( ) . GetSelected ( ) . Name
2023-03-23 18:47:29 +11:00
return self . c . Helpers ( ) . MergeAndRebase . MergeRefIntoCheckedOutBranch ( selectedBranchName )
2022-02-06 15:54:26 +11:00
}
2022-02-26 19:06:22 +11:00
func ( self * BranchesController ) rebase ( ) error {
2022-02-06 15:54:26 +11:00
selectedBranchName := self . context ( ) . GetSelected ( ) . Name
2023-03-23 18:47:29 +11:00
return self . c . Helpers ( ) . MergeAndRebase . RebaseOntoRef ( selectedBranchName )
2022-02-06 15:54:26 +11:00
}
2022-02-26 19:06:22 +11:00
func ( self * BranchesController ) fastForward ( branch * models . Branch ) error {
2022-02-06 15:54:26 +11: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 ,
} ,
)
2023-07-09 21:09:52 +10:00
return self . c . WithLoaderPanel ( message , func ( task gocui . Task ) error {
2023-03-23 18:47:29 +11:00
if branch == self . c . Helpers ( ) . Refs . GetCheckedOutRef ( ) {
2022-02-06 15:54:26 +11:00
self . c . LogAction ( action )
2023-03-23 13:04:57 +11:00
err := self . c . Git ( ) . Sync . Pull (
2023-07-09 11:32:27 +10:00
task ,
2022-02-06 15:54:26 +11:00
git_commands . PullOptions {
RemoteName : branch . UpstreamRemote ,
2022-06-01 20:30:13 +02:00
BranchName : branch . UpstreamBranch ,
2022-02-06 15:54:26 +11: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-07-09 11:32:27 +10:00
err := self . c . Git ( ) . Sync . FastForward ( task , branch . Name , branch . UpstreamRemote , branch . UpstreamBranch )
2022-02-06 15:54:26 +11: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 22:40:18 +09:00
func ( self * BranchesController ) createTag ( branch * models . Branch ) error {
2023-07-22 14:05:42 +10:00
return self . c . Helpers ( ) . Tags . OpenCreateTagPrompt ( branch . FullRefName ( ) , func ( ) { } )
2023-02-08 22:40:18 +09:00
}
2022-02-26 19:06:22 +11:00
func ( self * BranchesController ) createResetMenu ( selectedBranch * models . Branch ) error {
2023-03-23 18:47:29 +11:00
return self . c . Helpers ( ) . Refs . CreateGitResetMenu ( selectedBranch . Name )
2022-02-06 15:54:26 +11:00
}
2022-02-26 19:06:22 +11:00
func ( self * BranchesController ) rename ( branch * models . Branch ) error {
2022-02-06 15:54:26 +11: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 13:04:57 +11:00
if err := self . c . Git ( ) . Branch . Rename ( branch . Name , newBranchName ) ; err != nil {
2022-02-06 15:54:26 +11: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 13:04:57 +11:00
for i , newBranch := range self . c . Model ( ) . Branches {
2022-02-06 15:54:26 +11: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 {
2023-05-25 21:11:51 +10:00
Title : self . c . Tr . RenameBranch ,
2022-02-06 15:54:26 +11:00
Prompt : self . c . Tr . RenameBranchWarning ,
HandleConfirm : promptForNewName ,
} )
}
2022-02-26 19:06:22 +11:00
func ( self * BranchesController ) newBranch ( selectedBranch * models . Branch ) error {
2023-03-23 18:47:29 +11:00
return self . c . Helpers ( ) . Refs . NewBranch ( selectedBranch . FullRefName ( ) , selectedBranch . RefName ( ) , "" )
2022-02-06 15:54:26 +11:00
}
func ( self * BranchesController ) createPullRequestMenu ( selectedBranch * models . Branch , checkedOutBranch * models . Branch ) error {
menuItems := make ( [ ] * types . MenuItem , 0 , 4 )
2022-05-08 14:23:32 +10:00
fromToLabelColumns := func ( from string , to string ) [ ] string {
2022-02-06 15:54:26 +11:00
return [ ] string { fmt . Sprintf ( "%s → %s" , from , to ) }
}
menuItemsForBranch := func ( branch * models . Branch ) [ ] * types . MenuItem {
return [ ] * types . MenuItem {
{
2023-05-25 21:11:51 +10:00
LabelColumns : fromToLabelColumns ( branch . Name , self . c . Tr . DefaultBranch ) ,
2022-02-06 15:54:26 +11:00
OnPress : func ( ) error {
return self . createPullRequest ( branch . Name , "" )
} ,
} ,
{
2023-05-25 21:11:51 +10:00
LabelColumns : fromToLabelColumns ( branch . Name , self . c . Tr . SelectBranch ) ,
2022-02-06 15:54:26 +11:00
OnPress : func ( ) error {
return self . c . Prompt ( types . PromptOpts {
Title : branch . Name + " →" ,
2023-03-23 18:47:29 +11:00
FindSuggestionsFunc : self . c . Helpers ( ) . Suggestions . GetBranchNameSuggestionsFunc ( ) ,
2022-02-06 15:54:26 +11:00
HandleConfirm : func ( targetBranchName string ) error {
return self . createPullRequest ( branch . Name , targetBranchName )
2022-03-19 09:38:49 +11:00
} ,
} )
2022-02-06 15:54:26 +11:00
} ,
} ,
}
}
if selectedBranch != checkedOutBranch {
menuItems = append ( menuItems ,
& types . MenuItem {
2022-05-08 14:23:32 +10:00
LabelColumns : fromToLabelColumns ( checkedOutBranch . Name , selectedBranch . Name ) ,
2022-02-06 15:54:26 +11: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 18:47:29 +11:00
url , err := self . c . Helpers ( ) . Host . GetPullRequestURL ( from , to )
2022-02-06 15:54:26 +11:00
if err != nil {
return self . c . Error ( err )
}
self . c . LogAction ( self . c . Tr . Actions . OpenPullRequest )
2023-03-23 13:04:57 +11:00
if err := self . c . OS ( ) . OpenLink ( url ) ; err != nil {
2022-02-06 15:54:26 +11: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 )
}
}