Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXing Xin <xingxin.xx@bytedance.com>2023-05-04 14:52:22 +0300
committerJames Fargher <jfargher@gitlab.com>2023-06-28 01:19:19 +0300
commit764515237a36e2f5d77f99fc5ddd2e324741599f (patch)
treef1340045505ec5e85cc1c4ada299bbc688ca2075
parent26780b6ce4906b1efd90020ab40560bff5cbec67 (diff)
localrepo: Avoid getting all branches for default branch detectionblanet_default_branch_opt
To detect the default branch of a repo, we are currently getting all its branches and compare one by one. This approach is unnecessarily expensive, especially for repos having too many branches, giving HEAD is actually available for the vast majority of repos. This commit adjusts the logic of GetDefaultBranch, we now prefer detection using git-rev-parse to exhaustion using git-for-each-ref. For example, gitlab-org/gitlab has around 14,000 branches, getting all its branches took around 40ms for all refs packed in packed-refs. $ time git for-each-ref --format="%(refname)%00%(objectname)%00%(symref)" refs/heads/ >/dev/null real 0m0.042s user 0m0.032s sys 0m0.010s And it's getting terribly bad for all loose-refs. $ time git for-each-ref --format="%(refname)%00%(objectname)%00%(symref)" refs/heads/ >/dev/null real 0m0.177s user 0m0.062s sys 0m0.111s But it's much quicker to detect the existence of a branch. $ time git rev-parse --verify refs/heads/master >/dev/null real 0m0.003s user 0m0.002s sys 0m0.001s In addition to the comparison of git commands mentioned above, we can also save more time and memory for not iterating and keeping the branches list. Changelog: performance Signed-off-by: Xing Xin <xingxin.xx@bytedance.com>
-rw-r--r--internal/git/localrepo/refs.go41
1 files changed, 12 insertions, 29 deletions
diff --git a/internal/git/localrepo/refs.go b/internal/git/localrepo/refs.go
index d88f95911..dd3248f02 100644
--- a/internal/git/localrepo/refs.go
+++ b/internal/git/localrepo/refs.go
@@ -326,17 +326,6 @@ func (repo *Repo) GetRemoteReferences(ctx context.Context, remote string, opts .
// GetDefaultBranch determines the default branch name
func (repo *Repo) GetDefaultBranch(ctx context.Context) (git.ReferenceName, error) {
- branches, err := repo.GetBranches(ctx)
- if err != nil {
- return "", err
- }
- switch len(branches) {
- case 0:
- return "", nil
- case 1:
- return branches[0].Name, nil
- }
-
headReference, err := repo.HeadReference(ctx)
if err != nil {
return "", err
@@ -344,30 +333,24 @@ func (repo *Repo) GetDefaultBranch(ctx context.Context) (git.ReferenceName, erro
// Ideally we would only use HEAD to determine the default branch, but
// gitlab-rails depends on the branch being determined like this.
- var defaultRef, legacyDefaultRef git.ReferenceName
- for _, branch := range branches {
- if len(headReference) != 0 && headReference == branch.Name {
- return branch.Name, nil
+ for _, headCandidate := range []git.ReferenceName{
+ headReference, git.DefaultRef, git.LegacyDefaultRef,
+ } {
+ has, err := repo.HasRevision(ctx, headCandidate.Revision())
+ if err != nil {
+ return "", err
}
-
- if git.DefaultRef == branch.Name {
- defaultRef = branch.Name
+ if has {
+ return headCandidate, nil
}
-
- if git.LegacyDefaultRef == branch.Name {
- legacyDefaultRef = branch.Name
- }
- }
-
- if len(defaultRef) != 0 {
- return defaultRef, nil
}
- if len(legacyDefaultRef) != 0 {
- return legacyDefaultRef, nil
+ // If all else fails, return the first branch name
+ branches, err := repo.getReferences(ctx, 1, "refs/heads/")
+ if err != nil || len(branches) == 0 {
+ return "", err
}
- // If all else fails, return the first branch name
return branches[0].Name, nil
}