Skip to content

Commit 6422f05

Browse files
authored
Decouple diff stats query from actual diffing (#33810)
The diff stats are no longer part of the diff generation. Use `GetDiffShortStat` instead to get the total number of changed files, added lines, and deleted lines. As such, `gitdiff.GetDiff` can be simplified: It should not do more than expected. And do not run "git diff --shortstat" for pull list. Fix #31492
1 parent 1b2dfff commit 6422f05

File tree

17 files changed

+154
-210
lines changed

17 files changed

+154
-210
lines changed

modules/git/repo_compare.go

+3-11
Original file line numberDiff line numberDiff line change
@@ -174,17 +174,9 @@ func (repo *Repository) GetDiffNumChangedFiles(base, head string, directComparis
174174
return w.numLines, nil
175175
}
176176

177-
// GetDiffShortStat counts number of changed files, number of additions and deletions
178-
func (repo *Repository) GetDiffShortStat(base, head string) (numFiles, totalAdditions, totalDeletions int, err error) {
179-
numFiles, totalAdditions, totalDeletions, err = GetDiffShortStat(repo.Ctx, repo.Path, nil, base+"..."+head)
180-
if err != nil && strings.Contains(err.Error(), "no merge base") {
181-
return GetDiffShortStat(repo.Ctx, repo.Path, nil, base, head)
182-
}
183-
return numFiles, totalAdditions, totalDeletions, err
184-
}
185-
186-
// GetDiffShortStat counts number of changed files, number of additions and deletions
187-
func GetDiffShortStat(ctx context.Context, repoPath string, trustedArgs TrustedCmdArgs, dynamicArgs ...string) (numFiles, totalAdditions, totalDeletions int, err error) {
177+
// GetDiffShortStatByCmdArgs counts number of changed files, number of additions and deletions
178+
// TODO: it can be merged with another "GetDiffShortStat" in the future
179+
func GetDiffShortStatByCmdArgs(ctx context.Context, repoPath string, trustedArgs TrustedCmdArgs, dynamicArgs ...string) (numFiles, totalAdditions, totalDeletions int, err error) {
188180
// Now if we call:
189181
// $ git diff --shortstat 1ebb35b98889ff77299f24d82da426b434b0cca0...788b8b1440462d477f45b0088875
190182
// we get:

modules/structs/pull.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@ type PullRequest struct {
2525
Draft bool `json:"draft"`
2626
IsLocked bool `json:"is_locked"`
2727
Comments int `json:"comments"`
28+
2829
// number of review comments made on the diff of a PR review (not including comments on commits or issues in a PR)
29-
ReviewComments int `json:"review_comments"`
30-
Additions int `json:"additions"`
31-
Deletions int `json:"deletions"`
32-
ChangedFiles int `json:"changed_files"`
30+
ReviewComments int `json:"review_comments,omitempty"`
31+
32+
Additions *int `json:"additions,omitempty"`
33+
Deletions *int `json:"deletions,omitempty"`
34+
ChangedFiles *int `json:"changed_files,omitempty"`
3335

3436
HTMLURL string `json:"html_url"`
3537
DiffURL string `json:"diff_url"`

routers/api/v1/repo/pull.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -1591,6 +1591,7 @@ func GetPullRequestFiles(ctx *context.APIContext) {
15911591
maxLines := setting.Git.MaxGitDiffLines
15921592

15931593
// FIXME: If there are too many files in the repo, may cause some unpredictable issues.
1594+
// FIXME: it doesn't need to call "GetDiff" to do various parsing and highlighting
15941595
diff, err := gitdiff.GetDiff(ctx, baseGitRepo,
15951596
&gitdiff.DiffOptions{
15961597
BeforeCommitID: startCommitID,
@@ -1606,9 +1607,14 @@ func GetPullRequestFiles(ctx *context.APIContext) {
16061607
return
16071608
}
16081609

1610+
diffShortStat, err := gitdiff.GetDiffShortStat(baseGitRepo, startCommitID, endCommitID)
1611+
if err != nil {
1612+
ctx.APIErrorInternal(err)
1613+
return
1614+
}
16091615
listOptions := utils.GetListOptions(ctx)
16101616

1611-
totalNumberOfFiles := diff.NumFiles
1617+
totalNumberOfFiles := diffShortStat.NumFiles
16121618
totalNumberOfPages := int(math.Ceil(float64(totalNumberOfFiles) / float64(listOptions.PageSize)))
16131619

16141620
start, limit := listOptions.GetSkipTake()

routers/web/repo/commit.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -321,12 +321,17 @@ func Diff(ctx *context.Context) {
321321
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
322322
MaxFiles: maxFiles,
323323
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)),
324-
FileOnly: fileOnly,
325324
}, files...)
326325
if err != nil {
327326
ctx.NotFound(err)
328327
return
329328
}
329+
diffShortStat, err := gitdiff.GetDiffShortStat(gitRepo, "", commitID)
330+
if err != nil {
331+
ctx.ServerError("GetDiffShortStat", err)
332+
return
333+
}
334+
ctx.Data["DiffShortStat"] = diffShortStat
330335

331336
parents := make([]string, commit.ParentCount())
332337
for i := 0; i < commit.ParentCount(); i++ {
@@ -383,7 +388,7 @@ func Diff(ctx *context.Context) {
383388
ctx.Data["Verification"] = verification
384389
ctx.Data["Author"] = user_model.ValidateCommitWithEmail(ctx, commit)
385390
ctx.Data["Parents"] = parents
386-
ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0
391+
ctx.Data["DiffNotAvailable"] = diffShortStat.NumFiles == 0
387392

388393
if err := asymkey_model.CalculateTrustStatus(verification, ctx.Repo.Repository.GetTrustModel(), func(user *user_model.User) (bool, error) {
389394
return repo_model.IsOwnerMemberCollaborator(ctx, ctx.Repo.Repository, user.ID)

routers/web/repo/compare.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -624,14 +624,19 @@ func PrepareCompareDiff(
624624
MaxFiles: maxFiles,
625625
WhitespaceBehavior: whitespaceBehavior,
626626
DirectComparison: ci.DirectComparison,
627-
FileOnly: fileOnly,
628627
}, ctx.FormStrings("files")...)
629628
if err != nil {
630-
ctx.ServerError("GetDiffRangeWithWhitespaceBehavior", err)
629+
ctx.ServerError("GetDiff", err)
631630
return false
632631
}
632+
diffShortStat, err := gitdiff.GetDiffShortStat(ci.HeadGitRepo, beforeCommitID, headCommitID)
633+
if err != nil {
634+
ctx.ServerError("GetDiffShortStat", err)
635+
return false
636+
}
637+
ctx.Data["DiffShortStat"] = diffShortStat
633638
ctx.Data["Diff"] = diff
634-
ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0
639+
ctx.Data["DiffNotAvailable"] = diffShortStat.NumFiles == 0
635640

636641
if !fileOnly {
637642
diffTree, err := gitdiff.GetDiffTree(ctx, ci.HeadGitRepo, false, beforeCommitID, headCommitID)

routers/web/repo/editor.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ func DiffPreviewPost(ctx *context.Context) {
423423
return
424424
}
425425

426-
if diff.NumFiles != 0 {
426+
if len(diff.Files) != 0 {
427427
ctx.Data["File"] = diff.Files[0]
428428
}
429429

routers/web/repo/pull.go

+21-23
Original file line numberDiff line numberDiff line change
@@ -200,22 +200,13 @@ func GetPullDiffStats(ctx *context.Context) {
200200
return
201201
}
202202

203-
diffOptions := &gitdiff.DiffOptions{
204-
BeforeCommitID: mergeBaseCommitID,
205-
AfterCommitID: headCommitID,
206-
MaxLines: setting.Git.MaxGitDiffLines,
207-
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
208-
MaxFiles: setting.Git.MaxGitDiffFiles,
209-
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)),
210-
}
211-
212-
diff, err := gitdiff.GetPullDiffStats(ctx.Repo.GitRepo, diffOptions)
203+
diffShortStat, err := gitdiff.GetDiffShortStat(ctx.Repo.GitRepo, mergeBaseCommitID, headCommitID)
213204
if err != nil {
214-
ctx.ServerError("GetPullDiffStats", err)
205+
ctx.ServerError("GetDiffShortStat", err)
215206
return
216207
}
217208

218-
ctx.Data["Diff"] = diff
209+
ctx.Data["DiffShortStat"] = diffShortStat
219210
}
220211

221212
func GetMergedBaseCommitID(ctx *context.Context, issue *issues_model.Issue) string {
@@ -752,36 +743,43 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi
752743
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
753744
MaxFiles: maxFiles,
754745
WhitespaceBehavior: gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)),
755-
FileOnly: fileOnly,
756746
}
757747

758748
if !willShowSpecifiedCommit {
759749
diffOptions.BeforeCommitID = startCommitID
760750
}
761751

762-
var methodWithError string
763-
var diff *gitdiff.Diff
764-
shouldGetUserSpecificDiff := false
752+
diff, err := gitdiff.GetDiff(ctx, gitRepo, diffOptions, files...)
753+
if err != nil {
754+
ctx.ServerError("GetDiff", err)
755+
return
756+
}
765757

766758
// if we're not logged in or only a single commit (or commit range) is shown we
767759
// have to load only the diff and not get the viewed information
768760
// as the viewed information is designed to be loaded only on latest PR
769761
// diff and if you're signed in.
762+
shouldGetUserSpecificDiff := false
770763
if !ctx.IsSigned || willShowSpecifiedCommit || willShowSpecifiedCommitRange {
771-
diff, err = gitdiff.GetDiff(ctx, gitRepo, diffOptions, files...)
772-
methodWithError = "GetDiff"
764+
// do nothing
773765
} else {
774-
diff, err = gitdiff.SyncAndGetUserSpecificDiff(ctx, ctx.Doer.ID, pull, gitRepo, diffOptions, files...)
775-
methodWithError = "SyncAndGetUserSpecificDiff"
776766
shouldGetUserSpecificDiff = true
767+
err = gitdiff.SyncUserSpecificDiff(ctx, ctx.Doer.ID, pull, gitRepo, diff, diffOptions, files...)
768+
if err != nil {
769+
ctx.ServerError("SyncUserSpecificDiff", err)
770+
return
771+
}
777772
}
773+
774+
diffShortStat, err := gitdiff.GetDiffShortStat(ctx.Repo.GitRepo, startCommitID, endCommitID)
778775
if err != nil {
779-
ctx.ServerError(methodWithError, err)
776+
ctx.ServerError("GetDiffShortStat", err)
780777
return
781778
}
779+
ctx.Data["DiffShortStat"] = diffShortStat
782780

783781
ctx.PageData["prReview"] = map[string]any{
784-
"numberOfFiles": diff.NumFiles,
782+
"numberOfFiles": diffShortStat.NumFiles,
785783
"numberOfViewedFiles": diff.NumViewedFiles,
786784
}
787785

@@ -840,7 +838,7 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi
840838
}
841839

842840
ctx.Data["Diff"] = diff
843-
ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0
841+
ctx.Data["DiffNotAvailable"] = diffShortStat.NumFiles == 0
844842

845843
baseCommit, err := ctx.Repo.GitRepo.GetCommit(startCommitID)
846844
if err != nil {

services/convert/git_commit.go

+4-6
Original file line numberDiff line numberDiff line change
@@ -210,17 +210,15 @@ func ToCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Rep
210210

211211
// Get diff stats for commit
212212
if opts.Stat {
213-
diff, err := gitdiff.GetDiff(ctx, gitRepo, &gitdiff.DiffOptions{
214-
AfterCommitID: commit.ID.String(),
215-
})
213+
diffShortStat, err := gitdiff.GetDiffShortStat(gitRepo, "", commit.ID.String())
216214
if err != nil {
217215
return nil, err
218216
}
219217

220218
res.Stats = &api.CommitStats{
221-
Total: diff.TotalAddition + diff.TotalDeletion,
222-
Additions: diff.TotalAddition,
223-
Deletions: diff.TotalDeletion,
219+
Total: diffShortStat.TotalAddition + diffShortStat.TotalDeletion,
220+
Additions: diffShortStat.TotalAddition,
221+
Deletions: diffShortStat.TotalDeletion,
224222
}
225223
}
226224

services/convert/pull.go

+13-17
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ import (
1717
"code.gitea.io/gitea/modules/git"
1818
"code.gitea.io/gitea/modules/gitrepo"
1919
"code.gitea.io/gitea/modules/log"
20+
"code.gitea.io/gitea/modules/setting"
2021
api "code.gitea.io/gitea/modules/structs"
2122
"code.gitea.io/gitea/modules/util"
23+
"code.gitea.io/gitea/services/gitdiff"
2224
)
2325

2426
// ToAPIPullRequest assumes following fields have been assigned with valid values:
@@ -239,9 +241,13 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
239241
// Calculate diff
240242
startCommitID = pr.MergeBase
241243

242-
apiPullRequest.ChangedFiles, apiPullRequest.Additions, apiPullRequest.Deletions, err = gitRepo.GetDiffShortStat(startCommitID, endCommitID)
244+
diffShortStats, err := gitdiff.GetDiffShortStat(gitRepo, startCommitID, endCommitID)
243245
if err != nil {
244246
log.Error("GetDiffShortStat: %v", err)
247+
} else {
248+
apiPullRequest.ChangedFiles = &diffShortStats.NumFiles
249+
apiPullRequest.Additions = &diffShortStats.TotalAddition
250+
apiPullRequest.Deletions = &diffShortStats.TotalDeletion
245251
}
246252
}
247253

@@ -462,12 +468,6 @@ func ToAPIPullRequests(ctx context.Context, baseRepo *repo_model.Repository, prs
462468
return nil, err
463469
}
464470

465-
// Outer scope variables to be used in diff calculation
466-
var (
467-
startCommitID string
468-
endCommitID string
469-
)
470-
471471
if git.IsErrBranchNotExist(err) {
472472
headCommitID, err := headGitRepo.GetRefCommitID(apiPullRequest.Head.Ref)
473473
if err != nil && !git.IsErrNotExist(err) {
@@ -476,7 +476,6 @@ func ToAPIPullRequests(ctx context.Context, baseRepo *repo_model.Repository, prs
476476
}
477477
if err == nil {
478478
apiPullRequest.Head.Sha = headCommitID
479-
endCommitID = headCommitID
480479
}
481480
} else {
482481
commit, err := headBranch.GetCommit()
@@ -487,17 +486,8 @@ func ToAPIPullRequests(ctx context.Context, baseRepo *repo_model.Repository, prs
487486
if err == nil {
488487
apiPullRequest.Head.Ref = pr.HeadBranch
489488
apiPullRequest.Head.Sha = commit.ID.String()
490-
endCommitID = commit.ID.String()
491489
}
492490
}
493-
494-
// Calculate diff
495-
startCommitID = pr.MergeBase
496-
497-
apiPullRequest.ChangedFiles, apiPullRequest.Additions, apiPullRequest.Deletions, err = gitRepo.GetDiffShortStat(startCommitID, endCommitID)
498-
if err != nil {
499-
log.Error("GetDiffShortStat: %v", err)
500-
}
501491
}
502492

503493
if len(apiPullRequest.Head.Sha) == 0 && len(apiPullRequest.Head.Ref) != 0 {
@@ -518,6 +508,12 @@ func ToAPIPullRequests(ctx context.Context, baseRepo *repo_model.Repository, prs
518508
apiPullRequest.MergedBy = ToUser(ctx, pr.Merger, nil)
519509
}
520510

511+
// Do not provide "ChangeFiles/Additions/Deletions" for the PR list, because the "diff" is quite slow
512+
// If callers are interested in these values, they should do a separate request to get the PR details
513+
if apiPullRequest.ChangedFiles != nil || apiPullRequest.Additions != nil || apiPullRequest.Deletions != nil {
514+
setting.PanicInDevOrTesting("ChangedFiles/Additions/Deletions should not be set in PR list")
515+
}
516+
521517
apiPullRequests = append(apiPullRequests, apiPullRequest)
522518
}
523519

0 commit comments

Comments
 (0)