From 43472b1fbffc28cf93b51ca06bc2b0a4e2966cc3 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 19 Mar 2025 21:04:12 -0700 Subject: [PATCH 1/8] Fix dependency recycle --- models/git/branch.go | 10 ++++++++ models/migrations/migrations.go | 1 + models/migrations/v1_24/v318.go | 15 ++++++++++++ models/repo/repo.go | 11 --------- modules/git/repo_commit.go | 12 +--------- routers/api/v1/utils/git.go | 4 +++- .../actions => routers/common}/artifacts.go | 2 +- routers/web/repo/commit.go | 2 +- services/context/repo.go | 13 ++++------- services/mirror/mirror_pull.go | 14 ++--------- services/pull/merge.go | 4 ---- services/repository/cache.go | 23 ++++++++++++++++++- services/repository/commit.go | 15 ++++++------ services/repository/push.go | 23 +++++++++++-------- 14 files changed, 83 insertions(+), 66 deletions(-) create mode 100644 models/migrations/v1_24/v318.go rename {modules/actions => routers/common}/artifacts.go (98%) diff --git a/models/git/branch.go b/models/git/branch.go index d1caa35947b40..13bca74affd32 100644 --- a/models/git/branch.go +++ b/models/git/branch.go @@ -109,6 +109,7 @@ type Branch struct { Repo *repo_model.Repository `xorm:"-"` Name string `xorm:"UNIQUE(s) NOT NULL"` // git's ref-name is case-sensitive internally, however, in some databases (mssql, mysql, by default), it's case-insensitive at the moment CommitID string + CommitCount int64 // the number of commits in this branch CommitMessage string `xorm:"TEXT"` // it only stores the message summary (the first line) PusherID int64 Pusher *user_model.User `xorm:"-"` @@ -251,6 +252,15 @@ func UpdateBranch(ctx context.Context, repoID, pusherID int64, branchName string }) } +func UpdateBranchCommitCount(ctx context.Context, repoID int64, branchName string, commitCount int64) error { + _, err := db.GetEngine(ctx).Where("repo_id=? AND name=?", repoID, branchName). + Cols("commit_count"). + Update(&Branch{ + CommitCount: commitCount, + }) + return err +} + // AddDeletedBranch adds a deleted branch to the database func AddDeletedBranch(ctx context.Context, repoID int64, branchName string, deletedByID int64) error { branch, err := GetBranch(ctx, repoID, branchName) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 572738013f802..25155161a11ce 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -378,6 +378,7 @@ func prepareMigrationTasks() []*migration { newMigration(315, "Add Ephemeral to ActionRunner", v1_24.AddEphemeralToActionRunner), newMigration(316, "Add description for secrets and variables", v1_24.AddDescriptionForSecretsAndVariables), newMigration(317, "Add new index for action for heatmap", v1_24.AddNewIndexForUserDashboard), + newMigration(318, "Add branch commits count for branch table", v1_24.AddBranchCommitsCount), } return preparedMigrations } diff --git a/models/migrations/v1_24/v318.go b/models/migrations/v1_24/v318.go new file mode 100644 index 0000000000000..9063891b61232 --- /dev/null +++ b/models/migrations/v1_24/v318.go @@ -0,0 +1,15 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_24 //nolint + +import ( + "xorm.io/xorm" +) + +func AddBranchCommitsCount(x *xorm.Engine) error { + type Branch struct { + CommitCount int64 // the number of commits in this branch + } + return x.Sync(new(Branch)) +} diff --git a/models/repo/repo.go b/models/repo/repo.go index a8732f60bfff8..c81e57989e40e 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -376,17 +376,6 @@ func (repo *Repository) APIURL() string { return setting.AppURL + "api/v1/repos/" + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name) } -// GetCommitsCountCacheKey returns cache key used for commits count caching. -func (repo *Repository) GetCommitsCountCacheKey(contextName string, isRef bool) string { - var prefix string - if isRef { - prefix = "ref" - } else { - prefix = "commit" - } - return fmt.Sprintf("commits-count-%d-%s-%s", repo.ID, prefix, contextName) -} - // LoadUnits loads repo units into repo.Units func (repo *Repository) LoadUnits(ctx context.Context) (err error) { if repo.Units != nil { diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index 72f35711f0fd6..01067f4501881 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -502,18 +502,8 @@ func (repo *Repository) IsCommitInBranch(commitID, branch string) (r bool, err e return len(stdout) > 0, err } -func (repo *Repository) AddLastCommitCache(cacheKey, fullName, sha string) error { +func (repo *Repository) AddLastCommitCache(commitsCount int64, fullName, sha string) error { if repo.LastCommitCache == nil { - commitsCount, err := cache.GetInt64(cacheKey, func() (int64, error) { - commit, err := repo.GetCommit(sha) - if err != nil { - return 0, err - } - return commit.CommitsCount() - }) - if err != nil { - return err - } repo.LastCommitCache = NewLastCommitCache(commitsCount, fullName, repo, cache.GetCache()) } return nil diff --git a/routers/api/v1/utils/git.go b/routers/api/v1/utils/git.go index af672ba14766e..000ef46a5f591 100644 --- a/routers/api/v1/utils/git.go +++ b/routers/api/v1/utils/git.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/services/context" + repo_service "code.gitea.io/gitea/services/repository" ) // ResolveRefOrSha resolve ref to sha if exist @@ -38,7 +39,8 @@ func ResolveRefOrSha(ctx *context.APIContext, ref string) string { sha = MustConvertToSHA1(ctx, ctx.Repo, sha) if ctx.Repo.GitRepo != nil { - err := ctx.Repo.GitRepo.AddLastCommitCache(ctx.Repo.Repository.GetCommitsCountCacheKey(ref, ref != sha), ctx.Repo.Repository.FullName(), sha) + commitsCount, _ := repo_service.GetRefCommitsCount(ctx, ctx.Repo.Repository.ID, git.RefName(ref)) + err := ctx.Repo.GitRepo.AddLastCommitCache(commitsCount, ctx.Repo.Repository.FullName(), sha) if err != nil { log.Error("Unable to get commits count for %s in %s. Error: %v", sha, ctx.Repo.Repository.FullName(), err) } diff --git a/modules/actions/artifacts.go b/routers/common/artifacts.go similarity index 98% rename from modules/actions/artifacts.go rename to routers/common/artifacts.go index 4d074435efc8f..2e8247ff5eb86 100644 --- a/modules/actions/artifacts.go +++ b/routers/common/artifacts.go @@ -1,7 +1,7 @@ // Copyright 2025 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package actions +package common import ( "net/http" diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 3fd1eacb581eb..0249256639103 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -263,7 +263,7 @@ func FileHistory(ctx *context.Context) { } func LoadBranchesAndTags(ctx *context.Context) { - response, err := repo_service.LoadBranchesAndTags(ctx, ctx.Repo, ctx.PathParam("sha")) + response, err := repo_service.LoadBranchesAndTags(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.Repo.RepoLink, ctx.PathParam("sha")) if err == nil { ctx.JSON(http.StatusOK, response) return diff --git a/services/context/repo.go b/services/context/repo.go index 6eccd1312a971..80332afbdc337 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -32,6 +32,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" asymkey_service "code.gitea.io/gitea/services/asymkey" + repo_service "code.gitea.io/gitea/services/repository" "github.com/editorconfig/editorconfig-core-go/v2" ) @@ -164,15 +165,11 @@ func (r *Repository) CanCreateIssueDependencies(ctx context.Context, user *user_ } // GetCommitsCount returns cached commit count for current view -func (r *Repository) GetCommitsCount() (int64, error) { +func (r *Repository) GetCommitsCount(ctx context.Context) (int64, error) { if r.Commit == nil { return 0, nil } - contextName := r.RefFullName.ShortName() - isRef := r.RefFullName.IsBranch() || r.RefFullName.IsTag() - return cache.GetInt64(r.Repository.GetCommitsCountCacheKey(contextName, isRef), func() (int64, error) { - return r.Commit.CommitsCount() - }) + return repo_service.GetRefCommitsCount(ctx, r.Repository.ID, r.RefFullName) } // GetCommitGraphsCount returns cached commit count for current view @@ -782,7 +779,7 @@ func RepoRefByDefaultBranch() func(*Context) { ctx.Repo.RefFullName = git.RefNameFromBranch(ctx.Repo.Repository.DefaultBranch) ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch ctx.Repo.Commit, _ = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.BranchName) - ctx.Repo.CommitsCount, _ = ctx.Repo.GetCommitsCount() + ctx.Repo.CommitsCount, _ = ctx.Repo.GetCommitsCount(ctx) ctx.Data["RefFullName"] = ctx.Repo.RefFullName ctx.Data["BranchName"] = ctx.Repo.BranchName ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount @@ -931,7 +928,7 @@ func RepoRefByType(detectRefType git.RefType) func(*Context) { ctx.Data["CanCreateBranch"] = ctx.Repo.CanCreateBranch() // only used by the branch selector dropdown: AllowCreateNewRef - ctx.Repo.CommitsCount, err = ctx.Repo.GetCommitsCount() + ctx.Repo.CommitsCount, err = ctx.Repo.GetCommitsCount(ctx) if err != nil { ctx.ServerError("GetCommitsCount", err) return diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index 658747e7c83f1..022b7b5feb463 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -11,7 +11,6 @@ import ( repo_model "code.gitea.io/gitea/models/repo" system_model "code.gitea.io/gitea/models/system" - "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" giturl "code.gitea.io/gitea/modules/git/url" "code.gitea.io/gitea/modules/gitrepo" @@ -411,17 +410,6 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo log.Trace("SyncMirrors [repo: %-v Wiki]: git remote update complete", m.Repo) } - log.Trace("SyncMirrors [repo: %-v]: invalidating mirror branch caches...", m.Repo) - branches, _, err := gitrepo.GetBranchesByPath(ctx, m.Repo, 0, 0) - if err != nil { - log.Error("SyncMirrors [repo: %-v]: failed to GetBranches: %v", m.Repo, err) - return nil, false - } - - for _, branch := range branches { - cache.Remove(m.Repo.GetCommitsCountCacheKey(branch.Name, true)) - } - m.UpdatedUnix = timeutil.TimeStampNow() return parseRemoteUpdateOutput(output, m.GetRemoteName()), true } @@ -616,6 +604,8 @@ func checkAndUpdateEmptyRepository(ctx context.Context, m *repo_model.Mirror, re hasDefault = hasDefault || name == defaultBranchName hasMaster = hasMaster || name == "master" hasMain = hasMain || name == "main" + + // TODO: update branch commits count } if len(firstName) > 0 { diff --git a/services/pull/merge.go b/services/pull/merge.go index 1e1ca55bc12e9..4d0f41d3f5e05 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -21,7 +21,6 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/globallock" "code.gitea.io/gitea/modules/httplib" @@ -251,9 +250,6 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U notify_service.MergePullRequest(ctx, doer, pr) } - // Reset cached commit count - cache.Remove(pr.Issue.Repo.GetCommitsCountCacheKey(pr.BaseBranch, true)) - return handleCloseCrossReferences(ctx, pr, doer) } diff --git a/services/repository/cache.go b/services/repository/cache.go index b0811a99fc03b..8e811069f6a7d 100644 --- a/services/repository/cache.go +++ b/services/repository/cache.go @@ -6,11 +6,32 @@ package repository import ( "context" + git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" ) +func GetRefCommitsCount(ctx context.Context, repoID int64, refFullName git.RefName) (int64, error) { + // Get the commit count of the branch or the tag + switch { + case refFullName.IsBranch(): + branch, err := git_model.GetBranch(ctx, repoID, refFullName.BranchName()) + if err != nil { + return 0, err + } + return branch.CommitCount, nil + case refFullName.IsTag(): + tag, err := repo_model.GetRelease(ctx, repoID, refFullName.TagName()) + if err != nil { + return 0, err + } + return tag.NumCommits, nil + default: + return 0, nil + } +} + // CacheRef cachhe last commit information of the branch or the tag func CacheRef(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, fullRefName git.RefName) error { commit, err := gitRepo.GetCommit(fullRefName.String()) @@ -19,7 +40,7 @@ func CacheRef(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Rep } if gitRepo.LastCommitCache == nil { - commitsCount, err := cache.GetInt64(repo.GetCommitsCountCacheKey(fullRefName.ShortName(), true), commit.CommitsCount) + commitsCount, err := GetRefCommitsCount(ctx, repo.ID, fullRefName) if err != nil { return err } diff --git a/services/repository/commit.go b/services/repository/commit.go index e8c0262ef41c7..7845bdcc25d6b 100644 --- a/services/repository/commit.go +++ b/services/repository/commit.go @@ -7,8 +7,9 @@ import ( "context" "fmt" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/util" - gitea_ctx "code.gitea.io/gitea/services/context" ) type ContainedLinks struct { // TODO: better name? @@ -23,18 +24,18 @@ type namedLink struct { // TODO: better name? } // LoadBranchesAndTags creates a new repository branch -func LoadBranchesAndTags(ctx context.Context, baseRepo *gitea_ctx.Repository, commitSHA string) (*ContainedLinks, error) { - containedTags, err := baseRepo.GitRepo.ListOccurrences(ctx, "tag", commitSHA) +func LoadBranchesAndTags(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, repoLink string, commitSHA string) (*ContainedLinks, error) { + containedTags, err := gitRepo.ListOccurrences(ctx, "tag", commitSHA) if err != nil { return nil, fmt.Errorf("encountered a problem while querying %s: %w", "tags", err) } - containedBranches, err := baseRepo.GitRepo.ListOccurrences(ctx, "branch", commitSHA) + containedBranches, err := gitRepo.ListOccurrences(ctx, "branch", commitSHA) if err != nil { return nil, fmt.Errorf("encountered a problem while querying %s: %w", "branches", err) } result := &ContainedLinks{ - DefaultBranch: baseRepo.Repository.DefaultBranch, + DefaultBranch: repo.DefaultBranch, Branches: make([]*namedLink, 0, len(containedBranches)), Tags: make([]*namedLink, 0, len(containedTags)), } @@ -42,13 +43,13 @@ func LoadBranchesAndTags(ctx context.Context, baseRepo *gitea_ctx.Repository, co // TODO: Use a common method to get the link to a branch/tag instead of hard-coding it here result.Tags = append(result.Tags, &namedLink{ Name: tag, - WebLink: fmt.Sprintf("%s/src/tag/%s", baseRepo.RepoLink, util.PathEscapeSegments(tag)), + WebLink: fmt.Sprintf("%s/src/tag/%s", repoLink, util.PathEscapeSegments(tag)), }) } for _, branch := range containedBranches { result.Branches = append(result.Branches, &namedLink{ Name: branch, - WebLink: fmt.Sprintf("%s/src/branch/%s", baseRepo.RepoLink, util.PathEscapeSegments(branch)), + WebLink: fmt.Sprintf("%s/src/branch/%s", repoLink, util.PathEscapeSegments(branch)), }) } return result, nil diff --git a/services/repository/push.go b/services/repository/push.go index 6d3b9dd252abc..e9dc1080b8bd3 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -11,9 +11,9 @@ import ( "time" "code.gitea.io/gitea/models/db" + git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/graceful" @@ -296,7 +296,16 @@ func pushNewBranch(ctx context.Context, repo *repo_model.Repository, pusher *use return l, nil } -func pushUpdateBranch(_ context.Context, repo *repo_model.Repository, pusher *user_model.User, opts *repo_module.PushUpdateOptions, newCommit *git.Commit) ([]*git.Commit, error) { +func UpdateRepoBranchCommitsCount(ctx context.Context, repo *repo_model.Repository, branch string, newCommit *git.Commit, isForcePush bool) error { + // calculate the number of commits in the branch + commitsCount, err := newCommit.CommitsCount() + if err != nil { + return fmt.Errorf("newCommit.CommitsCount: %w", err) + } + return git_model.UpdateBranchCommitCount(ctx, repo.ID, branch, commitsCount) +} + +func pushUpdateBranch(ctx context.Context, repo *repo_model.Repository, pusher *user_model.User, opts *repo_module.PushUpdateOptions, newCommit *git.Commit) ([]*git.Commit, error) { l, err := newCommit.CommitsBeforeUntil(opts.OldCommitID) if err != nil { return nil, fmt.Errorf("newCommit.CommitsBeforeUntil: %w", err) @@ -320,13 +329,9 @@ func pushUpdateBranch(_ context.Context, repo *repo_model.Repository, pusher *us NewCommitID: opts.NewCommitID, }) - if isForcePush { - log.Trace("Push %s is a force push", opts.NewCommitID) - - cache.Remove(repo.GetCommitsCountCacheKey(opts.RefName(), true)) - } else { - // TODO: increment update the commit count cache but not remove - cache.Remove(repo.GetCommitsCountCacheKey(opts.RefName(), true)) + // calculate the number of commits in the branch + if err := UpdateRepoBranchCommitsCount(ctx, repo, branch, newCommit, isForcePush); err != nil { + log.Error("UpdateRepoBranchCommitsCount: %v", err) } return l, nil From 269a4facf08bc481c580c8a383d61a5461f46f93 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 19 Mar 2025 21:32:03 -0700 Subject: [PATCH 2/8] Fix bug --- .../common => modules/actions}/artifacts.go | 2 +- modules/git/ref.go | 12 ++++++++++ routers/api/v1/utils/git.go | 3 +-- routers/web/repo/repo.go | 2 +- services/context/repo.go | 23 ++++++++++++++++-- services/repository/cache.go | 24 ++----------------- services/repository/commit.go | 2 +- services/repository/files/content.go | 7 +++++- 8 files changed, 45 insertions(+), 30 deletions(-) rename {routers/common => modules/actions}/artifacts.go (98%) diff --git a/routers/common/artifacts.go b/modules/actions/artifacts.go similarity index 98% rename from routers/common/artifacts.go rename to modules/actions/artifacts.go index 2e8247ff5eb86..4d074435efc8f 100644 --- a/routers/common/artifacts.go +++ b/modules/actions/artifacts.go @@ -1,7 +1,7 @@ // Copyright 2025 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package common +package actions import ( "net/http" diff --git a/modules/git/ref.go b/modules/git/ref.go index f20a175e422a8..b8b3dbd5b5aee 100644 --- a/modules/git/ref.go +++ b/modules/git/ref.go @@ -84,6 +84,18 @@ func RefNameFromCommit(shortName string) RefName { return RefName(shortName) } +func RefNameFromObjectTypeAndShortName(objectType ObjectType, shortName string) RefName { + switch objectType { + case ObjectBranch: + return RefNameFromBranch(shortName) + case ObjectTag: + return RefNameFromTag(shortName) + case ObjectCommit: + return RefNameFromCommit(shortName) + } + return RefName(shortName) +} + func (ref RefName) String() string { return string(ref) } diff --git a/routers/api/v1/utils/git.go b/routers/api/v1/utils/git.go index 000ef46a5f591..f9544e298595f 100644 --- a/routers/api/v1/utils/git.go +++ b/routers/api/v1/utils/git.go @@ -12,7 +12,6 @@ import ( "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/services/context" - repo_service "code.gitea.io/gitea/services/repository" ) // ResolveRefOrSha resolve ref to sha if exist @@ -39,7 +38,7 @@ func ResolveRefOrSha(ctx *context.APIContext, ref string) string { sha = MustConvertToSHA1(ctx, ctx.Repo, sha) if ctx.Repo.GitRepo != nil { - commitsCount, _ := repo_service.GetRefCommitsCount(ctx, ctx.Repo.Repository.ID, git.RefName(ref)) + commitsCount, _ := context.GetRefCommitsCount(ctx, ctx.Repo.Repository.ID, git.RefName(ref)) err := ctx.Repo.GitRepo.AddLastCommitCache(commitsCount, ctx.Repo.Repository.FullName(), sha) if err != nil { log.Error("Unable to get commits count for %s in %s. Error: %v", sha, ctx.Repo.Repository.FullName(), err) diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 73baf683ed577..0bcb907e54376 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -71,7 +71,7 @@ func CommitInfoCache(ctx *context.Context) { ctx.ServerError("GetBranchCommit", err) return } - ctx.Repo.CommitsCount, err = ctx.Repo.GetCommitsCount() + ctx.Repo.CommitsCount, err = ctx.Repo.GetCommitsCount(ctx) if err != nil { ctx.ServerError("GetCommitsCount", err) return diff --git a/services/context/repo.go b/services/context/repo.go index 80332afbdc337..849f5877f04bd 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -32,7 +32,6 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" asymkey_service "code.gitea.io/gitea/services/asymkey" - repo_service "code.gitea.io/gitea/services/repository" "github.com/editorconfig/editorconfig-core-go/v2" ) @@ -164,12 +163,32 @@ func (r *Repository) CanCreateIssueDependencies(ctx context.Context, user *user_ return r.Repository.IsDependenciesEnabled(ctx) && r.Permission.CanWriteIssuesOrPulls(isPull) } +func GetRefCommitsCount(ctx context.Context, repoID int64, refFullName git.RefName) (int64, error) { + // Get the commit count of the branch or the tag + switch { + case refFullName.IsBranch(): + branch, err := git_model.GetBranch(ctx, repoID, refFullName.BranchName()) + if err != nil { + return 0, err + } + return branch.CommitCount, nil + case refFullName.IsTag(): + tag, err := repo_model.GetRelease(ctx, repoID, refFullName.TagName()) + if err != nil { + return 0, err + } + return tag.NumCommits, nil + default: + return 0, nil + } +} + // GetCommitsCount returns cached commit count for current view func (r *Repository) GetCommitsCount(ctx context.Context) (int64, error) { if r.Commit == nil { return 0, nil } - return repo_service.GetRefCommitsCount(ctx, r.Repository.ID, r.RefFullName) + return GetRefCommitsCount(ctx, r.Repository.ID, r.RefFullName) } // GetCommitGraphsCount returns cached commit count for current view diff --git a/services/repository/cache.go b/services/repository/cache.go index 8e811069f6a7d..e19b7449b479e 100644 --- a/services/repository/cache.go +++ b/services/repository/cache.go @@ -6,32 +6,12 @@ package repository import ( "context" - git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" + context_service "code.gitea.io/gitea/services/context" ) -func GetRefCommitsCount(ctx context.Context, repoID int64, refFullName git.RefName) (int64, error) { - // Get the commit count of the branch or the tag - switch { - case refFullName.IsBranch(): - branch, err := git_model.GetBranch(ctx, repoID, refFullName.BranchName()) - if err != nil { - return 0, err - } - return branch.CommitCount, nil - case refFullName.IsTag(): - tag, err := repo_model.GetRelease(ctx, repoID, refFullName.TagName()) - if err != nil { - return 0, err - } - return tag.NumCommits, nil - default: - return 0, nil - } -} - // CacheRef cachhe last commit information of the branch or the tag func CacheRef(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, fullRefName git.RefName) error { commit, err := gitRepo.GetCommit(fullRefName.String()) @@ -40,7 +20,7 @@ func CacheRef(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Rep } if gitRepo.LastCommitCache == nil { - commitsCount, err := GetRefCommitsCount(ctx, repo.ID, fullRefName) + commitsCount, err := context_service.GetRefCommitsCount(ctx, repo.ID, fullRefName) if err != nil { return err } diff --git a/services/repository/commit.go b/services/repository/commit.go index 7845bdcc25d6b..8447bc37abc6b 100644 --- a/services/repository/commit.go +++ b/services/repository/commit.go @@ -24,7 +24,7 @@ type namedLink struct { // TODO: better name? } // LoadBranchesAndTags creates a new repository branch -func LoadBranchesAndTags(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, repoLink string, commitSHA string) (*ContainedLinks, error) { +func LoadBranchesAndTags(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, repoLink, commitSHA string) (*ContainedLinks, error) { containedTags, err := gitRepo.ListOccurrences(ctx, "tag", commitSHA) if err != nil { return nil, fmt.Errorf("encountered a problem while querying %s: %w", "tags", err) diff --git a/services/repository/files/content.go b/services/repository/files/content.go index 0ab7422ce2ebf..616b47928fcf3 100644 --- a/services/repository/files/content.go +++ b/services/repository/files/content.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + context_service "code.gitea.io/gitea/services/context" ) // ContentType repo content type @@ -165,7 +166,11 @@ func GetContents(ctx context.Context, repo *repo_model.Repository, treePath, ref } selfURLString := selfURL.String() - err = gitRepo.AddLastCommitCache(repo.GetCommitsCountCacheKey(ref, refType != git.ObjectCommit), repo.FullName(), commitID) + refName := git.RefNameFromObjectTypeAndShortName(refType, ref) + + commitsCount, _ := context_service.GetRefCommitsCount(ctx, repo.ID, refName) + + err = gitRepo.AddLastCommitCache(commitsCount, repo.FullName(), commitID) if err != nil { return nil, err } From 646d24e1d418533e7a7fbc664231976b9593bc88 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 19 Mar 2025 22:06:27 -0700 Subject: [PATCH 3/8] Add cron task to update the wrong commits counts --- models/git/branch.go | 6 +++-- models/migrations/v1_24/v318.go | 3 ++- services/cron/tasks_basic.go | 11 +++++++++ services/repository/branch.go | 44 +++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/models/git/branch.go b/models/git/branch.go index 13bca74affd32..ad3f5d4ddac37 100644 --- a/models/git/branch.go +++ b/models/git/branch.go @@ -109,6 +109,7 @@ type Branch struct { Repo *repo_model.Repository `xorm:"-"` Name string `xorm:"UNIQUE(s) NOT NULL"` // git's ref-name is case-sensitive internally, however, in some databases (mssql, mysql, by default), it's case-insensitive at the moment CommitID string + CommitCountID string // the commit id of the commit count CommitCount int64 // the number of commits in this branch CommitMessage string `xorm:"TEXT"` // it only stores the message summary (the first line) PusherID int64 @@ -252,11 +253,12 @@ func UpdateBranch(ctx context.Context, repoID, pusherID int64, branchName string }) } -func UpdateBranchCommitCount(ctx context.Context, repoID int64, branchName string, commitCount int64) error { +func UpdateBranchCommitCount(ctx context.Context, repoID int64, branchName, commitID string, commitCount int64) error { _, err := db.GetEngine(ctx).Where("repo_id=? AND name=?", repoID, branchName). Cols("commit_count"). Update(&Branch{ - CommitCount: commitCount, + CommitCount: commitCount, + CommitCountID: commitID, }) return err } diff --git a/models/migrations/v1_24/v318.go b/models/migrations/v1_24/v318.go index 9063891b61232..262018b9caecf 100644 --- a/models/migrations/v1_24/v318.go +++ b/models/migrations/v1_24/v318.go @@ -9,7 +9,8 @@ import ( func AddBranchCommitsCount(x *xorm.Engine) error { type Branch struct { - CommitCount int64 // the number of commits in this branch + CommitCountID string // the commit id of the commit count + CommitCount int64 // the number of commits in this branch } return x.Sync(new(Branch)) } diff --git a/services/cron/tasks_basic.go b/services/cron/tasks_basic.go index 841981787dffd..8bb83d3fc7a09 100644 --- a/services/cron/tasks_basic.go +++ b/services/cron/tasks_basic.go @@ -166,6 +166,16 @@ func registerSyncRepoLicenses() { }) } +func registerSyncBranchCommitsCount() { + RegisterTaskFatal("sync_branch_commits_count", &BaseConfig{ + Enabled: true, + RunAtStart: true, + Schedule: "@midnight", + }, func(ctx context.Context, _ *user_model.User, _ Config) error { + return repo_service.SyncBranchCommitsCount(ctx) + }) +} + func initBasicTasks() { if setting.Mirror.Enabled { registerUpdateMirrorTask() @@ -183,4 +193,5 @@ func initBasicTasks() { registerCleanupPackages() } registerSyncRepoLicenses() + registerSyncBranchCommitsCount() } diff --git a/services/repository/branch.go b/services/repository/branch.go index 8804778bd5ebb..775ac35a4db16 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -736,3 +736,47 @@ func GetBranchDivergingInfo(ctx reqctx.RequestContext, baseRepo *repo_model.Repo info.BaseHasNewCommits = info.HeadCommitsBehind > 0 return info, nil } + +func SyncBranchCommitsCount(ctx context.Context) error { + for { + select { + case <-ctx.Done(): + return nil + default: + } + + // search all branches commits count are not synced + + for _, branch := range branches { + if err := syncBranchCommitsCount(ctx, branch); err != nil { + log.Error("syncBranchCommitsCount: %v", err) + } + } + } +} + +func syncBranchCommitsCount(ctx context.Context, branch *git_model.Branch) error { + if err := branch.LoadRepo(ctx); err != nil { + return err + } + commitID, err := gitrepo.GetBranchCommitID(ctx, branch.Repo, branch.Name) + if err != nil { + return err + } + + var cols []string + if commitID != branch.CommitID { + branch.CommitID = commitID + cols = append(cols, "commit_id") + } + + commit, err := gitrepo.GetCommit(ctx, branch.Repo, commitID) + + commitsCount, err := commit.CommitsCount() + if err != nil { + return err + } + + git_model.UpdateBranchCommitCount(ctx, branch.RepoID, branch.Name, commit.ID, commitsCount) + return nil +} From 78b47babf988e5cdf0f0c0c673af49be43b7bd75 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 20 Mar 2025 15:51:36 -0700 Subject: [PATCH 4/8] Add background cron task to fix wrong branch commit count information --- models/git/branch.go | 2 +- models/git/branch_list.go | 17 ++++++++++++++++ modules/gitrepo/commit.go | 26 ++++++++++++++++++++++++ options/locale/locale_en-US.ini | 1 + services/repository/branch.go | 36 +++++++++++++++++---------------- services/repository/push.go | 2 +- 6 files changed, 65 insertions(+), 19 deletions(-) create mode 100644 modules/gitrepo/commit.go diff --git a/models/git/branch.go b/models/git/branch.go index ad3f5d4ddac37..cfe9597706e1e 100644 --- a/models/git/branch.go +++ b/models/git/branch.go @@ -255,7 +255,7 @@ func UpdateBranch(ctx context.Context, repoID, pusherID int64, branchName string func UpdateBranchCommitCount(ctx context.Context, repoID int64, branchName, commitID string, commitCount int64) error { _, err := db.GetEngine(ctx).Where("repo_id=? AND name=?", repoID, branchName). - Cols("commit_count"). + Cols("commit_count", "commit_count_id"). Update(&Branch{ CommitCount: commitCount, CommitCountID: commitID, diff --git a/models/git/branch_list.go b/models/git/branch_list.go index 25e84526d29e4..bd4d62e4a4674 100644 --- a/models/git/branch_list.go +++ b/models/git/branch_list.go @@ -146,3 +146,20 @@ func FindBranchesByRepoAndBranchName(ctx context.Context, repoBranches map[int64 } return branchMap, nil } + +func FindCommitsCountOutdatedBranches(ctx context.Context, startID, limit int64) (BranchList, error) { + var branches BranchList + if err := db.GetEngine(ctx). + Join("INNER", "repository", "branch.repo_id = repository.id"). + And("repository.is_empty = ?", false). + Where("id > ?", startID). + And( + builder.Expr("commit_count_id IS NULL"). + Or(builder.Expr("commit_id <> commit_count_id")), + ). + Asc("id"). + Limit(int(limit)).Find(&branches); err != nil { + return nil, err + } + return branches, nil +} diff --git a/modules/gitrepo/commit.go b/modules/gitrepo/commit.go new file mode 100644 index 0000000000000..d6da7bd8b5cc9 --- /dev/null +++ b/modules/gitrepo/commit.go @@ -0,0 +1,26 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package gitrepo + +import ( + "context" + + "code.gitea.io/gitea/modules/git" +) + +func GetCommit(ctx context.Context, repo Repository, commitID string) (*git.Commit, error) { + gitRepo, err := git.OpenRepository(ctx, repoPath(repo)) + if err != nil { + return nil, err + } + defer gitRepo.Close() + return gitRepo.GetCommit(commitID) +} + +func CommitsCount(ctx context.Context, repo Repository, ref string) (int64, error) { + return git.CommitsCount(ctx, git.CommitsCountOptions{ + RepoPath: repoPath(repo), + Revision: []string{ref}, + }) +} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 876e135b22f57..6e680ca5640d0 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3016,6 +3016,7 @@ dashboard.sync_branch.started = Branches Sync started dashboard.sync_tag.started = Tags Sync started dashboard.rebuild_issue_indexer = Rebuild issue indexer dashboard.sync_repo_licenses = Sync repo licenses +dashboard.sync_branch_commits_count = Sync Branch commits counts users.user_manage_panel = User Account Management users.new_account = Create User Account diff --git a/services/repository/branch.go b/services/repository/branch.go index 775ac35a4db16..d8f5194934c3e 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -738,6 +738,7 @@ func GetBranchDivergingInfo(ctx reqctx.RequestContext, baseRepo *repo_model.Repo } func SyncBranchCommitsCount(ctx context.Context) error { + startID := int64(0) for { select { case <-ctx.Done(): @@ -746,8 +747,22 @@ func SyncBranchCommitsCount(ctx context.Context) error { } // search all branches commits count are not synced + branches, err := git_model.FindCommitsCountOutdatedBranches(ctx, startID, 100) + if err != nil { + return err + } + if len(branches) == 0 { + return nil + } + + if err := branches.LoadRepo(ctx); err != nil { + return err + } for _, branch := range branches { + if branch.ID > startID { + startID = branch.ID + } if err := syncBranchCommitsCount(ctx, branch); err != nil { log.Error("syncBranchCommitsCount: %v", err) } @@ -756,27 +771,14 @@ func SyncBranchCommitsCount(ctx context.Context) error { } func syncBranchCommitsCount(ctx context.Context, branch *git_model.Branch) error { - if err := branch.LoadRepo(ctx); err != nil { - return err - } - commitID, err := gitrepo.GetBranchCommitID(ctx, branch.Repo, branch.Name) - if err != nil { - return err - } - - var cols []string - if commitID != branch.CommitID { - branch.CommitID = commitID - cols = append(cols, "commit_id") + if branch.CommitID == "" { + return nil } - commit, err := gitrepo.GetCommit(ctx, branch.Repo, commitID) - - commitsCount, err := commit.CommitsCount() + commitsCount, err := gitrepo.CommitsCount(ctx, branch.Repo, branch.CommitID) if err != nil { return err } - git_model.UpdateBranchCommitCount(ctx, branch.RepoID, branch.Name, commit.ID, commitsCount) - return nil + return git_model.UpdateBranchCommitCount(ctx, branch.RepoID, branch.Name, branch.CommitID, commitsCount) } diff --git a/services/repository/push.go b/services/repository/push.go index e9dc1080b8bd3..6dcc70e5128fe 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -302,7 +302,7 @@ func UpdateRepoBranchCommitsCount(ctx context.Context, repo *repo_model.Reposito if err != nil { return fmt.Errorf("newCommit.CommitsCount: %w", err) } - return git_model.UpdateBranchCommitCount(ctx, repo.ID, branch, commitsCount) + return git_model.UpdateBranchCommitCount(ctx, repo.ID, branch, newCommit.ID.String(), commitsCount) } func pushUpdateBranch(ctx context.Context, repo *repo_model.Repository, pusher *user_model.User, opts *repo_module.PushUpdateOptions, newCommit *git.Commit) ([]*git.Commit, error) { From 84f5a2d667f2dbe561866ec7802926fa1b46d097 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 20 Mar 2025 16:11:14 -0700 Subject: [PATCH 5/8] Fix --- services/repository/push.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/services/repository/push.go b/services/repository/push.go index 6dcc70e5128fe..70506c85de6e6 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -286,6 +286,11 @@ func pushNewBranch(ctx context.Context, repo *repo_model.Repository, pusher *use if err := repo_model.UpdateRepositoryCols(ctx, repo, "default_branch", "is_empty"); err != nil { return nil, fmt.Errorf("UpdateRepositoryCols: %w", err) } + } else { + // calculate the number of commits in the branch + if err := UpdateRepoBranchCommitsCount(ctx, repo, opts.RefFullName.BranchName(), newCommit); err != nil { + log.Error("UpdateRepoBranchCommitsCount: %v", err) + } } l, err := newCommit.CommitsBeforeLimit(10) @@ -296,7 +301,7 @@ func pushNewBranch(ctx context.Context, repo *repo_model.Repository, pusher *use return l, nil } -func UpdateRepoBranchCommitsCount(ctx context.Context, repo *repo_model.Repository, branch string, newCommit *git.Commit, isForcePush bool) error { +func UpdateRepoBranchCommitsCount(ctx context.Context, repo *repo_model.Repository, branch string, newCommit *git.Commit) error { // calculate the number of commits in the branch commitsCount, err := newCommit.CommitsCount() if err != nil { @@ -313,6 +318,11 @@ func pushUpdateBranch(ctx context.Context, repo *repo_model.Repository, pusher * branch := opts.RefFullName.BranchName() + // calculate the number of commits in the branch + if err := UpdateRepoBranchCommitsCount(ctx, repo, branch, newCommit); err != nil { + log.Error("UpdateRepoBranchCommitsCount: %v", err) + } + isForcePush, err := newCommit.IsForcePush(opts.OldCommitID) if err != nil { log.Error("IsForcePush %s:%s failed: %v", repo.FullName(), branch, err) @@ -329,11 +339,6 @@ func pushUpdateBranch(ctx context.Context, repo *repo_model.Repository, pusher * NewCommitID: opts.NewCommitID, }) - // calculate the number of commits in the branch - if err := UpdateRepoBranchCommitsCount(ctx, repo, branch, newCommit, isForcePush); err != nil { - log.Error("UpdateRepoBranchCommitsCount: %v", err) - } - return l, nil } From 29f6a3f2d15759c5c1b074aebc01471e8a53f537 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 20 Mar 2025 16:21:36 -0700 Subject: [PATCH 6/8] Fix branch commits ount in pull mirror --- models/git/branch_list.go | 18 ++++++++++++++++++ services/mirror/mirror_pull.go | 2 ++ services/repository/branch.go | 30 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/models/git/branch_list.go b/models/git/branch_list.go index bd4d62e4a4674..11b942e80dbce 100644 --- a/models/git/branch_list.go +++ b/models/git/branch_list.go @@ -163,3 +163,21 @@ func FindCommitsCountOutdatedBranches(ctx context.Context, startID, limit int64) } return branches, nil } + +func FindRepoCommitsCountOutdatedBranches(ctx context.Context, repoID, startID, limit int64) (BranchList, error) { + var branches BranchList + if err := db.GetEngine(ctx). + Join("INNER", "repository", "branch.repo_id = repository.id"). + Where("branch.repo_id = ?", repoID). + And("repository.is_empty = ?", false). + And("id > ?", startID). + And( + builder.Expr("commit_count_id IS NULL"). + Or(builder.Expr("commit_id <> commit_count_id")), + ). + Asc("id"). + Limit(int(limit)).Find(&branches); err != nil { + return nil, err + } + return branches, nil +} diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index 022b7b5feb463..f7d9e9b1243f2 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -410,6 +410,8 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo log.Trace("SyncMirrors [repo: %-v Wiki]: git remote update complete", m.Repo) } + repo_service.SyncRepoBranchesCommitsCount(ctx, m.Repo) + m.UpdatedUnix = timeutil.TimeStampNow() return parseRemoteUpdateOutput(output, m.GetRemoteName()), true } diff --git a/services/repository/branch.go b/services/repository/branch.go index d8f5194934c3e..d4fe6c3f64d17 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -737,6 +737,36 @@ func GetBranchDivergingInfo(ctx reqctx.RequestContext, baseRepo *repo_model.Repo return info, nil } +func SyncRepoBranchesCommitsCount(ctx context.Context, repo *repo_model.Repository) error { + startID := int64(0) + for { + select { + case <-ctx.Done(): + return nil + default: + } + + // search all branches commits count are not synced + branches, err := git_model.FindRepoCommitsCountOutdatedBranches(ctx, repo.ID, startID, 100) + if err != nil { + return err + } + if len(branches) == 0 { + return nil + } + + for _, branch := range branches { + branch.Repo = repo + if branch.ID > startID { + startID = branch.ID + } + if err := syncBranchCommitsCount(ctx, branch); err != nil { + log.Error("syncBranchCommitsCount: %v", err) + } + } + } +} + func SyncBranchCommitsCount(ctx context.Context) error { startID := int64(0) for { From 09dc1cdeea351f7555135454fb1d744c6e4163d6 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 20 Mar 2025 16:52:00 -0700 Subject: [PATCH 7/8] Some fix --- models/repo/repo.go | 11 +++++++++++ routers/api/v1/utils/git.go | 2 +- routers/web/repo/commit.go | 2 +- services/context/repo.go | 17 +++++++++++++++-- services/mirror/mirror_pull.go | 6 +++--- services/repository/cache.go | 2 +- services/repository/commit.go | 15 +++++++-------- services/repository/files/content.go | 2 +- 8 files changed, 40 insertions(+), 17 deletions(-) diff --git a/models/repo/repo.go b/models/repo/repo.go index c81e57989e40e..a8732f60bfff8 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -376,6 +376,17 @@ func (repo *Repository) APIURL() string { return setting.AppURL + "api/v1/repos/" + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name) } +// GetCommitsCountCacheKey returns cache key used for commits count caching. +func (repo *Repository) GetCommitsCountCacheKey(contextName string, isRef bool) string { + var prefix string + if isRef { + prefix = "ref" + } else { + prefix = "commit" + } + return fmt.Sprintf("commits-count-%d-%s-%s", repo.ID, prefix, contextName) +} + // LoadUnits loads repo units into repo.Units func (repo *Repository) LoadUnits(ctx context.Context) (err error) { if repo.Units != nil { diff --git a/routers/api/v1/utils/git.go b/routers/api/v1/utils/git.go index f9544e298595f..0ec10a885d828 100644 --- a/routers/api/v1/utils/git.go +++ b/routers/api/v1/utils/git.go @@ -38,7 +38,7 @@ func ResolveRefOrSha(ctx *context.APIContext, ref string) string { sha = MustConvertToSHA1(ctx, ctx.Repo, sha) if ctx.Repo.GitRepo != nil { - commitsCount, _ := context.GetRefCommitsCount(ctx, ctx.Repo.Repository.ID, git.RefName(ref)) + commitsCount, _ := context.GetRefCommitsCount(ctx, ctx.Repo.Repository.ID, ctx.Repo.GitRepo, git.RefName(ref)) err := ctx.Repo.GitRepo.AddLastCommitCache(commitsCount, ctx.Repo.Repository.FullName(), sha) if err != nil { log.Error("Unable to get commits count for %s in %s. Error: %v", sha, ctx.Repo.Repository.FullName(), err) diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 0249256639103..3fd1eacb581eb 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -263,7 +263,7 @@ func FileHistory(ctx *context.Context) { } func LoadBranchesAndTags(ctx *context.Context) { - response, err := repo_service.LoadBranchesAndTags(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.Repo.RepoLink, ctx.PathParam("sha")) + response, err := repo_service.LoadBranchesAndTags(ctx, ctx.Repo, ctx.PathParam("sha")) if err == nil { ctx.JSON(http.StatusOK, response) return diff --git a/services/context/repo.go b/services/context/repo.go index 849f5877f04bd..4fb6c6aff43dd 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -163,7 +163,12 @@ func (r *Repository) CanCreateIssueDependencies(ctx context.Context, user *user_ return r.Repository.IsDependenciesEnabled(ctx) && r.Permission.CanWriteIssuesOrPulls(isPull) } -func GetRefCommitsCount(ctx context.Context, repoID int64, refFullName git.RefName) (int64, error) { +// getCommitsCountCacheKey returns cache key used for commits count caching. +func getCommitsCountCacheKey(contextName string, repoID int64) string { + return fmt.Sprintf("commits-count-%d-commit-%s", repoID, contextName) +} + +func GetRefCommitsCount(ctx context.Context, repoID int64, gitRepo *git.Repository, refFullName git.RefName) (int64, error) { // Get the commit count of the branch or the tag switch { case refFullName.IsBranch(): @@ -178,6 +183,14 @@ func GetRefCommitsCount(ctx context.Context, repoID int64, refFullName git.RefNa return 0, err } return tag.NumCommits, nil + case refFullName.RefType() == git.RefTypeCommit: + return cache.GetInt64(getCommitsCountCacheKey(string(refFullName), repoID), func() (int64, error) { + commit, err := gitRepo.GetCommit(string(refFullName)) + if err != nil { + return 0, err + } + return commit.CommitsCount() + }) default: return 0, nil } @@ -188,7 +201,7 @@ func (r *Repository) GetCommitsCount(ctx context.Context) (int64, error) { if r.Commit == nil { return 0, nil } - return GetRefCommitsCount(ctx, r.Repository.ID, r.RefFullName) + return GetRefCommitsCount(ctx, r.Repository.ID, r.GitRepo, r.RefFullName) } // GetCommitGraphsCount returns cached commit count for current view diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index f7d9e9b1243f2..09f172a33afaf 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -410,7 +410,9 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo log.Trace("SyncMirrors [repo: %-v Wiki]: git remote update complete", m.Repo) } - repo_service.SyncRepoBranchesCommitsCount(ctx, m.Repo) + if err := repo_service.SyncRepoBranchesCommitsCount(ctx, m.Repo); err != nil { + log.Error("SyncMirrors [repo: %-v]: failed to sync branches commits count: %v", m.Repo, err) + } m.UpdatedUnix = timeutil.TimeStampNow() return parseRemoteUpdateOutput(output, m.GetRemoteName()), true @@ -606,8 +608,6 @@ func checkAndUpdateEmptyRepository(ctx context.Context, m *repo_model.Mirror, re hasDefault = hasDefault || name == defaultBranchName hasMaster = hasMaster || name == "master" hasMain = hasMain || name == "main" - - // TODO: update branch commits count } if len(firstName) > 0 { diff --git a/services/repository/cache.go b/services/repository/cache.go index e19b7449b479e..648ebc4c97e45 100644 --- a/services/repository/cache.go +++ b/services/repository/cache.go @@ -20,7 +20,7 @@ func CacheRef(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Rep } if gitRepo.LastCommitCache == nil { - commitsCount, err := context_service.GetRefCommitsCount(ctx, repo.ID, fullRefName) + commitsCount, err := context_service.GetRefCommitsCount(ctx, repo.ID, gitRepo, fullRefName) if err != nil { return err } diff --git a/services/repository/commit.go b/services/repository/commit.go index 8447bc37abc6b..e8c0262ef41c7 100644 --- a/services/repository/commit.go +++ b/services/repository/commit.go @@ -7,9 +7,8 @@ import ( "context" "fmt" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/util" + gitea_ctx "code.gitea.io/gitea/services/context" ) type ContainedLinks struct { // TODO: better name? @@ -24,18 +23,18 @@ type namedLink struct { // TODO: better name? } // LoadBranchesAndTags creates a new repository branch -func LoadBranchesAndTags(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, repoLink, commitSHA string) (*ContainedLinks, error) { - containedTags, err := gitRepo.ListOccurrences(ctx, "tag", commitSHA) +func LoadBranchesAndTags(ctx context.Context, baseRepo *gitea_ctx.Repository, commitSHA string) (*ContainedLinks, error) { + containedTags, err := baseRepo.GitRepo.ListOccurrences(ctx, "tag", commitSHA) if err != nil { return nil, fmt.Errorf("encountered a problem while querying %s: %w", "tags", err) } - containedBranches, err := gitRepo.ListOccurrences(ctx, "branch", commitSHA) + containedBranches, err := baseRepo.GitRepo.ListOccurrences(ctx, "branch", commitSHA) if err != nil { return nil, fmt.Errorf("encountered a problem while querying %s: %w", "branches", err) } result := &ContainedLinks{ - DefaultBranch: repo.DefaultBranch, + DefaultBranch: baseRepo.Repository.DefaultBranch, Branches: make([]*namedLink, 0, len(containedBranches)), Tags: make([]*namedLink, 0, len(containedTags)), } @@ -43,13 +42,13 @@ func LoadBranchesAndTags(ctx context.Context, repo *repo_model.Repository, gitRe // TODO: Use a common method to get the link to a branch/tag instead of hard-coding it here result.Tags = append(result.Tags, &namedLink{ Name: tag, - WebLink: fmt.Sprintf("%s/src/tag/%s", repoLink, util.PathEscapeSegments(tag)), + WebLink: fmt.Sprintf("%s/src/tag/%s", baseRepo.RepoLink, util.PathEscapeSegments(tag)), }) } for _, branch := range containedBranches { result.Branches = append(result.Branches, &namedLink{ Name: branch, - WebLink: fmt.Sprintf("%s/src/branch/%s", repoLink, util.PathEscapeSegments(branch)), + WebLink: fmt.Sprintf("%s/src/branch/%s", baseRepo.RepoLink, util.PathEscapeSegments(branch)), }) } return result, nil diff --git a/services/repository/files/content.go b/services/repository/files/content.go index 616b47928fcf3..d223dbb5fe4c0 100644 --- a/services/repository/files/content.go +++ b/services/repository/files/content.go @@ -168,7 +168,7 @@ func GetContents(ctx context.Context, repo *repo_model.Repository, treePath, ref refName := git.RefNameFromObjectTypeAndShortName(refType, ref) - commitsCount, _ := context_service.GetRefCommitsCount(ctx, repo.ID, refName) + commitsCount, _ := context_service.GetRefCommitsCount(ctx, repo.ID, gitRepo, refName) err = gitRepo.AddLastCommitCache(commitsCount, repo.FullName(), commitID) if err != nil { From 998f9ffeebd194028660d3afe94660b51b9bf20a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 22 Mar 2025 17:23:42 -0700 Subject: [PATCH 8/8] Remove unused function --- modules/gitrepo/commit.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/modules/gitrepo/commit.go b/modules/gitrepo/commit.go index d6da7bd8b5cc9..344c3f6051db0 100644 --- a/modules/gitrepo/commit.go +++ b/modules/gitrepo/commit.go @@ -9,15 +9,6 @@ import ( "code.gitea.io/gitea/modules/git" ) -func GetCommit(ctx context.Context, repo Repository, commitID string) (*git.Commit, error) { - gitRepo, err := git.OpenRepository(ctx, repoPath(repo)) - if err != nil { - return nil, err - } - defer gitRepo.Close() - return gitRepo.GetCommit(commitID) -} - func CommitsCount(ctx context.Context, repo Repository, ref string) (int64, error) { return git.CommitsCount(ctx, git.CommitsCountOptions{ RepoPath: repoPath(repo),