Skip to content

Commit e0103df

Browse files
committed
Update the old merge method to go through the new support
This fixes the file path in the diff always being `file.txt`, as well as (I suspect) taking into account what's in the index instead of going straight to the ODB.
1 parent 4057f02 commit e0103df

File tree

8 files changed

+159
-107
lines changed

8 files changed

+159
-107
lines changed

Diff for: ObjectiveGit/GTIndex.h

+18
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
@class GTIndexEntry;
3434
@class GTRepository;
3535
@class GTTree;
36+
@class GTMergeResult;
3637

3738
NS_ASSUME_NONNULL_BEGIN
3839

@@ -234,6 +235,23 @@ NS_ASSUME_NONNULL_BEGIN
234235
- (GTIndexEntry * _Nullable)entryWithName:(NSString *)name error:(NSError **)error __deprecated_msg("use entryWithPath:error: instead.");
235236

236237

238+
@end
239+
240+
@interface GTIndex (FileMerging)
241+
242+
/// Gets the result of a merge with the given file entries
243+
///
244+
/// The parameters taked are the ones received from `enumerateConflictedFiles`.
245+
///
246+
/// ancestor - The ancestor entry
247+
/// ours - The index entry of our side
248+
/// theirs - The index entry of their side
249+
/// options - The merge options to use. Can be nil.
250+
/// error - The error if one occurred. Can be NULL.
251+
///
252+
/// Returns The results of the merge or nil on error
253+
- (GTMergeResult * _Nullable)resultOfMergingAncestorEntry:(GTIndexEntry *)ancestor ourEntry:(GTIndexEntry *)ours theirEntry:(GTIndexEntry *)theirs options:(NSDictionary * _Nullable)options error:(NSError * _Nullable __autoreleasing *)error;
254+
237255
@end
238256

239257
NS_ASSUME_NONNULL_END

Diff for: ObjectiveGit/GTIndex.m

+27
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@
3939
#import "GTBlob.h"
4040
#import "NSArray+StringArray.h"
4141
#import "NSError+Git.h"
42+
#import "GTMerge+Private.h"
4243

4344
#import "git2/errors.h"
45+
#import "git2/merge.h"
4446

4547
// The block synonymous with libgit2's `git_index_matched_path_cb` callback.
4648
typedef BOOL (^GTIndexPathspecMatchedBlock)(NSString *matchedPathspec, NSString *path, BOOL *stop);
@@ -406,4 +408,29 @@ - (GTIndexEntry *)entryWithName:(NSString *)name {
406408
- (GTIndexEntry *)entryWithName:(NSString *)name error:(NSError **)error {
407409
return [self entryWithPath:name error:error];
408410
}
411+
412+
@end
413+
414+
@implementation GTIndex (FileMerging)
415+
416+
- (GTMergeResult *)resultOfMergingAncestorEntry:(GTIndexEntry *)ancestorEntry ourEntry:(GTIndexEntry *)ourEntry theirEntry:(GTIndexEntry *)theirEntry options:(NSDictionary *)options error:(NSError * _Nullable __autoreleasing *)error {
417+
NSParameterAssert(ourEntry);
418+
NSParameterAssert(theirEntry);
419+
NSParameterAssert(ancestorEntry);
420+
421+
git_merge_file_result gitResult;
422+
git_merge_file_options opts;
423+
424+
BOOL success = [GTMergeFile handleMergeFileOptions:&opts optionsDict:options error:error];
425+
if (!success) return nil;
426+
427+
int gitError = git_merge_file_from_index(&gitResult, self.repository.git_repository, ancestorEntry.git_index_entry, ourEntry.git_index_entry, theirEntry.git_index_entry, &opts);
428+
if (gitError != 0) {
429+
if (error) *error = [NSError git_errorFor:gitError description:@"Merging entries failed"];
430+
return nil;
431+
}
432+
433+
return [[GTMergeResult alloc] initWithGitMergeFileResult:&gitResult];
434+
}
435+
409436
@end

Diff for: ObjectiveGit/GTMerge+Private.h

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//
2+
// GTMerge+Private.h
3+
// ObjectiveGitFramework
4+
//
5+
// Created by Etienne on 27/10/2018.
6+
// Copyright © 2018 GitHub, Inc. All rights reserved.
7+
//
8+
9+
#import "GTMerge.h"
10+
11+
@interface GTMergeFile (Private)
12+
13+
+ (BOOL)handleMergeFileOptions:(git_merge_file_options *)opts optionsDict:(NSDictionary *)dict error:(NSError **)error;
14+
15+
@end

Diff for: ObjectiveGit/GTMerge.m

+21
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
//
88

99
#import "GTMerge.h"
10+
#import "GTOID.h"
11+
#import "GTObjectDatabase.h"
12+
#import "GTOdbObject.h"
13+
#import "GTRepository.h"
14+
#import "GTIndex.h"
15+
#import "GTIndexEntry.h"
1016
#import "NSError+Git.h"
1117

1218
@interface GTMergeResult ()
@@ -67,6 +73,21 @@ + (instancetype)fileWithString:(NSString *)string path:(NSString * _Nullable)pat
6773
return [[self alloc] initWithData:stringData path:path mode:mode];
6874
}
6975

