1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-02-03 13:21:56 +02: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

@ -59,6 +59,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>f</kbd>: fast-forward this branch from its upstream <kbd>f</kbd>: fast-forward this branch from its upstream
<kbd>g</kbd>: view reset options <kbd>g</kbd>: view reset options
<kbd>R</kbd>: rename branch <kbd>R</kbd>: rename branch
<kbd>u</kbd>: set/unset upstream
<kbd>enter</kbd>: view commits <kbd>enter</kbd>: view commits
</pre> </pre>

View File

@ -86,6 +86,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>f</kbd>: fast-forward deze branch vanaf zijn upstream <kbd>f</kbd>: fast-forward deze branch vanaf zijn upstream
<kbd>g</kbd>: bekijk reset opties <kbd>g</kbd>: bekijk reset opties
<kbd>R</kbd>: hernoem branch <kbd>R</kbd>: hernoem branch
<kbd>u</kbd>: set/unset upstream
<kbd>enter</kbd>: bekijk commits <kbd>enter</kbd>: bekijk commits
</pre> </pre>

View File

@ -59,6 +59,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>f</kbd>: fast-forward this branch from its upstream <kbd>f</kbd>: fast-forward this branch from its upstream
<kbd>g</kbd>: wyświetl opcje resetu <kbd>g</kbd>: wyświetl opcje resetu
<kbd>R</kbd>: rename branch <kbd>R</kbd>: rename branch
<kbd>u</kbd>: set/unset upstream
<kbd>enter</kbd>: view commits <kbd>enter</kbd>: view commits
</pre> </pre>

View File

@ -74,6 +74,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
<kbd>f</kbd>: 从上游快进此分支 <kbd>f</kbd>: 从上游快进此分支
<kbd>g</kbd>: 查看重置选项 <kbd>g</kbd>: 查看重置选项
<kbd>R</kbd>: 重命名分支 <kbd>R</kbd>: 重命名分支
<kbd>u</kbd>: set/unset upstream
<kbd>enter</kbd>: 查看提交 <kbd>enter</kbd>: 查看提交
</pre> </pre>

View File

@ -109,6 +109,10 @@ func (self *BranchCommands) SetUpstream(remoteName string, remoteBranchName stri
return self.cmd.New(fmt.Sprintf("git branch --set-upstream-to=%s/%s %s", self.cmd.Quote(remoteName), self.cmd.Quote(remoteBranchName), self.cmd.Quote(branchName))).Run() return self.cmd.New(fmt.Sprintf("git branch --set-upstream-to=%s/%s %s", self.cmd.Quote(remoteName), self.cmd.Quote(remoteBranchName), self.cmd.Quote(branchName))).Run()
} }
func (self *BranchCommands) UnsetUpstream(branchName string) error {
return self.cmd.New(fmt.Sprintf("git branch --unset-upstream %s", self.cmd.Quote(branchName))).Run()
}
func (self *BranchCommands) GetCurrentBranchUpstreamDifferenceCount() (string, string) { func (self *BranchCommands) GetCurrentBranchUpstreamDifferenceCount() (string, string) {
return self.GetCommitDifferences("HEAD", "HEAD@{u}") return self.GetCommitDifferences("HEAD", "HEAD@{u}")
} }

View File

