@@ -128,7 +128,7 @@ func (e *errMergeConflict) Error() string {
128
128
return fmt .Sprintf ("conflict detected at: %s" , e .filename )
129
129
}
130
130
131
- func attemptMerge (ctx context.Context , file * unmergedFile , tmpBasePath string , gitRepo * git.Repository ) error {
131
+ func attemptMerge (ctx context.Context , file * unmergedFile , tmpBasePath string , filesToRemove * [] string , filesToAdd * [] git.IndexObjectInfo ) error {
132
132
log .Trace ("Attempt to merge:\n %v" , file )
133
133
134
134
switch {
@@ -142,14 +142,13 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, g
142
142
}
143
143
144
144
// Not a genuine conflict and we can simply remove the file from the index
145
- return gitRepo .RemoveFilesFromIndex (file .stage1 .path )
145
+ * filesToRemove = append (* filesToRemove , file .stage1 .path )
146
+ return nil
146
147
case file .stage1 == nil && file .stage2 != nil && (file .stage3 == nil || file .stage2 .SameAs (file .stage3 )):
147
148
// 2. Added in ours but not in theirs or identical in both
148
149
//
149
150
// Not a genuine conflict just add to the index
150
- if err := gitRepo .AddObjectToIndex (file .stage2 .mode , git .MustIDFromString (file .stage2 .sha ), file .stage2 .path ); err != nil {
151
- return err
152
- }
151
+ * filesToAdd = append (* filesToAdd , git.IndexObjectInfo {Mode : file .stage2 .mode , Object : git .MustIDFromString (file .stage2 .sha ), Filename : file .stage2 .path })
153
152
return nil
154
153
case file .stage1 == nil && file .stage2 != nil && file .stage3 != nil && file .stage2 .sha == file .stage3 .sha && file .stage2 .mode != file .stage3 .mode :
155
154
// 3. Added in both with the same sha but the modes are different
@@ -160,7 +159,8 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, g
160
159
// 4. Added in theirs but not ours:
161
160
//
162
161
// Not a genuine conflict just add to the index
163
- return gitRepo .AddObjectToIndex (file .stage3 .mode , git .MustIDFromString (file .stage3 .sha ), file .stage3 .path )
162
+ * filesToAdd = append (* filesToAdd , git.IndexObjectInfo {Mode : file .stage3 .mode , Object : git .MustIDFromString (file .stage3 .sha ), Filename : file .stage3 .path })
163
+ return nil
164
164
case file .stage1 == nil :
165
165
// 5. Created by new in both
166
166
//
@@ -221,7 +221,8 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, g
221
221
return err
222
222
}
223
223
hash = strings .TrimSpace (hash )
224
- return gitRepo .AddObjectToIndex (file .stage2 .mode , git .MustIDFromString (hash ), file .stage2 .path )
224
+ * filesToAdd = append (* filesToAdd , git.IndexObjectInfo {Mode : file .stage2 .mode , Object : git .MustIDFromString (hash ), Filename : file .stage2 .path })
225
+ return nil
225
226
default :
226
227
if file .stage1 != nil {
227
228
return & errMergeConflict {file .stage1 .path }
@@ -245,6 +246,9 @@ func AttemptThreeWayMerge(ctx context.Context, gitPath string, gitRepo *git.Repo
245
246
return false , nil , fmt .Errorf ("unable to run read-tree -m! Error: %w" , err )
246
247
}
247
248
249
+ var filesToRemove []string
250
+ var filesToAdd []git.IndexObjectInfo
251
+
248
252
// Then we use git ls-files -u to list the unmerged files and collate the triples in unmergedfiles
249
253
unmerged := make (chan * unmergedFile )
250
254
go unmergedFiles (ctx , gitPath , unmerged )
@@ -270,7 +274,7 @@ func AttemptThreeWayMerge(ctx context.Context, gitPath string, gitRepo *git.Repo
270
274
}
271
275
272
276
// OK now we have the unmerged file triplet attempt to merge it
273
- if err := attemptMerge (ctx , file , gitPath , gitRepo ); err != nil {
277
+ if err := attemptMerge (ctx , file , gitPath , & filesToRemove , & filesToAdd ); err != nil {
274
278
if conflictErr , ok := err .(* errMergeConflict ); ok {
275
279
log .Trace ("Conflict: %s in %s" , conflictErr .filename , description )
276
280
conflict = true
@@ -283,6 +287,15 @@ func AttemptThreeWayMerge(ctx context.Context, gitPath string, gitRepo *git.Repo
283
287
return false , nil , err
284
288
}
285
289
}
290
+
291
+ // Add and remove files in one command, as this is slow with many files otherwise
292
+ if err := gitRepo .RemoveFilesFromIndex (filesToRemove ... ); err != nil {
293
+ return false , nil , err
294
+ }
295
+ if err := gitRepo .AddObjectsToIndex (filesToAdd ... ); err != nil {
296
+ return false , nil , err
297
+ }
298
+
286
299
return conflict , conflictedFiles , nil
287
300
}
288
301
0 commit comments