76+
+ (instancetype)fileWithIndexEntry:(GTIndexEntry *)entry error:(NSError **)error {
77+
NSParameterAssert(entry);
78+
79+
const git_index_entry *git_entry = entry.git_index_entry;
80+
GTOID *ancestorOID = [[GTOID alloc] initWithGitOid:&git_entry->id];
81+
GTRepository *repository = entry.index.repository;
82+
GTObjectDatabase *database = [repository objectDatabaseWithError:error];
83+
NSData *contents = [[database objectWithOID:ancestorOID error:error] data];
84+
if (contents == nil) {
85+
return nil;
86+
}
87+
88+
return [[self alloc] initWithData:contents path:entry.path mode:git_entry->mode];
89+
}
90+
7091
- (instancetype)initWithData:(NSData *)data path:(NSString *)path mode:(unsigned int)mode {
7192
NSParameterAssert(data);
7293
self = [super init];

Diff for: ObjectiveGit/GTRepository+Merging.m

+7-65
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#import "GTIndexEntry.h"
2020
#import "GTOdbObject.h"
2121
#import "GTObjectDatabase.h"
22+
#import "GTMerge.h"
2223

2324
typedef void (^GTRemoteFetchTransferProgressBlock)(const git_transfer_progress *stats, BOOL *stop);
2425

@@ -173,78 +174,19 @@ - (BOOL)mergeBranchIntoCurrentBranch:(GTBranch *)branch withError:(NSError **)er
173174
}
174175

