@@ -380,18 +380,11 @@ func (diffFile *DiffFile) GetType() int {
380380}
381381
382382// GetTailSection creates a fake DiffLineSection if the last section is not the end of the file
383- func (diffFile * DiffFile ) GetTailSection (gitRepo * git.Repository , leftCommitID , rightCommitID string ) * DiffSection {
383+ func (diffFile * DiffFile ) GetTailSection (gitRepo * git.Repository , leftCommit , rightCommit * git. Commit ) * DiffSection {
384384 if len (diffFile .Sections ) == 0 || diffFile .Type != DiffFileChange || diffFile .IsBin || diffFile .IsLFSFile {
385385 return nil
386386 }
387- leftCommit , err := gitRepo .GetCommit (leftCommitID )
388- if err != nil {
389- return nil
390- }
391- rightCommit , err := gitRepo .GetCommit (rightCommitID )
392- if err != nil {
393- return nil
394- }
387+
395388 lastSection := diffFile .Sections [len (diffFile .Sections )- 1 ]
396389 lastLine := lastSection .Lines [len (lastSection .Lines )- 1 ]
397390 leftLineCount := getCommitFileLineCount (leftCommit , diffFile .Name )
@@ -494,7 +487,7 @@ func (diff *Diff) LoadComments(ctx context.Context, issue *issues_model.Issue, c
494487const cmdDiffHead = "diff --git "
495488
496489// ParsePatch builds a Diff object from a io.Reader and some parameters.
497- func ParsePatch (ctx context.Context , maxLines , maxLineCharacters , maxFiles int , reader io.Reader , skipToFile string ) (* Diff , error ) {
490+ func ParsePatch (ctx context.Context , maxLines , maxLineCharacters , maxFiles int , reader io.Reader , skipToFile string , cancel context. CancelFunc ) (* Diff , error ) {
498491 log .Debug ("ParsePatch(%d, %d, %d, ..., %s)" , maxLines , maxLineCharacters , maxFiles , skipToFile )
499492 var curFile * DiffFile
500493
@@ -536,6 +529,11 @@ parsingLoop:
536529 lastFile := createDiffFile (diff , line )
537530 diff .End = lastFile .Name
538531 diff .IsIncomplete = true
532+
533+ // signal that we are exiting this diff early
534+ if cancel != nil {
535+ cancel ()
536+ }
539537 _ , err := io .Copy (io .Discard , reader )
540538 if err != nil {
541539 // By the definition of io.Copy this never returns io.EOF
@@ -1094,13 +1092,16 @@ func readFileName(rd *strings.Reader) (string, bool) {
10941092// DiffOptions represents the options for a DiffRange
10951093type DiffOptions struct {
10961094 BeforeCommitID string
1095+ BeforeCommit * git.Commit
10971096 AfterCommitID string
1097+ AfterCommit * git.Commit
10981098 SkipTo string
10991099 MaxLines int
11001100 MaxLineCharacters int
11011101 MaxFiles int
11021102 WhitespaceBehavior git.TrustedCmdArgs
11031103 DirectComparison bool
1104+ FileOnly bool
11041105}
11051106
11061107// GetDiff builds a Diff between two commits of a repository.
@@ -1109,12 +1110,19 @@ type DiffOptions struct {
11091110func GetDiff (ctx context.Context , gitRepo * git.Repository , opts * DiffOptions , files ... string ) (* Diff , error ) {
11101111 repoPath := gitRepo .Path
11111112
1112- commit , err := gitRepo .GetCommit (opts .AfterCommitID )
1113- if err != nil {
1114- return nil , err
1113+ commit := opts .AfterCommit
1114+ if commit == nil {
1115+ var err error
1116+ commit , err = gitRepo .GetCommit (opts .AfterCommitID )
1117+ if err != nil {
1118+ return nil , err
1119+ }
11151120 }
11161121
1117- cmdDiff := git .NewCommand (gitRepo .Ctx )
1122+ ctx , cancel := context .WithCancel (ctx )
1123+ defer cancel ()
1124+
1125+ cmdDiff := git .NewCommand (ctx )
11181126 objectFormat , err := gitRepo .GetObjectFormat ()
11191127 if err != nil {
11201128 return nil , err
@@ -1136,6 +1144,14 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi
11361144 AddArguments (opts .WhitespaceBehavior ... ).
11371145 AddDynamicArguments (actualBeforeCommitID , opts .AfterCommitID )
11381146 opts .BeforeCommitID = actualBeforeCommitID
1147+
1148+ if opts .BeforeCommit == nil {
1149+ var err error
1150+ opts .BeforeCommit , err = gitRepo .GetCommit (opts .BeforeCommitID )
1151+ if err != nil {
1152+ return nil , err
1153+ }
1154+ }
11391155 }
11401156
11411157 // In git 2.31, git diff learned --skip-to which we can use to shortcut skip to file
@@ -1163,14 +1179,14 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi
11631179 Dir : repoPath ,
11641180 Stdout : writer ,
11651181 Stderr : stderr ,
1166- }); err != nil {
1182+ }); err != nil && err . Error () != "signal: killed" {
11671183 log .Error ("error during GetDiff(git diff dir: %s): %v, stderr: %s" , repoPath , err , stderr .String ())
11681184 }
11691185
11701186 _ = writer .Close ()
11711187 }()
11721188
1173- diff , err := ParsePatch (ctx , opts .MaxLines , opts .MaxLineCharacters , opts .MaxFiles , reader , parsePatchSkipToFile )
1189+ diff , err := ParsePatch (ctx , opts .MaxLines , opts .MaxLineCharacters , opts .MaxFiles , reader , parsePatchSkipToFile , cancel )
11741190 if err != nil {
11751191 return nil , fmt .Errorf ("unable to ParsePatch: %w" , err )
11761192 }
@@ -1205,37 +1221,28 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi
12051221 }
12061222 diffFile .IsGenerated = isGenerated .Value ()
12071223
1208- tailSection := diffFile .GetTailSection (gitRepo , opts .BeforeCommitID , opts . AfterCommitID )
1224+ tailSection := diffFile .GetTailSection (gitRepo , opts .BeforeCommit , commit )
12091225 if tailSection != nil {
12101226 diffFile .Sections = append (diffFile .Sections , tailSection )
12111227 }
12121228 }
12131229
1214- separator := "..."
1215- if opts .DirectComparison {
1216- separator = ".."
1230+ if opts .FileOnly {
1231+ return diff , nil
12171232 }
12181233
1219- diffPaths := []string {opts .BeforeCommitID + separator + opts .AfterCommitID }
1220- if len (opts .BeforeCommitID ) == 0 || opts .BeforeCommitID == objectFormat .EmptyObjectID ().String () {
1221- diffPaths = []string {objectFormat .EmptyTree ().String (), opts .AfterCommitID }
1222- }
1223- diff .NumFiles , diff .TotalAddition , diff .TotalDeletion , err = git .GetDiffShortStat (gitRepo .Ctx , repoPath , nil , diffPaths ... )
1224- if err != nil && strings .Contains (err .Error (), "no merge base" ) {
1225- // git >= 2.28 now returns an error if base and head have become unrelated.
1226- // previously it would return the results of git diff --shortstat base head so let's try that...
1227- diffPaths = []string {opts .BeforeCommitID , opts .AfterCommitID }
1228- diff .NumFiles , diff .TotalAddition , diff .TotalDeletion , err = git .GetDiffShortStat (gitRepo .Ctx , repoPath , nil , diffPaths ... )
1229- }
1234+ stats , err := GetPullDiffStats (gitRepo , opts )
12301235 if err != nil {
12311236 return nil , err
12321237 }
12331238
1239+ diff .NumFiles , diff .TotalAddition , diff .TotalDeletion = stats .NumFiles , stats .TotalAddition , stats .TotalDeletion
1240+
12341241 return diff , nil
12351242}
12361243
12371244type PullDiffStats struct {
1238- TotalAddition , TotalDeletion int
1245+ NumFiles , TotalAddition , TotalDeletion int
12391246}
12401247
12411248// GetPullDiffStats
@@ -1259,12 +1266,12 @@ func GetPullDiffStats(gitRepo *git.Repository, opts *DiffOptions) (*PullDiffStat
12591266 diffPaths = []string {objectFormat .EmptyTree ().String (), opts .AfterCommitID }
12601267 }
12611268
1262- _ , diff .TotalAddition , diff .TotalDeletion , err = git .GetDiffShortStat (gitRepo .Ctx , repoPath , nil , diffPaths ... )
1269+ diff . NumFiles , diff .TotalAddition , diff .TotalDeletion , err = git .GetDiffShortStat (gitRepo .Ctx , repoPath , nil , diffPaths ... )
12631270 if err != nil && strings .Contains (err .Error (), "no merge base" ) {
12641271 // git >= 2.28 now returns an error if base and head have become unrelated.
12651272 // previously it would return the results of git diff --shortstat base head so let's try that...
12661273 diffPaths = []string {opts .BeforeCommitID , opts .AfterCommitID }
1267- _ , diff .TotalAddition , diff .TotalDeletion , err = git .GetDiffShortStat (gitRepo .Ctx , repoPath , nil , diffPaths ... )
1274+ diff . NumFiles , diff .TotalAddition , diff .TotalDeletion , err = git .GetDiffShortStat (gitRepo .Ctx , repoPath , nil , diffPaths ... )
12681275 }
12691276 if err != nil {
12701277 return nil , err
@@ -1345,7 +1352,7 @@ outer:
13451352// CommentAsDiff returns c.Patch as *Diff
13461353func CommentAsDiff (ctx context.Context , c * issues_model.Comment ) (* Diff , error ) {
13471354 diff , err := ParsePatch (ctx , setting .Git .MaxGitDiffLines ,
1348- setting .Git .MaxGitDiffLineCharacters , setting .Git .MaxGitDiffFiles , strings .NewReader (c .Patch ), "" )
1355+ setting .Git .MaxGitDiffLineCharacters , setting .Git .MaxGitDiffFiles , strings .NewReader (c .Patch ), "" , nil )
13491356 if err != nil {
13501357 log .Error ("Unable to parse patch: %v" , err )
13511358 return nil , err
0 commit comments