mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-10-16 09:27:37 +03:00
GetMergeBase is always called with a full ref, so it shouldn't need the ignoringWarnings hack (which is about ignoring warnings coming from ambiguous refs). Also, separate stdout and stderr, which would also have solved the problem. We no longer really need it now, but it's still cleaner.
128 lines
3.8 KiB
Go
128 lines
3.8 KiB
Go
package git_commands
|
|
|
|
import (
|
|
"slices"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
|
"github.com/jesseduffield/lazygit/pkg/common"
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
"github.com/samber/lo"
|
|
"github.com/sasha-s/go-deadlock"
|
|
)
|
|
|
|
type MainBranches struct {
|
|
c *common.Common
|
|
// Which of the configured main branches 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
|
|
|
|
previousMainBranches []string
|
|
|
|
cmd oscommands.ICmdObjBuilder
|
|
mutex deadlock.Mutex
|
|
}
|
|
|
|
func NewMainBranches(
|
|
cmn *common.Common,
|
|
cmd oscommands.ICmdObjBuilder,
|
|
) *MainBranches {
|
|
return &MainBranches{
|
|
c: cmn,
|
|
existingMainBranches: nil,
|
|
cmd: cmd,
|
|
}
|
|
}
|
|
|
|
// 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()
|
|
|
|
configuredMainBranches := self.c.UserConfig().Git.MainBranches
|
|
|
|
if self.existingMainBranches == nil || !slices.Equal(self.previousMainBranches, configuredMainBranches) {
|
|
self.existingMainBranches = self.determineMainBranches(configuredMainBranches)
|
|
self.previousMainBranches = configuredMainBranches
|
|
}
|
|
|
|
return self.existingMainBranches
|
|
}
|
|
|
|
// Return the merge base of the given refName with the closest main branch.
|
|
func (self *MainBranches) GetMergeBase(refName string) string {
|
|
mainBranches := self.Get()
|
|
if len(mainBranches) == 0 {
|
|
return ""
|
|
}
|
|
|
|
// We pass all existing main branches to the merge-base call; git will
|
|
// return the base commit for the closest one.
|
|
|
|
// We ignore errors from this call, since we can't distinguish whether the
|
|
// error is because one of the main branches has been deleted since the last
|
|
// call to determineMainBranches, or because the refName has no common
|
|
// history with any of the main branches. Since the former should happen
|
|
// very rarely, users must quit and restart lazygit to fix it; the latter is
|
|
// also not very common, but can totally happen and is not an error.
|
|
|
|
output, _, _ := self.cmd.New(
|
|
NewGitCmd("merge-base").Arg(refName).Arg(mainBranches...).
|
|
ToArgv(),
|
|
).DontLog().RunWithOutputs()
|
|
return strings.TrimSpace(output)
|
|
}
|
|
|
|
func (self *MainBranches) determineMainBranches(configuredMainBranches []string) []string {
|
|
var existingBranches []string
|
|
var wg sync.WaitGroup
|
|
|
|
existingBranches = make([]string, len(configuredMainBranches))
|
|
|
|
for i, branchName := range 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
|
|
}
|