@@ -695,6 +695,7 @@ const cmdDiffHead = "diff --git "
695
695
696
696
// ParsePatch builds a Diff object from a io.Reader and some parameters.
697
697
func ParsePatch (maxLines , maxLineCharacters , maxFiles int , reader io.Reader , skipToFile string ) (* Diff , error ) {
698
+ log .Debug ("ParsePatch(%d, %d, %d, ..., %s)" , maxLines , maxLineCharacters , maxFiles , skipToFile )
698
699
var curFile * DiffFile
699
700
700
701
skipping := skipToFile != ""
@@ -726,7 +727,7 @@ parsingLoop:
726
727
return diff , fmt .Errorf ("invalid first file line: %s" , line )
727
728
}
728
729
729
- if len (diff .Files ) >= maxFiles {
730
+ if maxFiles > - 1 && len (diff .Files ) >= maxFiles {
730
731
lastFile := createDiffFile (diff , line )
731
732
diff .End = lastFile .Name
732
733
diff .IsIncomplete = true
@@ -1038,7 +1039,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
1038
1039
1039
1040
switch lineBytes [0 ] {
1040
1041
case '@' :
1041
- if curFileLinesCount >= maxLines {
1042
+ if maxLines > - 1 && curFileLinesCount >= maxLines {
1042
1043
curFile .IsIncomplete = true
1043
1044
continue
1044
1045
}
@@ -1075,7 +1076,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
1075
1076
rightLine = lineSectionInfo .RightIdx
1076
1077
continue
1077
1078
case '\\' :
1078
- if curFileLinesCount >= maxLines {
1079
+ if maxLines > - 1 && curFileLinesCount >= maxLines {
1079
1080
curFile .IsIncomplete = true
1080
1081
continue
1081
1082
}
@@ -1090,7 +1091,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
1090
1091
case '+' :
1091
1092
curFileLinesCount ++
1092
1093
curFile .Addition ++
1093
- if curFileLinesCount >= maxLines {
1094
+ if maxLines > - 1 && curFileLinesCount >= maxLines {
1094
1095
curFile .IsIncomplete = true
1095
1096
continue
1096
1097
}
@@ -1114,7 +1115,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
1114
1115
case '-' :
1115
1116
curFileLinesCount ++
1116
1117
curFile .Deletion ++
1117
- if curFileLinesCount >= maxLines {
1118
+ if maxLines > - 1 && curFileLinesCount >= maxLines {
1118
1119
curFile .IsIncomplete = true
1119
1120
continue
1120
1121
}
@@ -1134,7 +1135,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
1134
1135
curSection .Lines = append (curSection .Lines , diffLine )
1135
1136
case ' ' :
1136
1137
curFileLinesCount ++
1137
- if curFileLinesCount >= maxLines {
1138
+ if maxLines > - 1 && curFileLinesCount >= maxLines {
1138
1139
curFile .IsIncomplete = true
1139
1140
continue
1140
1141
}
@@ -1278,13 +1279,25 @@ func readFileName(rd *strings.Reader) (string, bool) {
1278
1279
return name [2 :], ambiguity
1279
1280
}
1280
1281
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.
1282
1295
// Passing the empty string as beforeCommitID returns a diff from the parent commit.
1283
1296
// 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 ) {
1285
1298
repoPath := gitRepo .Path
1286
1299
1287
- commit , err := gitRepo .GetCommit (afterCommitID )
1300
+ commit , err := gitRepo .GetCommit (opts . AfterCommitID )
1288
1301
if err != nil {
1289
1302
return nil , err
1290
1303
}
@@ -1293,45 +1306,54 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
1293
1306
defer cancel ()
1294
1307
1295
1308
argsLength := 6
1296
- if len (whitespaceBehavior ) > 0 {
1309
+ if len (opts . WhitespaceBehavior ) > 0 {
1297
1310
argsLength ++
1298
1311
}
1299
- if len (skipTo ) > 0 {
1312
+ if len (opts . SkipTo ) > 0 {
1300
1313
argsLength ++
1301
1314
}
1315
+ if len (files ) > 0 {
1316
+ argsLength += len (files ) + 1
1317
+ }
1302
1318
1303
1319
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 {
1305
1321
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 )
1308
1324
}
1309
1325
// append empty tree ref
1310
1326
diffArgs = append (diffArgs , "4b825dc642cb6eb9a060e54bf8d69288fbee4904" )
1311
- diffArgs = append (diffArgs , afterCommitID )
1327
+ diffArgs = append (diffArgs , opts . AfterCommitID )
1312
1328
} else {
1313
- actualBeforeCommitID := beforeCommitID
1329
+ actualBeforeCommitID := opts . BeforeCommitID
1314
1330
if len (actualBeforeCommitID ) == 0 {
1315
1331
parentCommit , _ := commit .Parent (0 )
1316
1332
actualBeforeCommitID = parentCommit .ID .String ()
1317
1333
}
1318
1334
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 )
1321
1337
}
1322
1338
diffArgs = append (diffArgs , actualBeforeCommitID )
1323
- diffArgs = append (diffArgs , afterCommitID )
1324
- beforeCommitID = actualBeforeCommitID
1339
+ diffArgs = append (diffArgs , opts . AfterCommitID )
1340
+ opts . BeforeCommitID = actualBeforeCommitID
1325
1341
}
1326
1342
1327
1343
// In git 2.31, git diff learned --skip-to which we can use to shortcut skip to file
1328
1344
// so if we are using at least this version of git we don't have to tell ParsePatch to do
1329
1345
// 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 )
1333
1349
parsePatchSkipToFile = ""
1334
1350
}
1351
+
1352
+ if len (files ) > 0 {
1353
+ diffArgs = append (diffArgs , "--" )
1354
+ diffArgs = append (diffArgs , files ... )
1355
+ }
1356
+
1335
1357
cmd := exec .CommandContext (ctx , git .GitExecutable , diffArgs ... )
1336
1358
1337
1359
cmd .Dir = repoPath
@@ -1349,16 +1371,16 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
1349
1371
pid := process .GetManager ().Add (fmt .Sprintf ("GetDiffRange [repo_path: %s]" , repoPath ), cancel )
1350
1372
defer process .GetManager ().Remove (pid )
1351
1373
1352
- diff , err := ParsePatch (maxLines , maxLineCharacters , maxFiles , stdout , parsePatchSkipToFile )
1374
+ diff , err := ParsePatch (opts . MaxLines , opts . MaxLineCharacters , opts . MaxFiles , stdout , parsePatchSkipToFile )
1353
1375
if err != nil {
1354
1376
return nil , fmt .Errorf ("unable to ParsePatch: %w" , err )
1355
1377
}
1356
- diff .Start = skipTo
1378
+ diff .Start = opts . SkipTo
1357
1379
1358
1380
var checker * git.CheckAttributeReader
1359
1381
1360
1382
if git .CheckGitVersionAtLeast ("1.7.8" ) == nil {
1361
- indexFilename , worktree , deleteTemporaryFile , err := gitRepo .ReadTreeToTemporaryIndex (afterCommitID )
1383
+ indexFilename , worktree , deleteTemporaryFile , err := gitRepo .ReadTreeToTemporaryIndex (opts . AfterCommitID )
1362
1384
if err == nil {
1363
1385
defer deleteTemporaryFile ()
1364
1386
@@ -1370,12 +1392,12 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
1370
1392
}
1371
1393
ctx , cancel := context .WithCancel (git .DefaultContext )
1372
1394
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 )
1374
1396
} else {
1375
1397
go func () {
1376
1398
err := checker .Run ()
1377
1399
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 )
1379
1401
}
1380
1402
cancel ()
1381
1403
}()
@@ -1426,7 +1448,7 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
1426
1448
diffFile .IsGenerated = analyze .IsGenerated (diffFile .Name )
1427
1449
}
1428
1450
1429
- tailSection := diffFile .GetTailSection (gitRepo , beforeCommitID , afterCommitID )
1451
+ tailSection := diffFile .GetTailSection (gitRepo , opts . BeforeCommitID , opts . AfterCommitID )
1430
1452
if tailSection != nil {
1431
1453
diffFile .Sections = append (diffFile .Sections , tailSection )
1432
1454
}
@@ -1437,19 +1459,19 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
1437
1459
}
1438
1460
1439
1461
separator := "..."
1440
- if directComparison {
1462
+ if opts . DirectComparison {
1441
1463
separator = ".."
1442
1464
}
1443
1465
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 }
1447
1469
}
1448
1470
diff .NumFiles , diff .TotalAddition , diff .TotalDeletion , err = git .GetDiffShortStat (repoPath , shortstatArgs ... )
1449
1471
if err != nil && strings .Contains (err .Error (), "no merge base" ) {
1450
1472
// git >= 2.28 now returns an error if base and head have become unrelated.
1451
1473
// 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 }
1453
1475
diff .NumFiles , diff .TotalAddition , diff .TotalDeletion , err = git .GetDiffShortStat (repoPath , shortstatArgs ... )
1454
1476
}
1455
1477
if err != nil {
@@ -1459,12 +1481,6 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
1459
1481
return diff , nil
1460
1482
}
1461
1483
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
-
1468
1484
// CommentAsDiff returns c.Patch as *Diff
1469
1485
func CommentAsDiff (c * models.Comment ) (* Diff , error ) {
1470
1486
diff , err := ParsePatch (setting .Git .MaxGitDiffLines ,
0 commit comments