175176
- (NSString * _Nullable)contentsOfDiffWithAncestor:(GTIndexEntry *)ancestor ourSide:(GTIndexEntry *)ourSide theirSide:(GTIndexEntry *)theirSide error:(NSError **)error {
177+
NSParameterAssert(ancestor && ourSide && theirSide);
176178

177-
GTObjectDatabase *database = [self objectDatabaseWithError:error];
178-
if (database == nil) {
179+
GTIndex *index = [self indexWithError:error];
180+
if (index == nil) {
179181
return nil;
180182
}
181183

182-
// initialize the ancestor's merge file input
183-
git_merge_file_input ancestorInput;
184-
int gitError = git_merge_file_init_input(&ancestorInput, GIT_MERGE_FILE_INPUT_VERSION);
185-
if (gitError != GIT_OK) {
186-
if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Failed to create merge file input for ancestor"];
187-
return nil;
188-
}
189-
190-
git_oid ancestorId = ancestor.git_index_entry->id;
191-
GTOID *ancestorOID = [[GTOID alloc] initWithGitOid:&ancestorId];
192-
NSData *ancestorData = [[database objectWithOID:ancestorOID error: error] data];
193-
if (ancestorData == nil) {
194-
return nil;
195-
}
196-
ancestorInput.ptr = ancestorData.bytes;
197-
ancestorInput.size = ancestorData.length;
198-
199-
200-
// initialize our merge file input
201-
git_merge_file_input ourInput;
202-
gitError = git_merge_file_init_input(&ourInput, GIT_MERGE_FILE_INPUT_VERSION);
203-
if (gitError != GIT_OK) {
204-
if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Failed to create merge file input for our side"];
184+
GTMergeResult *result = [index resultOfMergingAncestorEntry:ancestor ourEntry:ourSide theirEntry:theirSide options:nil error:error];
185+
if (result == nil) {
205186
return nil;
206187
}
207188

208-
git_oid ourId = ourSide.git_index_entry->id;
209-
GTOID *ourOID = [[GTOID alloc] initWithGitOid:&ourId];
210-
NSData *ourData = [[database objectWithOID:ourOID error: error] data];
211-
if (ourData == nil) {
212-
return nil;
213-
}
214-
ourInput.ptr = ourData.bytes;
215-
ourInput.size = ourData.length;
216-
217-
218-
// initialize their merge file input
219-
git_merge_file_input theirInput;
220-
gitError = git_merge_file_init_input(&theirInput, GIT_MERGE_FILE_INPUT_VERSION);
221-
if (gitError != GIT_OK) {
222-
if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Failed to create merge file input other side"];
223-
return nil;
224-
}
225-
226-
git_oid theirId = theirSide.git_index_entry->id;
227-
GTOID *theirOID = [[GTOID alloc] initWithGitOid:&theirId];
228-
NSData *theirData = [[database objectWithOID:theirOID error: error] data];
229-
if (theirData == nil) {
230-
return nil;
231-
}
232-
theirInput.ptr = theirData.bytes;
233-
theirInput.size = theirData.length;
234-
235-
236-
git_merge_file_result result;
237-
gitError = git_merge_file(&result, &ancestorInput, &ourInput, &theirInput, nil);
238-
if (gitError != GIT_OK) {
239-
if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Failed to create merge file"];
240-
return nil;
241-
}
242-
243-
NSString *mergedContent = [[NSString alloc] initWithBytes:result.ptr length:result.len encoding:NSUTF8StringEncoding];
244-
245-
git_merge_file_result_free(&result);
246-
247-
return mergedContent;
189+
return [[NSString alloc] initWithData:result.data encoding:NSUTF8StringEncoding];
248190
}
249191

250192
- (BOOL)annotatedCommit:(git_annotated_commit **)annotatedCommit fromCommit:(GTCommit *)fromCommit error:(NSError **)error {

Diff for: ObjectiveGitFramework.xcodeproj/project.pbxproj

+2
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@
500500
4D7BA1B82183C4C9003CD3CE /* GTMerge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GTMerge.h; sourceTree = "<group>"; };
501501
4D7BA1B92183C4C9003CD3CE /* GTMerge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GTMerge.m; sourceTree = "<group>"; };
502502
4D7BA1BF2183DD55003CD3CE /* GTMergeSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GTMergeSpec.m; sourceTree = "<group>"; };
503+
4D7BA1BE2183D3EE003CD3CE /* GTMerge+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "GTMerge+Private.h"; sourceTree = "<group>"; };
503504
4D9BCD23206D84AD003CD3CE /* libgit2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgit2.a; path = External/build/lib/libgit2.a; sourceTree = "<group>"; };
504505
4DBA4A3117DA73CE006CD5F5 /* GTRemoteSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTRemoteSpec.m; sourceTree = "<group>"; };
505506
4DC55AE31AD859AD0032563C /* GTCheckoutOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTCheckoutOptions.h; sourceTree = "<group>"; };
@@ -987,6 +988,7 @@
987988
4DC55AE31AD859AD0032563C /* GTCheckoutOptions.h */,
988989
4DC55AE41AD859AD0032563C /* GTCheckoutOptions.m */,
989990
4D7BA1B82183C4C9003CD3CE /* GTMerge.h */,
991+
4D7BA1BE2183D3EE003CD3CE /* GTMerge+Private.h */,
990992
4D7BA1B92183C4C9003CD3CE /* GTMerge.m */,
991993
);
992994
path = ObjectiveGit;

Diff for: ObjectiveGitTests/GTIndexSpec.m

+69
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,75 @@
328328
});
329329
});
330330

