44package repository
55
66import (
7- "context "
7+ "errors "
88 "fmt"
99
1010 issue_model "code.gitea.io/gitea/models/issues"
@@ -18,16 +18,24 @@ import (
1818)
1919
2020// MergeUpstream merges the base repository's default branch into the fork repository's current branch.
21- func MergeUpstream (ctx context. Context , doer * user_model.User , repo * repo_model.Repository , branch string ) (mergeStyle string , err error ) {
21+ func MergeUpstream (ctx reqctx. RequestContext , doer * user_model.User , repo * repo_model.Repository , branch string ) (mergeStyle string , err error ) {
2222 if err = repo .MustNotBeArchived (); err != nil {
2323 return "" , err
2424 }
2525 if err = repo .GetBaseRepo (ctx ); err != nil {
2626 return "" , err
2727 }
28+ divergingInfo , err := GetUpstreamDivergingInfo (ctx , repo , branch )
29+ if err != nil {
30+ return "" , err
31+ }
32+ if ! divergingInfo .BaseBranchHasNewCommits {
33+ return "up-to-date" , nil
34+ }
35+
2836 err = git .Push (ctx , repo .BaseRepo .RepoPath (), git.PushOptions {
2937 Remote : repo .RepoPath (),
30- Branch : fmt .Sprintf ("%s:%s" , repo . BaseRepo . DefaultBranch , branch ),
38+ Branch : fmt .Sprintf ("%s:%s" , divergingInfo . BaseBranchName , branch ),
3139 Env : repo_module .PushingEnvironment (doer , repo ),
3240 })
3341 if err == nil {
@@ -59,7 +67,7 @@ func MergeUpstream(ctx context.Context, doer *user_model.User, repo *repo_model.
5967 BaseRepoID : repo .BaseRepo .ID ,
6068 BaseRepo : repo .BaseRepo ,
6169 HeadBranch : branch , // maybe HeadCommitID is not needed
62- BaseBranch : repo . BaseRepo . DefaultBranch ,
70+ BaseBranch : divergingInfo . BaseBranchName ,
6371 }
6472 fakeIssue .PullRequest = fakePR
6573 err = pull .Update (ctx , fakePR , doer , "merge upstream" , false )
@@ -69,8 +77,15 @@ func MergeUpstream(ctx context.Context, doer *user_model.User, repo *repo_model.
6977 return "merge" , nil
7078}
7179
80+ // UpstreamDivergingInfo is also used in templates, so it needs to search for all references before changing it.
81+ type UpstreamDivergingInfo struct {
82+ BaseBranchName string
83+ BaseBranchHasNewCommits bool
84+ HeadBranchCommitsBehind int
85+ }
86+
7287// GetUpstreamDivergingInfo returns the information about the divergence between the fork repository's branch and the base repository's default branch.
73- func GetUpstreamDivergingInfo (ctx reqctx.RequestContext , forkRepo * repo_model.Repository , forkBranch string ) (* BranchDivergingInfo , error ) {
88+ func GetUpstreamDivergingInfo (ctx reqctx.RequestContext , forkRepo * repo_model.Repository , forkBranch string ) (* UpstreamDivergingInfo , error ) {
7489 if ! forkRepo .IsFork {
7590 return nil , util .NewInvalidArgumentErrorf ("repo is not a fork" )
7691 }
@@ -83,5 +98,26 @@ func GetUpstreamDivergingInfo(ctx reqctx.RequestContext, forkRepo *repo_model.Re
8398 return nil , err
8499 }
85100
86- return GetBranchDivergingInfo (ctx , forkRepo .BaseRepo , forkRepo .BaseRepo .DefaultBranch , forkRepo , forkBranch )
101+ // Do the best to follow the GitHub's behavior, suppose there is a `branch-a` in fork repo:
102+ // * if `branch-a` exists in base repo: try to sync `base:branch-a` to `fork:branch-a`
103+ // * if `branch-a` doesn't exist in base repo: try to sync `base:main` to `fork:branch-a`
104+ info , err := GetBranchDivergingInfo (ctx , forkRepo .BaseRepo , forkBranch , forkRepo , forkBranch )
105+ if err == nil {
106+ return & UpstreamDivergingInfo {
107+ BaseBranchName : forkBranch ,
108+ BaseBranchHasNewCommits : info .BaseHasNewCommits ,
109+ HeadBranchCommitsBehind : info .HeadCommitsBehind ,
110+ }, nil
111+ }
112+ if errors .Is (err , util .ErrNotExist ) {
113+ info , err = GetBranchDivergingInfo (ctx , forkRepo .BaseRepo , forkRepo .BaseRepo .DefaultBranch , forkRepo , forkBranch )
114+ if err == nil {
115+ return & UpstreamDivergingInfo {
116+ BaseBranchName : forkRepo .BaseRepo .DefaultBranch ,
117+ BaseBranchHasNewCommits : info .BaseHasNewCommits ,
118+ HeadBranchCommitsBehind : info .HeadCommitsBehind ,
119+ }, nil
120+ }
121+ }
122+ return nil , err
87123}
0 commit comments