1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-07-30 03:23:08 +03:00

Add option to (un)set upstream for a local branch

This commit is contained in:
Luka Markušić
2022-04-08 17:06:07 +02:00
parent d0e099d2fc
commit f83308c8df
16 changed files with 149 additions and 64 deletions

View File

@ -97,9 +97,50 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty
Handler: self.checkSelectedAndReal(self.rename),
Description: self.c.Tr.LcRenameBranch,
},
{
Key: opts.GetKey(opts.Config.Branches.SetUpstream),
Handler: self.checkSelected(self.setUpstream),
Description: self.c.Tr.LcSetUnsetUpstream,
OpensMenu: true,
},
}
}
func (self *BranchesController) setUpstream(selectedBranch *models.Branch) error {
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.Actions.SetUnsetUpstream,
Items: []*types.MenuItem{
{
DisplayStrings: []string{self.c.Tr.LcUnsetUpstream},
OnPress: func() error {
if err := self.git.Branch.UnsetUpstream(selectedBranch.Name); err != nil {
return self.c.Error(err)
}
return nil
},
Key: 'u',
},
{
DisplayStrings: []string{self.c.Tr.LcSetUpstream},
OnPress: func() error {
return self.helpers.Upstream.PromptForUpstream(selectedBranch, func(upstream string) error {
upstreamRemote, upstreamBranch, err := self.helpers.Upstream.ParseUpstream(upstream)
if err != nil {
return self.c.Error(err)
}
if err := self.git.Branch.SetUpstream(upstreamRemote, upstreamBranch, selectedBranch.Name); err != nil {
return self.c.Error(err)
}
return nil
})
},
Key: 's',
},
},
})
}
func (self *BranchesController) Context() types.Context {
return self.context()
}

View File

@ -12,6 +12,7 @@ type Helpers struct {
Host *HostHelper
PatchBuilding *PatchBuildingHelper
GPG *GpgHelper
Upstream *UpstreamHelper
}
func NewStubHelpers() *Helpers {
@ -27,5 +28,6 @@ func NewStubHelpers() *Helpers {
Host: &HostHelper{},
PatchBuilding: &PatchBuildingHelper{},
GPG: &GpgHelper{},
Upstream: &UpstreamHelper{},
}
}

View File

@ -0,0 +1,78 @@
package helpers
import (
"errors"
"strings"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type UpstreamHelper struct {
c *types.HelperCommon
model *types.Model
getRemoteBranchesSuggestionsFunc func(string) func(string) []*types.Suggestion
}
type IUpstreamHelper interface {
ParseUpstream(string) (string, string, error)
PromptForUpstream(*models.Branch, func(string) error) error
GetSuggestedRemote() string
}
var _ IUpstreamHelper = &UpstreamHelper{}
func NewUpstreamHelper(
c *types.HelperCommon,
model *types.Model,
getRemoteBranchesSuggestionsFunc func(string) func(string) []*types.Suggestion,
) *UpstreamHelper {
return &UpstreamHelper{
c: c,
model: model,
getRemoteBranchesSuggestionsFunc: getRemoteBranchesSuggestionsFunc,
}
}
func (self *UpstreamHelper) ParseUpstream(upstream string) (string, string, error) {
var upstreamBranch, upstreamRemote string
split := strings.Split(upstream, " ")
if len(split) != 2 {
return "", "", errors.New(self.c.Tr.InvalidUpstream)
}
upstreamRemote = split[0]
upstreamBranch = split[1]
return upstreamRemote, upstreamBranch, nil
}
func (self *UpstreamHelper) PromptForUpstream(currentBranch *models.Branch, onConfirm func(string) error) error {
suggestedRemote := self.GetSuggestedRemote()
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.EnterUpstream,
InitialContent: suggestedRemote + " " + currentBranch.Name,
FindSuggestionsFunc: self.getRemoteBranchesSuggestionsFunc(" "),
HandleConfirm: onConfirm,
})
}
func (self *UpstreamHelper) GetSuggestedRemote() string {
return getSuggestedRemote(self.model.Remotes)
}
func getSuggestedRemote(remotes []*models.Remote) string {
if len(remotes) == 0 {
return "origin"
}
for _, remote := range remotes {
if remote.Name == "origin" {
return remote.Name
}
}
return remotes[0].Name
}

