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 <bircni@icloud.com>
This commit is contained in:
Giteabot
2026-07-09 18:29:28 -07:00
committed by GitHub
parent d9534e7bfa
commit bfebc4b0e1
3 changed files with 54 additions and 1 deletions

View File

@@ -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
}

View File

@@ -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 <x@m.com>"},
},
[]*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 <c@m.com>"},
},
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 <me@silverwind.io>"},
},
nil,
},
}
for _, c := range cases {
assert.Equal(t, c.coAuthors, c.commit.CoAuthorIdentities())
}
}

View File

@@ -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