mirror of
				https://github.com/jesseduffield/lazygit.git
				synced 2025-10-30 23:57:43 +02:00 
			
		
		
		
	Add option to (un)set upstream for a local branch
This commit is contained in:
		| @@ -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>g</kbd>: view reset options | ||||
|   <kbd>R</kbd>: rename branch | ||||
|   <kbd>u</kbd>: set/unset upstream | ||||
|   <kbd>enter</kbd>: view commits | ||||
| </pre> | ||||
|  | ||||
|   | ||||
| @@ -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>g</kbd>: bekijk reset opties | ||||
|   <kbd>R</kbd>: hernoem branch | ||||
|   <kbd>u</kbd>: set/unset upstream | ||||
|   <kbd>enter</kbd>: bekijk commits | ||||
| </pre> | ||||
|  | ||||
|   | ||||
| @@ -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>g</kbd>: wyświetl opcje resetu | ||||
|   <kbd>R</kbd>: rename branch | ||||
|   <kbd>u</kbd>: set/unset upstream | ||||
|   <kbd>enter</kbd>: view commits | ||||
| </pre> | ||||
|  | ||||
|   | ||||
| @@ -74,6 +74,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | ||||
|   <kbd>f</kbd>: 从上游快进此分支 | ||||
|   <kbd>g</kbd>: 查看重置选项 | ||||
|   <kbd>R</kbd>: 重命名分支 | ||||
|   <kbd>u</kbd>: set/unset upstream | ||||
|   <kbd>enter</kbd>: 查看提交 | ||||
| </pre> | ||||
|  | ||||
|   | ||||
| @@ -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() | ||||
| } | ||||
|  | ||||
| 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) { | ||||
| 	return self.GetCommitDifferences("HEAD", "HEAD@{u}") | ||||
| } | ||||
|   | ||||
| @@ -23,12 +23,13 @@ func (gui *Gui) resetControllers() { | ||||
| 	) | ||||
|  | ||||
| 	rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon, gui.State.Contexts, gui.git, gui.takeOverMergeConflictScrolling, refsHelper) | ||||
| 	suggestionsHelper := helpers.NewSuggestionsHelper(helperCommon, model, gui.refreshSuggestions) | ||||
| 	gui.helpers = &helpers.Helpers{ | ||||
| 		Refs:           refsHelper, | ||||
| 		Host:           helpers.NewHostHelper(helperCommon, gui.git), | ||||
| 		PatchBuilding:  helpers.NewPatchBuildingHelper(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), | ||||
| 		WorkingTree:    helpers.NewWorkingTreeHelper(helperCommon, gui.git, model), | ||||
| 		Tags:           helpers.NewTagsHelper(helperCommon, gui.git), | ||||
| @@ -41,6 +42,7 @@ func (gui *Gui) resetControllers() { | ||||
| 			func() *cherrypicking.CherryPicking { return gui.State.Modes.CherryPicking }, | ||||
| 			rebaseHelper, | ||||
| 		), | ||||
| 		Upstream: helpers.NewUpstreamHelper(helperCommon, model, suggestionsHelper.GetRemoteBranchesSuggestionsFunc), | ||||
| 	} | ||||
|  | ||||
| 	gui.CustomCommandsClient = custom_commands.NewClient( | ||||
| @@ -64,7 +66,6 @@ func (gui *Gui) resetControllers() { | ||||
|  | ||||
| 	syncController := controllers.NewSyncController( | ||||
| 		common, | ||||
| 		gui.getSuggestedRemote, | ||||
| 	) | ||||
|  | ||||
| 	submodulesController := controllers.NewSubmodulesController( | ||||
|   | ||||
| @@ -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() | ||||
| } | ||||
|   | ||||
| @@ -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{}, | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										78
									
								
								pkg/gui/controllers/helpers/upstream_helper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								pkg/gui/controllers/helpers/upstream_helper.go
									
									
									
									
									
										Normal 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 | ||||
| } | ||||
| @@ -1,4 +1,4 @@ | ||||
| package gui | ||||
| package helpers | ||||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| @@ -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), | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
| @@ -312,6 +312,7 @@ func chineseTranslationSet() TranslationSet { | ||||
| 		DeleteRemoteBranch:                  "删除远程分支", | ||||
| 		DeleteRemoteBranchMessage:           "您确定要删除远程分支吗?", | ||||
| 		LcSetUpstream:                       "设置为检出分支的上游", | ||||
| 		LcSetAsUpstream:                     "设置为检出分支的上游", | ||||
| 		SetUpstreamTitle:                    "设置上游分支", | ||||
| 		SetUpstreamMessage:                  "您确定要将 {{.checkedOut}} 的上游分支设置为 {{.selected}} 吗?", | ||||
| 		LcEditRemote:                        "编辑远程仓库", | ||||
|   | ||||
| @@ -271,6 +271,7 @@ func dutchTranslationSet() TranslationSet { | ||||
| 		DeleteRemoteBranch:                  "Verwijder Remote Branch", | ||||
| 		DeleteRemoteBranchMessage:           "Weet je zeker dat je deze remote branch wilt verwijderen", | ||||
| 		LcSetUpstream:                       "stel in als upstream van uitgecheckte branch", | ||||
| 		LcSetAsUpstream:                     "stel in als upstream van uitgecheckte branch", | ||||
| 		SetUpstreamTitle:                    "Stel in als upstream branch", | ||||
| 		SetUpstreamMessage:                  "Weet je zeker dat je de upstream branch van '{{.checkedOut}}' naar '{{.selected}}' wilt zetten", | ||||
| 		LcEditRemote:                        "wijzig remote", | ||||
|   | ||||
| @@ -306,7 +306,9 @@ type TranslationSet struct { | ||||
| 	LcRemoveRemotePrompt                string | ||||
| 	DeleteRemoteBranch                  string | ||||
| 	DeleteRemoteBranchMessage           string | ||||
| 	LcSetAsUpstream                     string | ||||
| 	LcSetUpstream                       string | ||||
| 	LcUnsetUpstream                     string | ||||
| 	SetUpstreamTitle                    string | ||||
| 	SetUpstreamMessage                  string | ||||
| 	LcEditRemote                        string | ||||
| @@ -339,6 +341,7 @@ type TranslationSet struct { | ||||
| 	Panel                               string | ||||
| 	Keybindings                         string | ||||
| 	LcRenameBranch                      string | ||||
| 	LcSetUnsetUpstream                  string | ||||
| 	NewGitFlowBranchPrompt              string | ||||
| 	RenameBranchWarning                 string | ||||
| 	LcOpenMenu                          string | ||||
| @@ -506,6 +509,7 @@ type Actions struct { | ||||
| 	Merge                             string | ||||
| 	RebaseBranch                      string | ||||
| 	RenameBranch                      string | ||||
| 	SetUnsetUpstream                  string | ||||
| 	CreateBranch                      string | ||||
| 	FastForwardBranch                 string | ||||
| 	CherryPick                        string | ||||
| @@ -906,7 +910,9 @@ func EnglishTranslationSet() TranslationSet { | ||||
| 		LcRemoveRemotePrompt:                "Are you sure you want to remove remote", | ||||
| 		DeleteRemoteBranch:                  "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", | ||||
| 		SetUpstreamMessage:                  "Are you sure you want to set the upstream branch of '{{.checkedOut}}' to '{{.selected}}'", | ||||
| 		LcEditRemote:                        "edit remote", | ||||
| @@ -939,6 +945,7 @@ func EnglishTranslationSet() TranslationSet { | ||||
| 		Panel:                               "Panel", | ||||
| 		Keybindings:                         "Keybindings", | ||||
| 		LcRenameBranch:                      "rename branch", | ||||
| 		LcSetUnsetUpstream:                  "set/unset upstream", | ||||
| 		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?", | ||||
| 		LcOpenMenu:                          "open menu", | ||||
| @@ -1088,6 +1095,7 @@ func EnglishTranslationSet() TranslationSet { | ||||
| 			Merge:                             "Merge", | ||||
| 			RebaseBranch:                      "Rebase branch", | ||||
| 			RenameBranch:                      "Rename branch", | ||||
| 			SetUnsetUpstream:                  "Set/unset upstream", | ||||
| 			CreateBranch:                      "Create branch", | ||||
| 			CherryPick:                        "(Cherry-pick) Paste commits", | ||||
| 			CheckoutFile:                      "Checkout file", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user