@@ -380,18 +380,11 @@ func (diffFile *DiffFile) GetType() int {
380
380
}
381
381
382
382
// 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 {
384
384
if len (diffFile .Sections ) == 0 || diffFile .Type != DiffFileChange || diffFile .IsBin || diffFile .IsLFSFile {
385
385
return nil
386
386
}
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
+
395
388
lastSection := diffFile .Sections [len (diffFile .Sections )- 1 ]
396
389
lastLine := lastSection .Lines [len (lastSection .Lines )- 1 ]
397
390
leftLineCount := getCommitFileLineCount (leftCommit , diffFile .Name )
@@ -536,11 +529,6 @@ parsingLoop:
536
529
lastFile := createDiffFile (diff , line )
537
530
diff .End = lastFile .Name
538
531
diff .IsIncomplete = true
539
- _ , err := io .Copy (io .Discard , reader )
540
- if err != nil {
541
- // By the definition of io.Copy this never returns io.EOF
542
- return diff , fmt .Errorf ("error during io.Copy: %w" , err )
543
- }
544
532
break parsingLoop
545
533
}
546
534
@@ -1101,6 +1089,7 @@ type DiffOptions struct {
1101
1089
MaxFiles int
1102
1090
WhitespaceBehavior git.TrustedCmdArgs
1103
1091
DirectComparison bool
1092
+ FileOnly bool
1104
1093
}
1105
1094
1106
1095
// GetDiff builds a Diff between two commits of a repository.
@@ -1109,12 +1098,16 @@ type DiffOptions struct {
1109
1098
func GetDiff (ctx context.Context , gitRepo * git.Repository , opts * DiffOptions , files ... string ) (* Diff , error ) {
1110
1099
repoPath := gitRepo .Path
1111
1100
1101
+ var beforeCommit * git.Commit
1112
1102
commit , err := gitRepo .GetCommit (opts .AfterCommitID )
1113
1103
if err != nil {
1114
1104
return nil , err
1115
1105
}
1116
1106
1117
- cmdDiff := git .NewCommand (gitRepo .Ctx )
1107
+ cmdCtx , cmdCancel := context .WithCancel (ctx )
1108
+ defer cmdCancel ()
1109
+
1110
+ cmdDiff := git .NewCommand (cmdCtx )
1118
1111
objectFormat , err := gitRepo .GetObjectFormat ()
1119
1112
if err != nil {
1120
1113
return nil , err
@@ -1136,6 +1129,12 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi
1136
1129
AddArguments (opts .WhitespaceBehavior ... ).
1137
1130
AddDynamicArguments (actualBeforeCommitID , opts .AfterCommitID )
1138
1131
opts .BeforeCommitID = actualBeforeCommitID
1132
+
1133
+ var err error
1134
+ beforeCommit , err = gitRepo .GetCommit (opts .BeforeCommitID )
1135
+ if err != nil {
1136
+ return nil , err
1137
+ }
1139
1138
}
1140
1139
1141
1140
// In git 2.31, git diff learned --skip-to which we can use to shortcut skip to file
@@ -1163,14 +1162,16 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi
1163
1162
Dir : repoPath ,
1164
1163
Stdout : writer ,
1165
1164
Stderr : stderr ,
1166
- }); err != nil {
1165
+ }); err != nil && err . Error () != "signal: killed" {
1167
1166
log .Error ("error during GetDiff(git diff dir: %s): %v, stderr: %s" , repoPath , err , stderr .String ())
1168
1167
}
1169
1168
1170
1169
_ = writer .Close ()
1171
1170
}()
1172
1171
1173
- diff , err := ParsePatch (ctx , opts .MaxLines , opts .MaxLineCharacters , opts .MaxFiles , reader , parsePatchSkipToFile )
1172
+ diff , err := ParsePatch (cmdCtx , opts .MaxLines , opts .MaxLineCharacters , opts .MaxFiles , reader , parsePatchSkipToFile )
1173
+ // Ensure the git process is killed if it didn't exit already
1174
+ cmdCancel ()
1174
1175
if err != nil {
1175
1176
return nil , fmt .Errorf ("unable to ParsePatch: %w" , err )
1176
1177
}
@@ -1205,37 +1206,28 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi
1205
1206
}
1206
1207
diffFile .IsGenerated = isGenerated .Value ()
1207
1208
1208
- tailSection := diffFile .GetTailSection (gitRepo , opts . BeforeCommitID , opts . AfterCommitID )
1209
+ tailSection := diffFile .GetTailSection (gitRepo , beforeCommit , commit )
1209
1210
if tailSection != nil {
1210
1211
diffFile .Sections = append (diffFile .Sections , tailSection )
1211
1212
}
1212
1213
}
1213
1214
1214
- separator := "..."
1215
- if opts .DirectComparison {
1216
- separator = ".."
1215
+ if opts .FileOnly {
1216
+ return diff , nil
1217
1217
}
1218
1218
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
- }
1219
+ stats , err := GetPullDiffStats (gitRepo , opts )
1230
1220
if err != nil {
1231
1221
return nil , err
1232
1222
}
1233
1223
1224
+ diff .NumFiles , diff .TotalAddition , diff .TotalDeletion = stats .NumFiles , stats .TotalAddition , stats .TotalDeletion
1225
+
1234
1226
return diff , nil
1235
1227
}
1236
1228
1237
1229
type PullDiffStats struct {
1238
- TotalAddition , TotalDeletion int
1230
+ NumFiles , TotalAddition , TotalDeletion int
1239
1231
}
1240
1232
1241
1233
// GetPullDiffStats
@@ -1259,12 +1251,12 @@ func GetPullDiffStats(gitRepo *git.Repository, opts *DiffOptions) (*PullDiffStat
1259
1251
diffPaths = []string {objectFormat .EmptyTree ().String (), opts .AfterCommitID }
1260
1252
}
1261
1253
1262
- _ , diff .TotalAddition , diff .TotalDeletion , err = git .GetDiffShortStat (gitRepo .Ctx , repoPath , nil , diffPaths ... )
1254
+ diff . NumFiles , diff .TotalAddition , diff .TotalDeletion , err = git .GetDiffShortStat (gitRepo .Ctx , repoPath , nil , diffPaths ... )
1263
1255
if err != nil && strings .Contains (err .Error (), "no merge base" ) {
1264
1256
// git >= 2.28 now returns an error if base and head have become unrelated.
1265
1257
// previously it would return the results of git diff --shortstat base head so let's try that...
1266
1258
diffPaths = []string {opts .BeforeCommitID , opts .AfterCommitID }
1267
- _ , diff .TotalAddition , diff .TotalDeletion , err = git .GetDiffShortStat (gitRepo .Ctx , repoPath , nil , diffPaths ... )
1259
+ diff . NumFiles , diff .TotalAddition , diff .TotalDeletion , err = git .GetDiffShortStat (gitRepo .Ctx , repoPath , nil , diffPaths ... )
1268
1260
}
1269
1261
if err != nil {
1270
1262
return nil , err
0 commit comments