@ -5,6 +5,7 @@ package repository
import (
"context"
"errors"
"fmt"
issue_model "code.gitea.io/gitea/models/issues"
@ -24,9 +25,17 @@ func MergeUpstream(ctx context.Context, doer *user_model.User, repo *repo_model.
if err = repo . GetBaseRepo ( ctx ) ; err != nil {
return "" , err
}
divergingInfo , err := GetUpstreamDivergingInfo ( ctx , repo , branch )
if err != nil {
return "" , err
}
if ! divergingInfo . BaseBranchHasNewCommits {
return "up-to-date" , nil
}
err = git . Push ( ctx , repo . BaseRepo . RepoPath ( ) , git . PushOptions {
Remote : repo . RepoPath ( ) ,
Branch : fmt . Sprintf ( "%s:%s" , repo . BaseRepo . DefaultBranch , branch ) ,
Branch : fmt . Sprintf ( "%s:%s" , divergingInf o. BaseBranchName , branch ) ,
Env : repo_module . PushingEnvironment ( doer , repo ) ,
} )
if err == nil {
@ -58,7 +67,7 @@ func MergeUpstream(ctx context.Context, doer *user_model.User, repo *repo_model.
BaseRepoID : repo . BaseRepo . ID ,
BaseRepo : repo . BaseRepo ,
HeadBranch : branch , // maybe HeadCommitID is not needed
BaseBranch : rep o. BaseRepo . Default Branch ,
BaseBranch : divergingInf o. BaseBranchName ,
}
fakeIssue . PullRequest = fakePR
err = pull . Update ( ctx , fakePR , doer , "merge upstream" , false )
@ -68,8 +77,15 @@ func MergeUpstream(ctx context.Context, doer *user_model.User, repo *repo_model.
return "merge" , nil
}
// UpstreamDivergingInfo is also used in templates, so it needs to search for all references before changing it.
type UpstreamDivergingInfo struct {
BaseBranchName string
BaseBranchHasNewCommits bool
HeadBranchCommitsBehind int
}
// GetUpstreamDivergingInfo returns the information about the divergence between the fork repository's branch and the base repository's default branch.
func GetUpstreamDivergingInfo ( ctx context . Context , forkRepo * repo_model . Repository , forkBranch string ) ( * BranchDivergingInfo , error ) {
func GetUpstreamDivergingInfo ( ctx context . Context , forkRepo * repo_model . Repository , forkBranch string ) ( * Upstream DivergingInfo, error ) {
if ! forkRepo . IsFork {
return nil , util . NewInvalidArgumentErrorf ( "repo is not a fork" )
}
@ -82,5 +98,26 @@ func GetUpstreamDivergingInfo(ctx context.Context, forkRepo *repo_model.Reposito
return nil , err
}
return GetBranchDivergingInfo ( ctx , forkRepo . BaseRepo , forkRepo . BaseRepo . DefaultBranch , forkRepo , forkBranch )
// Do the best to follow the GitHub's behavior, suppose there is a `branch-a` in fork repo:
// * if `branch-a` exists in base repo: try to sync `base:branch-a` to `fork:branch-a`
// * if `branch-a` doesn't exist in base repo: try to sync `base:main` to `fork:branch-a`
info , err := GetBranchDivergingInfo ( ctx , forkRepo . BaseRepo , forkBranch , forkRepo , forkBranch )
if err == nil {
return & UpstreamDivergingInfo {
BaseBranchName : forkBranch ,
BaseBranchHasNewCommits : info . BaseHasNewCommits ,
HeadBranchCommitsBehind : info . HeadCommitsBehind ,
} , nil
}
if errors . Is ( err , util . ErrNotExist ) {
info , err = GetBranchDivergingInfo ( ctx , forkRepo . BaseRepo , forkRepo . BaseRepo . DefaultBranch , forkRepo , forkBranch )
if err == nil {
return & UpstreamDivergingInfo {
BaseBranchName : forkRepo . BaseRepo . DefaultBranch ,
BaseBranchHasNewCommits : info . BaseHasNewCommits ,
HeadBranchCommitsBehind : info . HeadCommitsBehind ,
} , nil
}
}
return nil , err
}