@@ -695,6 +695,7 @@ const cmdDiffHead = "diff --git "
695695
696696// ParsePatch builds a Diff object from a io.Reader and some parameters.
697697func ParsePatch (maxLines , maxLineCharacters , maxFiles int , reader io.Reader , skipToFile string ) (* Diff , error ) {
698+ log .Debug ("ParsePatch(%d, %d, %d, ..., %s)" , maxLines , maxLineCharacters , maxFiles , skipToFile )
698699 var curFile * DiffFile
699700
700701 skipping := skipToFile != ""
@@ -726,7 +727,7 @@ parsingLoop:
726727 return diff , fmt .Errorf ("invalid first file line: %s" , line )
727728 }
728729
729- if len (diff .Files ) >= maxFiles {
730+ if maxFiles > - 1 && len (diff .Files ) >= maxFiles {
730731 lastFile := createDiffFile (diff , line )
731732 diff .End = lastFile .Name
732733 diff .IsIncomplete = true
@@ -1038,7 +1039,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
10381039
10391040 switch lineBytes [0 ] {
10401041 case '@' :
1041- if curFileLinesCount >= maxLines {
1042+ if maxLines > - 1 && curFileLinesCount >= maxLines {
10421043 curFile .IsIncomplete = true
10431044 continue
10441045 }
@@ -1075,7 +1076,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
10751076 rightLine = lineSectionInfo .RightIdx
10761077 continue
10771078 case '\\' :
1078- if curFileLinesCount >= maxLines {
1079+ if maxLines > - 1 && curFileLinesCount >= maxLines {
10791080 curFile .IsIncomplete = true
10801081 continue
10811082 }
@@ -1090,7 +1091,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
10901091 case '+' :
10911092 curFileLinesCount ++
10921093 curFile .Addition ++
1093- if curFileLinesCount >= maxLines {
1094+ if maxLines > - 1 && curFileLinesCount >= maxLines {
10941095 curFile .IsIncomplete = true
10951096 continue
10961097 }
@@ -1114,7 +1115,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
11141115 case '-' :
11151116 curFileLinesCount ++
11161117 curFile .Deletion ++
1117- if curFileLinesCount >= maxLines {
1118+ if maxLines > - 1 && curFileLinesCount >= maxLines {
11181119 curFile .IsIncomplete = true
11191120 continue
11201121 }
@@ -1134,7 +1135,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
11341135 curSection .Lines = append (curSection .Lines , diffLine )
11351136 case ' ' :
11361137 curFileLinesCount ++
1137- if curFileLinesCount >= maxLines {
1138+ if maxLines > - 1 && curFileLinesCount >= maxLines {
11381139 curFile .IsIncomplete = true
11391140 continue
11401141 }
@@ -1278,13 +1279,25 @@ func readFileName(rd *strings.Reader) (string, bool) {
12781279 return name [2 :], ambiguity
12791280}
12801281
1281- // GetDiffRangeWithWhitespaceBehavior builds a Diff between two commits of a repository.
1282+ // DiffOptions represents the options for a DiffRange
1283+ type DiffOptions struct {
1284+ BeforeCommitID string
1285+ AfterCommitID string
1286+ SkipTo string
1287+ MaxLines int
1288+ MaxLineCharacters int
1289+ MaxFiles int
1290+ WhitespaceBehavior string
1291+ DirectComparison bool
1292+ }
1293+
1294+ // GetDiff builds a Diff between two commits of a repository.
12821295// Passing the empty string as beforeCommitID returns a diff from the parent commit.
12831296// The whitespaceBehavior is either an empty string or a git flag
1284- func GetDiffRangeWithWhitespaceBehavior (gitRepo * git.Repository , beforeCommitID , afterCommitID , skipTo string , maxLines , maxLineCharacters , maxFiles int , whitespaceBehavior string , directComparison bool ) (* Diff , error ) {
1297+ func GetDiff (gitRepo * git.Repository , opts * DiffOptions , files ... string ) (* Diff , error ) {
12851298 repoPath := gitRepo .Path
12861299
1287- commit , err := gitRepo .GetCommit (afterCommitID )
1300+ commit , err := gitRepo .GetCommit (opts . AfterCommitID )
12881301 if err != nil {
12891302 return nil , err
12901303 }
@@ -1293,45 +1306,54 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
12931306 defer cancel ()
12941307
12951308 argsLength := 6
1296- if len (whitespaceBehavior ) > 0 {
1309+ if len (opts . WhitespaceBehavior ) > 0 {
12971310 argsLength ++
12981311 }
1299- if len (skipTo ) > 0 {
1312+ if len (opts . SkipTo ) > 0 {
13001313 argsLength ++
13011314 }
1315+ if len (files ) > 0 {
1316+ argsLength += len (files ) + 1
1317+ }
13021318
13031319 diffArgs := make ([]string , 0 , argsLength )
1304- if (len (beforeCommitID ) == 0 || beforeCommitID == git .EmptySHA ) && commit .ParentCount () == 0 {
1320+ if (len (opts . BeforeCommitID ) == 0 || opts . BeforeCommitID == git .EmptySHA ) && commit .ParentCount () == 0 {
13051321 diffArgs = append (diffArgs , "diff" , "--src-prefix=\\ a/" , "--dst-prefix=\\ b/" , "-M" )
1306- if len (whitespaceBehavior ) != 0 {
1307- diffArgs = append (diffArgs , whitespaceBehavior )
1322+ if len (opts . WhitespaceBehavior ) != 0 {
1323+ diffArgs = append (diffArgs , opts . WhitespaceBehavior )
13081324 }
13091325 // append empty tree ref
13101326 diffArgs = append (diffArgs , "4b825dc642cb6eb9a060e54bf8d69288fbee4904" )
1311- diffArgs = append (diffArgs , afterCommitID )
1327+ diffArgs = append (diffArgs , opts . AfterCommitID )
13121328 } else {
1313- actualBeforeCommitID := beforeCommitID
1329+ actualBeforeCommitID := opts . BeforeCommitID
13141330 if len (actualBeforeCommitID ) == 0 {
13151331 parentCommit , _ := commit .Parent (0 )
13161332 actualBeforeCommitID = parentCommit .ID .String ()
13171333 }
13181334 diffArgs = append (diffArgs , "diff" , "--src-prefix=\\ a/" , "--dst-prefix=\\ b/" , "-M" )
1319- if len (whitespaceBehavior ) != 0 {
1320- diffArgs = append (diffArgs , whitespaceBehavior )
1335+ if len (opts . WhitespaceBehavior ) != 0 {
1336+ diffArgs = append (diffArgs , opts . WhitespaceBehavior )
13211337 }
13221338 diffArgs = append (diffArgs , actualBeforeCommitID )
1323- diffArgs = append (diffArgs , afterCommitID )
1324- beforeCommitID = actualBeforeCommitID
1339+ diffArgs = append (diffArgs , opts . AfterCommitID )
1340+ opts . BeforeCommitID = actualBeforeCommitID
13251341 }
13261342
13271343 // In git 2.31, git diff learned --skip-to which we can use to shortcut skip to file
13281344 // so if we are using at least this version of git we don't have to tell ParsePatch to do
13291345 // the skipping for us
1330- parsePatchSkipToFile := skipTo
1331- if skipTo != "" && git .CheckGitVersionAtLeast ("2.31" ) == nil {
1332- diffArgs = append (diffArgs , "--skip-to=" + skipTo )
1346+ parsePatchSkipToFile := opts . SkipTo
1347+ if opts . SkipTo != "" && git .CheckGitVersionAtLeast ("2.31" ) == nil {
1348+ diffArgs = append (diffArgs , "--skip-to=" + opts . SkipTo )
13331349 parsePatchSkipToFile = ""
13341350 }
1351+
1352+ if len (files ) > 0 {
1353+ diffArgs = append (diffArgs , "--" )
1354+ diffArgs = append (diffArgs , files ... )
1355+ }
1356+
13351357 cmd := exec .CommandContext (ctx , git .GitExecutable , diffArgs ... )
13361358
13371359 cmd .Dir = repoPath
@@ -1349,16 +1371,16 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
13491371 pid := process .GetManager ().Add (fmt .Sprintf ("GetDiffRange [repo_path: %s]" , repoPath ), cancel )
13501372 defer process .GetManager ().Remove (pid )
13511373
1352- diff , err := ParsePatch (maxLines , maxLineCharacters , maxFiles , stdout , parsePatchSkipToFile )
1374+ diff , err := ParsePatch (opts . MaxLines , opts . MaxLineCharacters , opts . MaxFiles , stdout , parsePatchSkipToFile )
13531375 if err != nil {
13541376 return nil , fmt .Errorf ("unable to ParsePatch: %w" , err )
13551377 }
1356- diff .Start = skipTo
1378+ diff .Start = opts . SkipTo
13571379
13581380 var checker * git.CheckAttributeReader
13591381
13601382 if git .CheckGitVersionAtLeast ("1.7.8" ) == nil {
1361- indexFilename , worktree , deleteTemporaryFile , err := gitRepo .ReadTreeToTemporaryIndex (afterCommitID )
1383+ indexFilename , worktree , deleteTemporaryFile , err := gitRepo .ReadTreeToTemporaryIndex (opts . AfterCommitID )
13621384 if err == nil {
13631385 defer deleteTemporaryFile ()
13641386
@@ -1370,12 +1392,12 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
13701392 }
13711393 ctx , cancel := context .WithCancel (git .DefaultContext )
13721394 if err := checker .Init (ctx ); err != nil {
1373- log .Error ("Unable to open checker for %s. Error: %v" , afterCommitID , err )
1395+ log .Error ("Unable to open checker for %s. Error: %v" , opts . AfterCommitID , err )
13741396 } else {
13751397 go func () {
13761398 err := checker .Run ()
13771399 if err != nil && err != ctx .Err () {
1378- log .Error ("Unable to open checker for %s. Error: %v" , afterCommitID , err )
1400+ log .Error ("Unable to open checker for %s. Error: %v" , opts . AfterCommitID , err )
13791401 }
13801402 cancel ()
13811403 }()
@@ -1426,7 +1448,7 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
14261448 diffFile .IsGenerated = analyze .IsGenerated (diffFile .Name )
14271449 }
14281450
1429- tailSection := diffFile .GetTailSection (gitRepo , beforeCommitID , afterCommitID )
1451+ tailSection := diffFile .GetTailSection (gitRepo , opts . BeforeCommitID , opts . AfterCommitID )
14301452 if tailSection != nil {
14311453 diffFile .Sections = append (diffFile .Sections , tailSection )
14321454 }
@@ -1437,19 +1459,19 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
14371459 }
14381460
14391461 separator := "..."
1440- if directComparison {
1462+ if opts . DirectComparison {
14411463 separator = ".."
14421464 }
14431465
1444- shortstatArgs := []string {beforeCommitID + separator + afterCommitID }
1445- if len (beforeCommitID ) == 0 || beforeCommitID == git .EmptySHA {
1446- shortstatArgs = []string {git .EmptyTreeSHA , afterCommitID }
1466+ shortstatArgs := []string {opts . BeforeCommitID + separator + opts . AfterCommitID }
1467+ if len (opts . BeforeCommitID ) == 0 || opts . BeforeCommitID == git .EmptySHA {
1468+ shortstatArgs = []string {git .EmptyTreeSHA , opts . AfterCommitID }
14471469 }
14481470 diff .NumFiles , diff .TotalAddition , diff .TotalDeletion , err = git .GetDiffShortStat (repoPath , shortstatArgs ... )
14491471 if err != nil && strings .Contains (err .Error (), "no merge base" ) {
14501472 // git >= 2.28 now returns an error if base and head have become unrelated.
14511473 // previously it would return the results of git diff --shortstat base head so let's try that...
1452- shortstatArgs = []string {beforeCommitID , afterCommitID }
1474+ shortstatArgs = []string {opts . BeforeCommitID , opts . AfterCommitID }
14531475 diff .NumFiles , diff .TotalAddition , diff .TotalDeletion , err = git .GetDiffShortStat (repoPath , shortstatArgs ... )
14541476 }
14551477 if err != nil {
@@ -1459,12 +1481,6 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
14591481 return diff , nil
14601482}
14611483
1462- // GetDiffCommitWithWhitespaceBehavior builds a Diff representing the given commitID.
1463- // The whitespaceBehavior is either an empty string or a git flag
1464- func GetDiffCommitWithWhitespaceBehavior (gitRepo * git.Repository , commitID , skipTo string , maxLines , maxLineCharacters , maxFiles int , whitespaceBehavior string , directComparison bool ) (* Diff , error ) {
1465- return GetDiffRangeWithWhitespaceBehavior (gitRepo , "" , commitID , skipTo , maxLines , maxLineCharacters , maxFiles , whitespaceBehavior , directComparison )
1466- }
1467-
14681484// CommentAsDiff returns c.Patch as *Diff
14691485func CommentAsDiff (c * models.Comment ) (* Diff , error ) {
14701486 diff , err := ParsePatch (setting .Git .MaxGitDiffLines ,
0 commit comments