@ -23,12 +23,13 @@ func (gui *Gui) resetControllers() {
) )
rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon, gui.State.Contexts, gui.git, gui.takeOverMergeConflictScrolling, refsHelper) rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon, gui.State.Contexts, gui.git, gui.takeOverMergeConflictScrolling, refsHelper)
suggestionsHelper := helpers.NewSuggestionsHelper(helperCommon, model, gui.refreshSuggestions)
gui.helpers = &helpers.Helpers{ gui.helpers = &helpers.Helpers{
Refs: refsHelper, Refs: refsHelper,
Host: helpers.NewHostHelper(helperCommon, gui.git), Host: helpers.NewHostHelper(helperCommon, gui.git),
PatchBuilding: helpers.NewPatchBuildingHelper(helperCommon, gui.git), PatchBuilding: helpers.NewPatchBuildingHelper(helperCommon, gui.git),
Bisect: helpers.NewBisectHelper(helperCommon, gui.git), Bisect: helpers.NewBisectHelper(helperCommon, gui.git),
Suggestions: helpers.NewSuggestionsHelper(helperCommon, model, gui.refreshSuggestions), Suggestions: suggestionsHelper,
Files: helpers.NewFilesHelper(helperCommon, gui.git, osCommand), Files: helpers.NewFilesHelper(helperCommon, gui.git, osCommand),
WorkingTree: helpers.NewWorkingTreeHelper(helperCommon, gui.git, model), WorkingTree: helpers.NewWorkingTreeHelper(helperCommon, gui.git, model),
Tags: helpers.NewTagsHelper(helperCommon, gui.git), Tags: helpers.NewTagsHelper(helperCommon, gui.git),
@ -41,6 +42,7 @@ func (gui *Gui) resetControllers() {
func() *cherrypicking.CherryPicking { return gui.State.Modes.CherryPicking }, func() *cherrypicking.CherryPicking { return gui.State.Modes.CherryPicking },
rebaseHelper, rebaseHelper,
), ),
Upstream: helpers.NewUpstreamHelper(helperCommon, model, suggestionsHelper.GetRemoteBranchesSuggestionsFunc),
} }
gui.CustomCommandsClient = custom_commands.NewClient( gui.CustomCommandsClient = custom_commands.NewClient(
@ -64,7 +66,6 @@ func (gui *Gui) resetControllers() {
syncController := controllers.NewSyncController( syncController := controllers.NewSyncController(
common, common,
gui.getSuggestedRemote,
) )
submodulesController := controllers.NewSubmodulesController( submodulesController := controllers.NewSubmodulesController(

View File

@ -97,9 +97,50 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty
Handler: self.checkSelectedAndReal(self.rename), Handler: self.checkSelectedAndReal(self.rename),
Description: self.c.Tr.LcRenameBranch, 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 { func (self *BranchesController) Context() types.Context {
return self.context() return self.context()
} }

View File

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

@ -1,4 +1,4 @@
package gui package helpers
import ( import (
"testing" "testing"

View File

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

View File

@ -1,7 +1,6 @@
package controllers package controllers
import ( import (
"errors"
"fmt" "fmt"
"strings" "strings"
@ -13,21 +12,16 @@ import (
type SyncController struct { type SyncController struct {
baseController baseController
*controllerCommon *controllerCommon
getSuggestedRemote func() string
} }
var _ types.IController = &SyncController{} var _ types.IController = &SyncController{}
func NewSyncController( func NewSyncController(
common *controllerCommon, common *controllerCommon,
getSuggestedRemote func() string,
) *SyncController { ) *SyncController {
return &SyncController{ return &SyncController{
baseController: baseController{}, baseController: baseController{},
controllerCommon: common, controllerCommon: common,
getSuggestedRemote: getSuggestedRemote,
} }
} }
@ -85,8 +79,8 @@ func (self *SyncController) push(currentBranch *models.Branch) error {
if self.git.Config.GetPushToCurrent() { if self.git.Config.GetPushToCurrent() {
return self.pushAux(pushOpts{setUpstream: true}) return self.pushAux(pushOpts{setUpstream: true})
} else { } else {
return self.promptForUpstream(currentBranch, func(upstream string) error { return self.helpers.Upstream.PromptForUpstream(currentBranch, func(upstream string) error {
upstreamRemote, upstreamBranch, err := self.parseUpstream(upstream) upstreamRemote, upstreamBranch, err := self.helpers.Upstream.ParseUpstream(upstream)
if err != nil { if err != nil {
return self.c.Error(err) 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 we have no upstream branch we need to set that first
if !currentBranch.IsTrackingRemote() { 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 { if err := self.setCurrentBranchUpstream(upstream); err != nil {
return self.c.Error(err) return self.c.Error(err)
} }
@ -119,7 +113,7 @@ func (self *SyncController) pull(currentBranch *models.Branch) error {
} }
func (self *SyncController) setCurrentBranchUpstream(upstream string) 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 { if err != nil {
return err return err
} }
@ -136,30 +130,6 @@ func (self *SyncController) setCurrentBranchUpstream(upstream string) error {
return nil 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 { type PullFilesOptions struct {
UpstreamRemote string UpstreamRemote string
UpstreamBranch string UpstreamBranch string

View File

@ -1,25 +0,0 @@
package gui
import "github.com/jesseduffield/lazygit/pkg/commands/models"
// this file is to put things where it's not obvious where they belong while this refactor takes place
func (gui *Gui) getSuggestedRemote() string {
remotes := gui.State.Model.Remotes
return getSuggestedRemote(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

@ -312,6 +312,7 @@ func chineseTranslationSet() TranslationSet {
DeleteRemoteBranch: "删除远程分支", DeleteRemoteBranch: "删除远程分支",
DeleteRemoteBranchMessage: "您确定要删除远程分支吗?", DeleteRemoteBranchMessage: "您确定要删除远程分支吗?",
LcSetUpstream: "设置为检出分支的上游", LcSetUpstream: "设置为检出分支的上游",
LcSetAsUpstream: "设置为检出分支的上游",
SetUpstreamTitle: "设置上游分支", SetUpstreamTitle: "设置上游分支",
SetUpstreamMessage: "您确定要将 {{.checkedOut}} 的上游分支设置为 {{.selected}} 吗?", SetUpstreamMessage: "您确定要将 {{.checkedOut}} 的上游分支设置为 {{.selected}} 吗?",
LcEditRemote: "编辑远程仓库", LcEditRemote: "编辑远程仓库",

View File

@ -271,6 +271,7 @@ func dutchTranslationSet() TranslationSet {
DeleteRemoteBranch: "Verwijder Remote Branch", DeleteRemoteBranch: "Verwijder Remote Branch",
DeleteRemoteBranchMessage: "Weet je zeker dat je deze remote branch wilt verwijderen", DeleteRemoteBranchMessage: "Weet je zeker dat je deze remote branch wilt verwijderen",
LcSetUpstream: "stel in als upstream van uitgecheckte branch", LcSetUpstream: "stel in als upstream van uitgecheckte branch",
LcSetAsUpstream: "stel in als upstream van uitgecheckte branch",
SetUpstreamTitle: "Stel in als upstream branch", SetUpstreamTitle: "Stel in als upstream branch",
SetUpstreamMessage: "Weet je zeker dat je de upstream branch van '{{.checkedOut}}' naar '{{.selected}}' wilt zetten", SetUpstreamMessage: "Weet je zeker dat je de upstream branch van '{{.checkedOut}}' naar '{{.selected}}' wilt zetten",
LcEditRemote: "wijzig remote", LcEditRemote: "wijzig remote",

View File

@ -306,7 +306,9 @@ type TranslationSet struct {
LcRemoveRemotePrompt string LcRemoveRemotePrompt string
DeleteRemoteBranch string DeleteRemoteBranch string
DeleteRemoteBranchMessage string DeleteRemoteBranchMessage string
LcSetAsUpstream string
LcSetUpstream string LcSetUpstream string
LcUnsetUpstream string
SetUpstreamTitle string SetUpstreamTitle string
SetUpstreamMessage string SetUpstreamMessage string
LcEditRemote string LcEditRemote string
@ -339,6 +341,7 @@ type TranslationSet struct {
Panel string Panel string
Keybindings string Keybindings string
LcRenameBranch string LcRenameBranch string
LcSetUnsetUpstream string
NewGitFlowBranchPrompt string NewGitFlowBranchPrompt string
RenameBranchWarning string RenameBranchWarning string
LcOpenMenu string LcOpenMenu string
@ -506,6 +509,7 @@ type Actions struct {
Merge string Merge string
RebaseBranch string RebaseBranch string
RenameBranch string RenameBranch string
SetUnsetUpstream string
CreateBranch string CreateBranch string
FastForwardBranch string FastForwardBranch string
CherryPick string CherryPick string
@ -906,7 +910,9 @@ func EnglishTranslationSet() TranslationSet {
LcRemoveRemotePrompt: "Are you sure you want to remove remote", LcRemoveRemotePrompt: "Are you sure you want to remove remote",
DeleteRemoteBranch: "Delete Remote Branch", DeleteRemoteBranch: "Delete Remote Branch",
DeleteRemoteBranchMessage: "Are you sure you want to delete remote branch", DeleteRemoteBranchMessage: "Are you sure you want to delete remote branch",
LcSetUpstream: "set as upstream of checked-out branch", LcSetAsUpstream: "set as upstream of checked-out branch",
LcSetUpstream: "set upstream of selected branch",
LcUnsetUpstream: "unset upstream of selected branch",
SetUpstreamTitle: "Set upstream branch", SetUpstreamTitle: "Set upstream branch",
SetUpstreamMessage: "Are you sure you want to set the upstream branch of '{{.checkedOut}}' to '{{.selected}}'", SetUpstreamMessage: "Are you sure you want to set the upstream branch of '{{.checkedOut}}' to '{{.selected}}'",
LcEditRemote: "edit remote", LcEditRemote: "edit remote",
@ -939,6 +945,7 @@ func EnglishTranslationSet() TranslationSet {
Panel: "Panel", Panel: "Panel",
Keybindings: "Keybindings", Keybindings: "Keybindings",
LcRenameBranch: "rename branch", LcRenameBranch: "rename branch",
LcSetUnsetUpstream: "set/unset upstream",
NewBranchNamePrompt: "Enter new branch name for branch", NewBranchNamePrompt: "Enter new branch name for branch",
RenameBranchWarning: "This branch is tracking a remote. This action will only rename the local branch name, not the name of the remote branch. Continue?", RenameBranchWarning: "This branch is tracking a remote. This action will only rename the local branch name, not the name of the remote branch. Continue?",
LcOpenMenu: "open menu", LcOpenMenu: "open menu",
@ -1088,6 +1095,7 @@ func EnglishTranslationSet() TranslationSet {
Merge: "Merge", Merge: "Merge",
RebaseBranch: "Rebase branch", RebaseBranch: "Rebase branch",
RenameBranch: "Rename branch", RenameBranch: "Rename branch",
SetUnsetUpstream: "Set/unset upstream",
CreateBranch: "Create branch", CreateBranch: "Create branch",
CherryPick: "(Cherry-pick) Paste commits", CherryPick: "(Cherry-pick) Paste commits",
CheckoutFile: "Checkout file", CheckoutFile: "Checkout file",