diff --git a/models/git/branch.go b/models/git/branch.go index e683ce47e65..a264f555d9d 100644 --- a/models/git/branch.go +++ b/models/git/branch.go @@ -440,6 +440,8 @@ type FindRecentlyPushedNewBranchesOptions struct { } type RecentlyPushedNewBranch struct { + BranchRepo *repo_model.Repository + BranchName string BranchDisplayName string BranchLink string BranchCompareURL string @@ -540,7 +542,9 @@ func FindRecentlyPushedNewBranches(ctx context.Context, doer *user_model.User, o branchDisplayName = fmt.Sprintf("%s:%s", branch.Repo.FullName(), branchDisplayName) } newBranches = append(newBranches, &RecentlyPushedNewBranch{ + BranchRepo: branch.Repo, BranchDisplayName: branchDisplayName, + BranchName: branch.Name, BranchLink: fmt.Sprintf("%s/src/branch/%s", branch.Repo.Link(), util.PathEscapeSegments(branch.Name)), BranchCompareURL: branch.Repo.ComposeBranchCompareURL(opts.BaseRepo, branch.Name), CommitTime: branch.CommitTime, diff --git a/routers/web/repo/view_home.go b/routers/web/repo/view_home.go index ff2ee3c7ec1..d141df181ce 100644 --- a/routers/web/repo/view_home.go +++ b/routers/web/repo/view_home.go @@ -215,10 +215,28 @@ func prepareRecentlyPushedNewBranches(ctx *context.Context) { if !opts.Repo.IsMirror && !opts.BaseRepo.IsMirror && opts.BaseRepo.UnitEnabled(ctx, unit_model.TypePullRequests) && baseRepoPerm.CanRead(unit_model.TypePullRequests) { - ctx.Data["RecentlyPushedNewBranches"], err = git_model.FindRecentlyPushedNewBranches(ctx, ctx.Doer, opts) + var finalBranches []*git_model.RecentlyPushedNewBranch + branches, err := git_model.FindRecentlyPushedNewBranches(ctx, ctx.Doer, opts) if err != nil { log.Error("FindRecentlyPushedNewBranches failed: %v", err) } + + for _, branch := range branches { + divergingInfo, err := repo_service.GetBranchDivergingInfo(ctx, + branch.BranchRepo, branch.BranchName, // "base" repo for diverging info + opts.BaseRepo, opts.BaseRepo.DefaultBranch, // "head" repo for diverging info + ) + if err != nil { + log.Error("GetBranchDivergingInfo failed: %v", err) + continue + } + branchRepoHasNewCommits := divergingInfo.BaseHasNewCommits + baseRepoCommitsBehind := divergingInfo.HeadCommitsBehind + if branchRepoHasNewCommits || baseRepoCommitsBehind > 0 { + finalBranches = append(finalBranches, branch) + } + } + ctx.Data["RecentlyPushedNewBranches"] = finalBranches } } } diff --git a/services/repository/branch.go b/services/repository/branch.go index a1065f56411..08c53bbb6a8 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -26,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/queue" repo_module "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/modules/reqctx" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" webhook_module "code.gitea.io/gitea/modules/webhook" @@ -665,3 +666,59 @@ func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, gitR return nil } + +// BranchDivergingInfo contains the information about the divergence of a head branch to the base branch. +// This struct is also used in templates, so it needs to search for all references before changing it. +type BranchDivergingInfo struct { + BaseHasNewCommits bool + HeadCommitsBehind int + HeadCommitsAhead int +} + +// GetBranchDivergingInfo returns the information about the divergence of a patch branch to the base branch. +func GetBranchDivergingInfo(ctx reqctx.RequestContext, baseRepo *repo_model.Repository, baseBranch string, headRepo *repo_model.Repository, headBranch string) (*BranchDivergingInfo, error) { + headGitBranch, err := git_model.GetBranch(ctx, headRepo.ID, headBranch) + if err != nil { + return nil, err + } + + baseGitBranch, err := git_model.GetBranch(ctx, baseRepo.ID, baseBranch) + if err != nil { + return nil, err + } + + info := &BranchDivergingInfo{} + if headGitBranch.CommitID == baseGitBranch.CommitID { + return info, nil + } + + // if the fork repo has new commits, this call will fail because they are not in the base repo + // exit status 128 - fatal: Invalid symmetric difference expression aaaaaaaaaaaa...bbbbbbbbbbbb + // so at the moment, we first check the update time, then check whether the fork branch has base's head + diff, err := git.GetDivergingCommits(ctx, baseRepo.RepoPath(), baseGitBranch.CommitID, headGitBranch.CommitID) + if err != nil { + info.BaseHasNewCommits = baseGitBranch.UpdatedUnix > headGitBranch.UpdatedUnix + if headRepo.IsFork && info.BaseHasNewCommits { + return info, nil + } + // if the base's update time is before the fork, check whether the base's head is in the fork + headGitRepo, err := gitrepo.RepositoryFromRequestContextOrOpen(ctx, headRepo) + if err != nil { + return nil, err + } + headCommit, err := headGitRepo.GetCommit(headGitBranch.CommitID) + if err != nil { + return nil, err + } + baseCommitID, err := git.NewIDFromString(baseGitBranch.CommitID) + if err != nil { + return nil, err + } + hasPreviousCommit, _ := headCommit.HasPreviousCommit(baseCommitID) + info.BaseHasNewCommits = !hasPreviousCommit + return info, nil + } + + info.HeadCommitsBehind, info.HeadCommitsAhead = diff.Behind, diff.Ahead + return info, nil +} diff --git a/services/repository/merge_upstream.go b/services/repository/merge_upstream.go index ef161889c09..008e7de3857 100644 --- a/services/repository/merge_upstream.go +++ b/services/repository/merge_upstream.go @@ -7,24 +7,16 @@ import ( "context" "fmt" - git_model "code.gitea.io/gitea/models/git" issue_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/gitrepo" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/reqctx" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/pull" ) -type UpstreamDivergingInfo struct { - BaseHasNewCommits bool - CommitsBehind int - CommitsAhead int -} - // MergeUpstream merges the base repository's default branch into the fork repository's current branch. func MergeUpstream(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, branch string) (mergeStyle string, err error) { if err = repo.MustNotBeArchived(); err != nil { @@ -78,67 +70,18 @@ func MergeUpstream(ctx context.Context, doer *user_model.User, repo *repo_model. } // GetUpstreamDivergingInfo returns the information about the divergence between the fork repository's branch and the base repository's default branch. -func GetUpstreamDivergingInfo(ctx reqctx.RequestContext, repo *repo_model.Repository, branch string) (*UpstreamDivergingInfo, error) { - if !repo.IsFork { +func GetUpstreamDivergingInfo(ctx reqctx.RequestContext, forkRepo *repo_model.Repository, forkBranch string) (*BranchDivergingInfo, error) { + if !forkRepo.IsFork { return nil, util.NewInvalidArgumentErrorf("repo is not a fork") } - if repo.IsArchived { + if forkRepo.IsArchived { return nil, util.NewInvalidArgumentErrorf("repo is archived") } - if err := repo.GetBaseRepo(ctx); err != nil { + if err := forkRepo.GetBaseRepo(ctx); err != nil { return nil, err } - forkBranch, err := git_model.GetBranch(ctx, repo.ID, branch) - if err != nil { - return nil, err - } - - baseBranch, err := git_model.GetBranch(ctx, repo.BaseRepo.ID, repo.BaseRepo.DefaultBranch) - if err != nil { - return nil, err - } - - info := &UpstreamDivergingInfo{} - if forkBranch.CommitID == baseBranch.CommitID { - return info, nil - } - - // if the fork repo has new commits, this call will fail because they are not in the base repo - // exit status 128 - fatal: Invalid symmetric difference expression aaaaaaaaaaaa...bbbbbbbbbbbb - // so at the moment, we first check the update time, then check whether the fork branch has base's head - diff, err := git.GetDivergingCommits(ctx, repo.BaseRepo.RepoPath(), baseBranch.CommitID, forkBranch.CommitID) - if err != nil { - info.BaseHasNewCommits = baseBranch.UpdatedUnix > forkBranch.UpdatedUnix - if info.BaseHasNewCommits { - return info, nil - } - - // if the base's update time is before the fork, check whether the base's head is in the fork - baseGitRepo, err := gitrepo.RepositoryFromRequestContextOrOpen(ctx, repo.BaseRepo) - if err != nil { - return nil, err - } - headGitRepo, err := gitrepo.RepositoryFromRequestContextOrOpen(ctx, repo) - if err != nil { - return nil, err - } - - baseCommitID, err := baseGitRepo.ConvertToGitID(baseBranch.CommitID) - if err != nil { - return nil, err - } - headCommit, err := headGitRepo.GetCommit(forkBranch.CommitID) - if err != nil { - return nil, err - } - hasPreviousCommit, _ := headCommit.HasPreviousCommit(baseCommitID) - info.BaseHasNewCommits = !hasPreviousCommit - return info, nil - } - - info.CommitsBehind, info.CommitsAhead = diff.Behind, diff.Ahead - return info, nil + return GetBranchDivergingInfo(ctx, forkRepo.BaseRepo, forkRepo.BaseRepo.DefaultBranch, forkRepo, forkBranch) } diff --git a/templates/repo/code/upstream_diverging_info.tmpl b/templates/repo/code/upstream_diverging_info.tmpl index a1f37b8c05d..8d6e55959f5 100644 --- a/templates/repo/code/upstream_diverging_info.tmpl +++ b/templates/repo/code/upstream_diverging_info.tmpl @@ -1,10 +1,10 @@ -{{if and .UpstreamDivergingInfo (or .UpstreamDivergingInfo.BaseHasNewCommits .UpstreamDivergingInfo.CommitsBehind)}} +{{if and .UpstreamDivergingInfo (or .UpstreamDivergingInfo.BaseHasNewCommits .UpstreamDivergingInfo.HeadCommitsBehind)}}