331+
describe(@"-resultOfMergingAncestorEntry:ourEntry:theirEntry:options:error:", ^{
332+
it(@"should produce a nice merge conflict description", ^{
333+
NSURL *mainURL = [repository.fileURL URLByAppendingPathComponent:@"main.m"];
334+
NSData *mainData = [[NSFileManager defaultManager] contentsAtPath:mainURL.path];
335+
expect(mainData).notTo(beNil());
336+
337+
NSString *mainString = [[NSString alloc] initWithData:mainData encoding:NSUTF8StringEncoding];
338+
NSData *masterData = [[mainString stringByReplacingOccurrencesOfString:@"return" withString:@"//The meaning of life is 41\n return"] dataUsingEncoding:NSUTF8StringEncoding];
339+
NSData *otherData = [[mainString stringByReplacingOccurrencesOfString:@"return" withString:@"//The meaning of life is 42\n return"] dataUsingEncoding:NSUTF8StringEncoding];
340+
341+
expect(@([[NSFileManager defaultManager] createFileAtPath:mainURL.path contents:masterData attributes:nil])).to(beTruthy());
342+
343+
GTIndex *index = [repository indexWithError:NULL];
344+
expect(@([index addFile:mainURL.lastPathComponent error:NULL])).to(beTruthy());
345+
GTReference *head = [repository headReferenceWithError:NULL];
346+
GTCommit *parent = [repository lookUpObjectByOID:head.targetOID objectType:GTObjectTypeCommit error:NULL];
347+
expect(parent).toNot(beNil());
348+
GTTree *masterTree = [index writeTree:NULL];
349+
expect(masterTree).toNot(beNil());
350+
351+
GTBranch *otherBranch = [repository lookUpBranchWithName:@"other-branch" type:GTBranchTypeLocal success:NULL error:NULL];
352+
expect(otherBranch).toNot(beNil());
353+
expect(@([repository checkoutReference:otherBranch.reference options:nil error:NULL])).to(beTruthy());
354+
355+
expect(@([[NSFileManager defaultManager] createFileAtPath:mainURL.path contents:otherData attributes:nil])).to(beTruthy());
356+
357+
index = [repository indexWithError:NULL];
358+
expect(@([index addFile:mainURL.lastPathComponent error:NULL])).to(beTruthy());
359+
GTTree *otherTree = [index writeTree:NULL];
360+
expect(otherTree).toNot(beNil());
361+
362+
GTIndex *conflictIndex = [otherTree merge:masterTree ancestor:parent.tree error:NULL];
363+
expect(@([conflictIndex hasConflicts])).to(beTruthy());
364+
365+
[conflictIndex enumerateConflictedFilesWithError:NULL usingBlock:^(GTIndexEntry * _Nonnull ancestor, GTIndexEntry * _Nonnull ours, GTIndexEntry * _Nonnull theirs, BOOL * _Nonnull stop) {
366+
367+
GTMergeResult *result = [conflictIndex resultOfMergingAncestorEntry:ancestor ourEntry:ours theirEntry:theirs options:nil error:NULL];
368+
expect(result).notTo(beNil());
369+
370+
NSString *conflictString = [[NSString alloc] initWithData:result.data encoding:NSUTF8StringEncoding];
371+
NSString *expectedString = @"//\n"
372+
"// main.m\n"
373+
"// Test\n"
374+
"//\n"
375+
"// Created by Joe Ricioppo on 9/28/10.\n"
376+
"// Copyright 2010 __MyCompanyName__. All rights reserved.\n"
377+
"//\n"
378+
"\n"
379+
"#import <Cocoa/Cocoa.h>\n"
380+
"\n"
381+
"int main(int argc, char *argv[])\n"
382+
"{\n"
383+
"<<<<<<< main.m\n"
384+
" //The meaning of life is 42\n"
385+
"=======\n"
386+
" //The meaning of life is 41\n"
387+
">>>>>>> main.m\n"
388+
" return NSApplicationMain(argc, (const char **) argv);\n"
389+
"}\n"
390+
"123456789\n"
391+
"123456789\n"
392+
"123456789\n"
393+
"123456789!blah!\n";
394+
395+
expect(conflictString).to(equal(expectedString));
396+
}];
397+
});
398+
});
399+
331400
afterEach(^{
332401
[self tearDown];
333402
});

