mirror of
				https://github.com/jesseduffield/lazygit.git
				synced 2025-10-30 23:57:43 +02:00 
			
		
		
		
	Factor out CommitLoader.mainBranches into its own class, and store it in Model
This commit is contained in:
		| @@ -35,11 +35,6 @@ type CommitLoader struct { | ||||
| 	readFile      func(filename string) ([]byte, error) | ||||
| 	walkFiles     func(root string, fn filepath.WalkFunc) error | ||||
| 	dotGitDir     string | ||||
| 	// List of main branches that exist in the repo. | ||||
| 	// We use these to obtain the merge base of the branch. | ||||
| 	// When nil, we're yet to obtain the list of existing main branches. | ||||
| 	// When an empty slice, we've obtained the list and it's empty. | ||||
| 	mainBranches []string | ||||
| 	*GitCommon | ||||
| } | ||||
|  | ||||
| @@ -56,7 +51,6 @@ func NewCommitLoader( | ||||
| 		getRebaseMode: getRebaseMode, | ||||
| 		readFile:      os.ReadFile, | ||||
| 		walkFiles:     filepath.Walk, | ||||
| 		mainBranches:  nil, | ||||
| 		GitCommon:     gitCommon, | ||||
| 	} | ||||
| } | ||||
| @@ -72,6 +66,7 @@ type GetCommitsOptions struct { | ||||
| 	All bool | ||||
| 	// If non-empty, show divergence from this ref (left-right log) | ||||
| 	RefToShowDivergenceFrom string | ||||
| 	MainBranches            *MainBranches | ||||
| } | ||||
|  | ||||
| // GetCommits obtains the commits of the current branch | ||||
| @@ -108,9 +103,9 @@ func (self *CommitLoader) GetCommits(opts GetCommitsOptions) ([]*models.Commit, | ||||
| 	go utils.Safe(func() { | ||||
| 		defer wg.Done() | ||||
|  | ||||
| 		ancestor = self.getMergeBase(opts.RefName) | ||||
| 		ancestor = self.getMergeBase(opts.RefName, opts.MainBranches) | ||||
| 		if opts.RefToShowDivergenceFrom != "" { | ||||
| 			remoteAncestor = self.getMergeBase(opts.RefToShowDivergenceFrom) | ||||
| 			remoteAncestor = self.getMergeBase(opts.RefToShowDivergenceFrom, opts.MainBranches) | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| @@ -471,12 +466,9 @@ func setCommitMergedStatuses(ancestor string, commits []*models.Commit) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (self *CommitLoader) getMergeBase(refName string) string { | ||||
| 	if self.mainBranches == nil { | ||||
| 		self.mainBranches = self.getExistingMainBranches() | ||||
| 	} | ||||
|  | ||||
| 	if len(self.mainBranches) == 0 { | ||||
| func (self *CommitLoader) getMergeBase(refName string, existingMainBranches *ExistingMainBranches) string { | ||||
| 	mainBranches := existingMainBranches.Get() | ||||
| 	if len(mainBranches) == 0 { | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| @@ -491,63 +483,12 @@ func (self *CommitLoader) getMergeBase(refName string) string { | ||||
| 	// also not very common, but can totally happen and is not an error. | ||||
|  | ||||
| 	output, _ := self.cmd.New( | ||||
| 		NewGitCmd("merge-base").Arg(refName).Arg(self.mainBranches...). | ||||
| 		NewGitCmd("merge-base").Arg(refName).Arg(mainBranches...). | ||||
| 			ToArgv(), | ||||
| 	).DontLog().RunWithOutput() | ||||
| 	return ignoringWarnings(output) | ||||
| } | ||||
|  | ||||
| func (self *CommitLoader) getExistingMainBranches() []string { | ||||
| 	var existingBranches []string | ||||
| 	var wg sync.WaitGroup | ||||
|  | ||||
| 	mainBranches := self.UserConfig.Git.MainBranches | ||||
| 	existingBranches = make([]string, len(mainBranches)) | ||||
|  | ||||
| 	for i, branchName := range mainBranches { | ||||
| 		wg.Add(1) | ||||
| 		go utils.Safe(func() { | ||||
| 			defer wg.Done() | ||||
|  | ||||
| 			// Try to determine upstream of local main branch | ||||
| 			if ref, err := self.cmd.New( | ||||
| 				NewGitCmd("rev-parse").Arg("--symbolic-full-name", branchName+"@{u}").ToArgv(), | ||||
| 			).DontLog().RunWithOutput(); err == nil { | ||||
| 				existingBranches[i] = strings.TrimSpace(ref) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			// If this failed, a local branch for this main branch doesn't exist or it | ||||
| 			// has no upstream configured. Try looking for one in the "origin" remote. | ||||
| 			ref := "refs/remotes/origin/" + branchName | ||||
| 			if err := self.cmd.New( | ||||
| 				NewGitCmd("rev-parse").Arg("--verify", "--quiet", ref).ToArgv(), | ||||
| 			).DontLog().Run(); err == nil { | ||||
| 				existingBranches[i] = ref | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			// If this failed as well, try if we have the main branch as a local | ||||
| 			// branch. This covers the case where somebody is using git locally | ||||
| 			// for something, but never pushing anywhere. | ||||
| 			ref = "refs/heads/" + branchName | ||||
| 			if err := self.cmd.New( | ||||
| 				NewGitCmd("rev-parse").Arg("--verify", "--quiet", ref).ToArgv(), | ||||
| 			).DontLog().Run(); err == nil { | ||||
| 				existingBranches[i] = ref | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	wg.Wait() | ||||
|  | ||||
| 	existingBranches = lo.Filter(existingBranches, func(branch string, _ int) bool { | ||||
| 		return branch != "" | ||||
| 	}) | ||||
|  | ||||
| 	return existingBranches | ||||
| } | ||||
|  | ||||
| func ignoringWarnings(commandOutput string) string { | ||||
| 	trimmedOutput := strings.TrimSpace(commandOutput) | ||||
| 	split := strings.Split(trimmedOutput, "\n") | ||||
|   | ||||
| @@ -307,10 +307,11 @@ func TestGetCommits(t *testing.T) { | ||||
| 			common := utils.NewDummyCommon() | ||||
| 			common.AppState = &config.AppState{} | ||||
| 			common.AppState.GitLogOrder = scenario.logOrder | ||||
| 			cmd := oscommands.NewDummyCmdObjBuilder(scenario.runner) | ||||
|  | ||||
| 			builder := &CommitLoader{ | ||||
| 				Common:        common, | ||||
| 				cmd:           oscommands.NewDummyCmdObjBuilder(scenario.runner), | ||||
| 				cmd:           cmd, | ||||
| 				getRebaseMode: func() (enums.RebaseMode, error) { return scenario.rebaseMode, nil }, | ||||
| 				dotGitDir:     ".git", | ||||
| 				readFile: func(filename string) ([]byte, error) { | ||||
| @@ -322,7 +323,9 @@ func TestGetCommits(t *testing.T) { | ||||
| 			} | ||||
|  | ||||
| 			common.UserConfig.Git.MainBranches = scenario.mainBranches | ||||
| 			commits, err := builder.GetCommits(scenario.opts) | ||||
| 			opts := scenario.opts | ||||
| 			opts.MainBranches = NewMainBranches(scenario.mainBranches, cmd) | ||||
| 			commits, err := builder.GetCommits(opts) | ||||
|  | ||||
| 			assert.Equal(t, scenario.expectedCommits, commits) | ||||
| 			assert.Equal(t, scenario.expectedError, err) | ||||
|   | ||||
							
								
								
									
										98
									
								
								pkg/commands/git_commands/main_branches.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								pkg/commands/git_commands/main_branches.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| package git_commands | ||||
|  | ||||
| import ( | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/jesseduffield/lazygit/pkg/commands/oscommands" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/utils" | ||||
| 	"github.com/samber/lo" | ||||
| 	"github.com/sasha-s/go-deadlock" | ||||
| ) | ||||
|  | ||||
| type MainBranches struct { | ||||
| 	// List of main branches configured by the user. Just the bare names. | ||||
| 	configuredMainBranches []string | ||||
| 	// Which of these actually exist in the repository. Full ref names, and it | ||||
| 	// could be either "refs/heads/..." or "refs/remotes/origin/..." depending | ||||
| 	// on which one exists for a given bare name. | ||||
| 	existingMainBranches []string | ||||
|  | ||||
| 	cmd   oscommands.ICmdObjBuilder | ||||
| 	mutex *deadlock.Mutex | ||||
| } | ||||
|  | ||||
| func NewMainBranches( | ||||
| 	configuredMainBranches []string, | ||||
| 	cmd oscommands.ICmdObjBuilder, | ||||
| ) *MainBranches { | ||||
| 	return &MainBranches{ | ||||
| 		configuredMainBranches: configuredMainBranches, | ||||
| 		existingMainBranches:   nil, | ||||
| 		cmd:                    cmd, | ||||
| 		mutex:                  &deadlock.Mutex{}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Get the list of main branches that exist in the repository. This is a list of | ||||
| // full ref names. | ||||
| func (self *MainBranches) Get() []string { | ||||
| 	self.mutex.Lock() | ||||
| 	defer self.mutex.Unlock() | ||||
|  | ||||
| 	if self.existingMainBranches == nil { | ||||
| 		self.existingMainBranches = self.determineMainBranches() | ||||
| 	} | ||||
|  | ||||
| 	return self.existingMainBranches | ||||
| } | ||||
|  | ||||
| func (self *MainBranches) determineMainBranches() []string { | ||||
| 	var existingBranches []string | ||||
| 	var wg sync.WaitGroup | ||||
|  | ||||
| 	existingBranches = make([]string, len(self.configuredMainBranches)) | ||||
|  | ||||
| 	for i, branchName := range self.configuredMainBranches { | ||||
| 		wg.Add(1) | ||||
| 		go utils.Safe(func() { | ||||
| 			defer wg.Done() | ||||
|  | ||||
| 			// Try to determine upstream of local main branch | ||||
| 			if ref, err := self.cmd.New( | ||||
| 				NewGitCmd("rev-parse").Arg("--symbolic-full-name", branchName+"@{u}").ToArgv(), | ||||
| 			).DontLog().RunWithOutput(); err == nil { | ||||
| 				existingBranches[i] = strings.TrimSpace(ref) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			// If this failed, a local branch for this main branch doesn't exist or it | ||||
| 			// has no upstream configured. Try looking for one in the "origin" remote. | ||||
| 			ref := "refs/remotes/origin/" + branchName | ||||
| 			if err := self.cmd.New( | ||||
| 				NewGitCmd("rev-parse").Arg("--verify", "--quiet", ref).ToArgv(), | ||||
| 			).DontLog().Run(); err == nil { | ||||
| 				existingBranches[i] = ref | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			// If this failed as well, try if we have the main branch as a local | ||||
| 			// branch. This covers the case where somebody is using git locally | ||||
| 			// for something, but never pushing anywhere. | ||||
| 			ref = "refs/heads/" + branchName | ||||
| 			if err := self.cmd.New( | ||||
| 				NewGitCmd("rev-parse").Arg("--verify", "--quiet", ref).ToArgv(), | ||||
| 			).DontLog().Run(); err == nil { | ||||
| 				existingBranches[i] = ref | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	wg.Wait() | ||||
|  | ||||
| 	existingBranches = lo.Filter(existingBranches, func(branch string, _ int) bool { | ||||
| 		return branch != "" | ||||
| 	}) | ||||
|  | ||||
| 	return existingBranches | ||||
| } | ||||
| @@ -331,6 +331,7 @@ func (self *RefreshHelper) refreshCommitsWithLimit() error { | ||||
| 			RefName:              self.refForLog(), | ||||
| 			RefForPushedStatus:   checkedOutBranchName, | ||||
| 			All:                  self.c.Contexts().LocalCommits.GetShowWholeGitGraph(), | ||||
| 			MainBranches:         self.c.Model().MainBranches, | ||||
| 		}, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| @@ -357,6 +358,7 @@ func (self *RefreshHelper) refreshSubCommitsWithLimit() error { | ||||
| 			RefName:                 self.c.Contexts().SubCommits.GetRef().FullRefName(), | ||||
| 			RefToShowDivergenceFrom: self.c.Contexts().SubCommits.GetRefToShowDivergenceFrom(), | ||||
| 			RefForPushedStatus:      self.c.Contexts().SubCommits.GetRef().FullRefName(), | ||||
| 			MainBranches:            self.c.Model().MainBranches, | ||||
| 		}, | ||||
| 	) | ||||
| 	if err != nil { | ||||
|   | ||||
| @@ -44,6 +44,7 @@ func (self *SubCommitsHelper) ViewSubCommits(opts ViewSubCommitsOpts) error { | ||||
| 			RefName:                 opts.Ref.FullRefName(), | ||||
| 			RefForPushedStatus:      opts.Ref.FullRefName(), | ||||
| 			RefToShowDivergenceFrom: opts.RefToShowDivergenceFrom, | ||||
| 			MainBranches:            self.c.Model().MainBranches, | ||||
| 		}, | ||||
| 	) | ||||
| 	if err != nil { | ||||
|   | ||||
| @@ -379,6 +379,7 @@ func (gui *Gui) resetState(startArgs appTypes.StartArgs) types.Context { | ||||
| 			BisectInfo:            git_commands.NewNullBisectInfo(), | ||||
| 			FilesTrie:             patricia.NewTrie(), | ||||
| 			Authors:               map[string]*models.Author{}, | ||||
| 			MainBranches:          git_commands.NewMainBranches(gui.UserConfig.Git.MainBranches, gui.os.Cmd), | ||||
| 		}, | ||||
| 		Modes: &types.Modes{ | ||||
| 			Filtering:        filtering.New(startArgs.FilterPath, ""), | ||||
|   | ||||
| @@ -281,6 +281,8 @@ type Model struct { | ||||
| 	// we're on a detached head because we're rebasing or bisecting. | ||||
| 	CheckedOutBranch string | ||||
|  | ||||
| 	MainBranches *git_commands.MainBranches | ||||
|  | ||||
| 	// for displaying suggestions while typing in a file name | ||||
| 	FilesTrie *patricia.Trie | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user