View File

@ -0,0 +1,31 @@
package helpers
import (
"testing"
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/stretchr/testify/assert"
)
func TestGetSuggestedRemote(t *testing.T) {
cases := []struct {
remotes []*models.Remote
expected string
}{
{mkRemoteList(), "origin"},
{mkRemoteList("upstream", "origin", "foo"), "origin"},
{mkRemoteList("upstream", "foo", "bar"), "upstream"},
}
for _, c := range cases {
result := getSuggestedRemote(c.remotes)
assert.EqualValues(t, c.expected, result)
}
}
func mkRemoteList(names ...string) []*models.Remote {
return slices.Map(names, func(name string) *models.Remote {
return &models.Remote{Name: name}
})
}

View File

@ -57,7 +57,7 @@ func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts)
{
Key: opts.GetKey(opts.Config.Branches.SetUpstream),
Handler: self.checkSelected(self.setAsUpstream),
Description: self.c.Tr.LcSetUpstream,
Description: self.c.Tr.LcSetAsUpstream,
},
{
Key: opts.GetKey(opts.Config.Universal.Return),

View File

@ -1,7 +1,6 @@
package controllers
import (
"errors"
"fmt"
"strings"
@ -13,21 +12,16 @@ import (
type SyncController struct {
baseController
*controllerCommon
getSuggestedRemote func() string
}
var _ types.IController = &SyncController{}
func NewSyncController(
common *controllerCommon,
getSuggestedRemote func() string,
) *SyncController {
return &SyncController{
baseController: baseController{},
controllerCommon: common,
getSuggestedRemote: getSuggestedRemote,
}
}
@ -85,8 +79,8 @@ func (self *SyncController) push(currentBranch *models.Branch) error {
if self.git.Config.GetPushToCurrent() {
return self.pushAux(pushOpts{setUpstream: true})
} else {
return self.promptForUpstream(currentBranch, func(upstream string) error {
upstreamRemote, upstreamBranch, err := self.parseUpstream(upstream)
return self.helpers.Upstream.PromptForUpstream(currentBranch, func(upstream string) error {
upstreamRemote, upstreamBranch, err := self.helpers.Upstream.ParseUpstream(upstream)
if err != nil {
return self.c.Error(err)
}
@ -106,7 +100,7 @@ func (self *SyncController) pull(currentBranch *models.Branch) error {
// if we have no upstream branch we need to set that first
if !currentBranch.IsTrackingRemote() {
return self.promptForUpstream(currentBranch, func(upstream string) error {
return self.helpers.Upstream.PromptForUpstream(currentBranch, func(upstream string) error {
if err := self.setCurrentBranchUpstream(upstream); err != nil {
return self.c.Error(err)
}
@ -119,7 +113,7 @@ func (self *SyncController) pull(currentBranch *models.Branch) error {
}
func (self *SyncController) setCurrentBranchUpstream(upstream string) error {
upstreamRemote, upstreamBranch, err := self.parseUpstream(upstream)
upstreamRemote, upstreamBranch, err := self.helpers.Upstream.ParseUpstream(upstream)
if err != nil {
return err
}
@ -136,30 +130,6 @@ func (self *SyncController) setCurrentBranchUpstream(upstream string) error {
return nil
}
func (self *SyncController) parseUpstream(upstream string) (string, string, error) {
var upstreamBranch, upstreamRemote string
split := strings.Split(upstream, " ")
if len(split) != 2 {
return "", "", errors.New(self.c.Tr.InvalidUpstream)
}
upstreamRemote = split[0]
upstreamBranch = split[1]
return upstreamRemote, upstreamBranch, nil
}
func (self *SyncController) promptForUpstream(currentBranch *models.Branch, onConfirm func(string) error) error {
suggestedRemote := self.getSuggestedRemote()
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.EnterUpstream,
InitialContent: suggestedRemote + " " + currentBranch.Name,
FindSuggestionsFunc: self.helpers.Suggestions.GetRemoteBranchesSuggestionsFunc(" "),
HandleConfirm: onConfirm,
})
}
type PullFilesOptions struct {
UpstreamRemote string
UpstreamBranch string