Diff for: ObjectiveGitTests/GTRepositorySpec.m

-42
Original file line numberDiff line numberDiff line change
@@ -260,48 +260,6 @@
260260
});
261261
});
262262

263-
describe(@"-contentsOfDiffWithAncestor:ourSide:theirSide:error:", ^{
264-
it(@"should produce a nice merge conflict description", ^{
265-
NSURL *mainURL = [repository.fileURL URLByAppendingPathComponent:@"main.m"];
266-
NSData *mainData = [[NSFileManager defaultManager] contentsAtPath:mainURL.path];
267-
expect(mainData).notTo(beNil());
268-
269-
NSString *mainString = [[NSString alloc] initWithData:mainData encoding:NSUTF8StringEncoding];
270-
NSData *masterData = [[mainString stringByReplacingOccurrencesOfString:@"return" withString:@"//The meaning of life is 41\n return"] dataUsingEncoding:NSUTF8StringEncoding];
271-
NSData *otherData = [[mainString stringByReplacingOccurrencesOfString:@"return" withString:@"//The meaning of life is 42\n return"] dataUsingEncoding:NSUTF8StringEncoding];
272-
273-
expect(@([[NSFileManager defaultManager] createFileAtPath:mainURL.path contents:masterData attributes:nil])).to(beTruthy());
274-
275-
GTIndex *index = [repository indexWithError:NULL];
276-
expect(@([index addFile:mainURL.lastPathComponent error:NULL])).to(beTruthy());
277-
GTReference *head = [repository headReferenceWithError:NULL];
278-
GTCommit *parent = [repository lookUpObjectByOID:head.targetOID objectType:GTObjectTypeCommit error:NULL];
279-
expect(parent).toNot(beNil());
280-
GTTree *masterTree = [index writeTree:NULL];
281-
expect(masterTree).toNot(beNil());
282-
283-
GTBranch *otherBranch = [repository lookUpBranchWithName:@"other-branch" type:GTBranchTypeLocal success:NULL error:NULL];
284-
expect(otherBranch).toNot(beNil());
285-
expect(@([repository checkoutReference:otherBranch.reference options:nil error:NULL])).to(beTruthy());
286-
287-
expect(@([[NSFileManager defaultManager] createFileAtPath:mainURL.path contents:otherData attributes:nil])).to(beTruthy());
288-
289-
index = [repository indexWithError:NULL];
290-
expect(@([index addFile:mainURL.lastPathComponent error:NULL])).to(beTruthy());
291-
GTTree *otherTree = [index writeTree:NULL];
292-
expect(otherTree).toNot(beNil());
293-
294-
GTIndex *conflictIndex = [otherTree merge:masterTree ancestor:parent.tree error:NULL];
295-
expect(@([conflictIndex hasConflicts])).to(beTruthy());
296-
297-
[conflictIndex enumerateConflictedFilesWithError:NULL usingBlock:^(GTIndexEntry * _Nonnull ancestor, GTIndexEntry * _Nonnull ours, GTIndexEntry * _Nonnull theirs, BOOL * _Nonnull stop) {
298-
299-
NSString *conflictString = [repository contentsOfDiffWithAncestor:ancestor ourSide:ours theirSide:theirs error:NULL];
300-
expect(conflictString).to(equal(@"//\n// main.m\n// Test\n//\n// Created by Joe Ricioppo on 9/28/10.\n// Copyright 2010 __MyCompanyName__. All rights reserved.\n//\n\n#import <Cocoa/Cocoa.h>\n\nint main(int argc, char *argv[])\n{\n<<<<<<< file.txt\n //The meaning of life is 42\n=======\n //The meaning of life is 41\n>>>>>>> file.txt\n return NSApplicationMain(argc, (const char **) argv);\n}\n123456789\n123456789\n123456789\n123456789!blah!\n"));
301-
}];
302-
});
303-
});
304-
305263
describe(@"-mergeBaseBetweenFirstOID:secondOID:error:", ^{
306264
it(@"should find the merge base between two branches", ^{
307265
NSError *error = nil;

0 commit comments

Comments
 (0)