Skip to content

Commit d647e74

Browse files
authored
Improve squash merge commit author and co-author with private emails (#22977)
When emails addresses are private, squash merges always use `@noreply.localhost` for the author of the squash commit. And the author is redundantly added as a co-author in the commit message. Also without private mails, the redundant co-author is possible when committing with a signature that's different than the user full name and primary email. Now try to find a commit by the same user in the list of commits, and prefer the signature from that over one constructed from the account settings.
1 parent 0141d16 commit d647e74

File tree

2 files changed

+53
-7
lines changed

2 files changed

+53
-7
lines changed

services/pull/merge_squash.go

+43-5
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,62 @@ import (
77
"fmt"
88

99
repo_model "code.gitea.io/gitea/models/repo"
10+
user_model "code.gitea.io/gitea/models/user"
11+
"code.gitea.io/gitea/modules/container"
1012
"code.gitea.io/gitea/modules/git"
1113
"code.gitea.io/gitea/modules/log"
1214
"code.gitea.io/gitea/modules/setting"
1315
)
1416

17+
// doMergeStyleSquash gets a commit author signature for squash commits
18+
func getAuthorSignatureSquash(ctx *mergeContext) (*git.Signature, error) {
19+
if err := ctx.pr.Issue.LoadPoster(ctx); err != nil {
20+
log.Error("%-v Issue[%d].LoadPoster: %v", ctx.pr, ctx.pr.Issue.ID, err)
21+
return nil, err
22+
}
23+
24+
// Try to get an signature from the same user in one of the commits, as the
25+
// poster email might be private or commits might have a different signature
26+
// than the primary email address of the poster.
27+
gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, ctx.tmpBasePath)
28+
if err != nil {
29+
log.Error("%-v Unable to open base repository: %v", ctx.pr, err)
30+
return nil, err
31+
}
32+
defer closer.Close()
33+
34+
commits, err := gitRepo.CommitsBetweenIDs(trackingBranch, "HEAD")
35+
if err != nil {
36+
log.Error("%-v Unable to get commits between: %s %s: %v", ctx.pr, "HEAD", trackingBranch, err)
37+
return nil, err
38+
}
39+
40+
uniqueEmails := make(container.Set[string])
41+
for _, commit := range commits {
42+
if commit.Author != nil && uniqueEmails.Add(commit.Author.Email) {
43+
commitUser, _ := user_model.GetUserByEmail(ctx, commit.Author.Email)
44+
if commitUser != nil && commitUser.ID == ctx.pr.Issue.Poster.ID {
45+
return commit.Author, nil
46+
}
47+
}
48+
}
49+
50+
return ctx.pr.Issue.Poster.NewGitSig(), nil
51+
}
52+
1553
// doMergeStyleSquash squashes the tracking branch on the current HEAD (=base)
1654
func doMergeStyleSquash(ctx *mergeContext, message string) error {
55+
sig, err := getAuthorSignatureSquash(ctx)
56+
if err != nil {
57+
return fmt.Errorf("getAuthorSignatureSquash: %w", err)
58+
}
59+
1760
cmdMerge := git.NewCommand(ctx, "merge", "--squash").AddDynamicArguments(trackingBranch)
1861
if err := runMergeCommand(ctx, repo_model.MergeStyleSquash, cmdMerge); err != nil {
1962
log.Error("%-v Unable to merge --squash tracking into base: %v", ctx.pr, err)
2063
return err
2164
}
2265

23-
if err := ctx.pr.Issue.LoadPoster(ctx); err != nil {
24-
log.Error("%-v Issue[%d].LoadPoster: %v", ctx.pr, ctx.pr.Issue.ID, err)
25-
return fmt.Errorf("LoadPoster: %w", err)
26-
}
27-
sig := ctx.pr.Issue.Poster.NewGitSig()
2866
if setting.Repository.PullRequest.AddCoCommitterTrailers && ctx.committer.String() != sig.String() {
2967
// add trailer
3068
message += fmt.Sprintf("\nCo-authored-by: %s\nCo-committed-by: %s\n", sig.String(), sig.String())

services/pull/pull.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,12 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ
669669

670670
authorString := commit.Author.String()
671671
if uniqueAuthors.Add(authorString) && authorString != posterSig {
672-
authors = append(authors, authorString)
672+
// Compare use account as well to avoid adding the same author multiple times
673+
// times when email addresses are private or multiple emails are used.
674+
commitUser, _ := user_model.GetUserByEmail(ctx, commit.Author.Email)
675+
if commitUser == nil || commitUser.ID != pr.Issue.Poster.ID {
676+
authors = append(authors, authorString)
677+
}
673678
}
674679
}
675680

@@ -690,7 +695,10 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ
690695
for _, commit := range commits {
691696
authorString := commit.Author.String()
692697
if uniqueAuthors.Add(authorString) && authorString != posterSig {
693-
authors = append(authors, authorString)
698+
commitUser, _ := user_model.GetUserByEmail(ctx, commit.Author.Email)
699+
if commitUser == nil || commitUser.ID != pr.Issue.Poster.ID {
700+
authors = append(authors, authorString)
701+
}
694702
}
695703
}
696704
skip += limit

0 commit comments

Comments
 (0)