From bfebc4b0e172cf4a261b920c59f16eb8954e673a Mon Sep 17 00:00:00 2001 From: Giteabot Date: Thu, 9 Jul 2026 18:29:28 -0700 Subject: [PATCH] fix: incorrect co-author detection on commit page (#38386) (#38387) Backport #38386 by @bircni The commit page built its "co-authored by" list from `AllParticipantIdentities()[1:]`, which only drops the author and leaves the committer in the list even though the committer is already shown separately as "committed by". This caused the committer to be wrongly rendered as a co-author (issue #38384): a commit authored by `silverwind`, committed by `bircni`, with a `Co-authored-by: silverwind` trailer displayed "co-authored by bircni" instead of the actual trailer identity. This adds a `Commit.CoAuthorIdentities()` method that excludes both the author and the committer, uses it on the commit page, and covers the fix with a regression test. Closes #38384 Co-authored-by: bircni --- modules/git/commit_message.go | 14 +++++++++++ modules/git/commit_message_test.go | 39 ++++++++++++++++++++++++++++++ routers/web/repo/commit.go | 2 +- 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/modules/git/commit_message.go b/modules/git/commit_message.go index 0729609d87e..9aa3a6966a3 100644 --- a/modules/git/commit_message.go +++ b/modules/git/commit_message.go @@ -131,3 +131,17 @@ func (c *Commit) AllParticipantIdentities() []*CommitIdentity { } return c.allParticipants } + +// CoAuthorIdentities returns the commit's co-authors: the participants without the +// author and the committer, which are already displayed separately. This avoids +// surfacing the committer as a "co-author" (see issue #38384). +func (c *Commit) CoAuthorIdentities() []*CommitIdentity { + var ret []*CommitIdentity + for _, p := range c.AllParticipantIdentities()[1:] { // index 0 is always the author + if c.Committer.Email != "" && strings.EqualFold(p.Email, c.Committer.Email) { + continue + } + ret = append(ret, p) + } + return ret +} diff --git a/modules/git/commit_message_test.go b/modules/git/commit_message_test.go index 1d13f818033..ba5927d9fd6 100644 --- a/modules/git/commit_message_test.go +++ b/modules/git/commit_message_test.go @@ -80,3 +80,42 @@ func TestCommitMessageAllParticipantIdentities(t *testing.T) { assert.Equal(t, c.participant, c.commit.AllParticipantIdentities()) } } + +func TestCommitMessageCoAuthorIdentities(t *testing.T) { + sig := func(n, e string) *Signature { return &Signature{Name: n, Email: e} } + idt := func(n, e string) *CommitIdentity { return &CommitIdentity{Name: n, Email: e} } + cases := []struct { + commit *Commit + coAuthors []*CommitIdentity + }{ + { + // a genuine co-author (neither author nor committer) is reported + &Commit{ + Author: sig("a", "a@m.com"), Committer: sig("c", "c@m.com"), + CommitMessage: CommitMessage{MessageRaw: "Co-authored-by: x "}, + }, + []*CommitIdentity{idt("x", "x@m.com")}, + }, + { + // the committer is shown separately as "committed by", so it must + // not appear as a co-author even though it is a participant + &Commit{ + Author: sig("a", "a@m.com"), Committer: sig("c", "c@m.com"), + CommitMessage: CommitMessage{MessageRaw: "Co-authored-by: c "}, + }, + nil, + }, + { + // regression for #38384: a Co-authored-by trailer naming the author + // must not cause the committer to be surfaced as the co-author + &Commit{ + Author: sig("silverwind", "me@silverwind.io"), Committer: sig("bircni", "bircni@icloud.com"), + CommitMessage: CommitMessage{MessageRaw: "Co-authored-by: silverwind "}, + }, + nil, + }, + } + for _, c := range cases { + assert.Equal(t, c.coAuthors, c.commit.CoAuthorIdentities()) + } +} diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index d8953878184..b1b1909e10c 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -398,7 +398,7 @@ func Diff(ctx *context.Context) { verification := asymkey_service.ParseCommitWithSignature(ctx, commit) ctx.Data["Verification"] = verification ctx.Data["Author"] = user_model.GetUserByGitAuthor(ctx, commit) - ctx.Data["CommitOtherParticipants"] = gituser.BuildAvatarStackData(ctx, commit.AllParticipantIdentities(), nil).Participants[1:] + ctx.Data["CommitOtherParticipants"] = gituser.BuildAvatarStackData(ctx, commit.CoAuthorIdentities(), nil).Participants ctx.Data["Parents"] = parents ctx.Data["DiffNotAvailable"] = diffShortStat.NumFiles == 0