feat: improve getting shortstat (#9587)

Refactor the existing functions to get shortstat of commit and between two commits to use performant alternatives, mainly `git-diff-tree` and `git-diff-index`.

Resolves forgejo/forgejo#9551

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/9587
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
Co-authored-by: Gusted <postmaster@gusted.xyz>
Co-committed-by: Gusted <postmaster@gusted.xyz>
This commit is contained in:
Gusted 2025-10-10 14:15:38 +02:00 committed by Gusted
parent 84e9b566a0
commit 419eb0a4a2
28 changed files with 116 additions and 32 deletions

View file

@ -9,6 +9,7 @@ import (
"bytes"
"cmp"
"context"
"errors"
"fmt"
"html"
"html/template"
@ -1285,31 +1286,21 @@ type PullDiffStats struct {
// GetPullDiffStats
func GetPullDiffStats(gitRepo *git.Repository, opts *DiffOptions) (*PullDiffStats, error) {
repoPath := gitRepo.Path
diff := &PullDiffStats{}
separator := "..."
if opts.DirectComparison {
separator = ".."
}
objectFormat, err := gitRepo.GetObjectFormat()
if err != nil {
return nil, err
}
diffPaths := []string{opts.BeforeCommitID + separator + opts.AfterCommitID}
if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == objectFormat.EmptyObjectID().String() {
diffPaths = []string{objectFormat.EmptyTree().String(), opts.AfterCommitID}
opts.BeforeCommitID = objectFormat.EmptyTree().String()
opts.DirectComparison = true
}
diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(gitRepo.Ctx, repoPath, nil, diffPaths...)
if err != nil && strings.Contains(err.Error(), "no merge base") {
// git >= 2.28 now returns an error if base and head have become unrelated.
// previously it would return the results of git diff --shortstat base head so let's try that...
diffPaths = []string{opts.BeforeCommitID, opts.AfterCommitID}
diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(gitRepo.Ctx, repoPath, nil, diffPaths...)
diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = gitRepo.GetShortStat(opts.BeforeCommitID, opts.AfterCommitID, !opts.DirectComparison)
if errors.Is(err, git.ErrNoMergebaseFound) {
diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = gitRepo.GetShortStat(opts.BeforeCommitID, opts.AfterCommitID, false)
}
if err != nil {
return nil, err