diff --git a/ObjectiveGit/GTRepository+Merging.h b/ObjectiveGit/GTRepository+Merging.h index 81b3f7a44..927fc62b2 100644 --- a/ObjectiveGit/GTRepository+Merging.h +++ b/ObjectiveGit/GTRepository+Merging.h @@ -63,6 +63,16 @@ typedef NS_OPTIONS(NSInteger, GTMergePreference) { /// will point to an error describing what happened). - (BOOL)mergeBranchIntoCurrentBranch:(GTBranch *)fromBranch withError:(NSError **)error; +/// Complete a pending merge +/// +/// This method can be used to complete a merge that has been stopped because +/// of conflicts. +/// +/// error - The error if one occurred. Can be NULL +/// +/// Returns YES if the merge could be committed, NO otherwise. +- (BOOL)finalizeMerge:(NSError **)error; + /// Gets the file content with conflict markers for the given file /// /// The parameters taked are the ones received from `enumerateConflictedFiles`. diff --git a/ObjectiveGit/GTRepository+Merging.m b/ObjectiveGit/GTRepository+Merging.m index 6d2ac1c08..4685bce67 100644 --- a/ObjectiveGit/GTRepository+Merging.m +++ b/ObjectiveGit/GTRepository+Merging.m @@ -129,6 +129,69 @@ - (BOOL)mergeAnnotatedCommits:(NSArray *)annotatedCommits return YES; } +- (BOOL)finalizeMerge:(NSError **)error { + GTRepositoryStateType state; + BOOL success = [self calculateState:&state withError:error]; + if (!success) { + return NO; + } + + if (state != GTRepositoryStateMerge) { + if (error) *error = [NSError git_errorFor:GIT_EINVALID description:@"Repository is not in a merge state"]; + return NO; + } + + GTIndex *index = [self indexWithError:error]; + if (index == nil) { + return NO; + } + + if (index.hasConflicts) { + if (error) *error = [NSError git_errorFor:GIT_ECONFLICT description:@"Index has unmerged changes"]; + return NO; + } + + GTTree *mergedTree = [index writeTree:error]; + if (mergedTree == nil) { + return NO; + } + + GTBranch *localBranch = [self currentBranchWithError:error]; + if (localBranch == nil) { + return NO; + } + + GTCommit *localCommit = [localBranch targetCommitWithError:error]; + if (!localCommit) { + return NO; + } + + // Build the commits' parents + NSMutableArray *parents = [NSMutableArray array]; + [parents addObject:localCommit]; + + NSArray *mergeHeads = [self mergeHeadEntriesWithError:error]; + if (mergeHeads.count == 0) { + return NO; + } + for (GTOID *oid in mergeHeads) { + NSError *lookupError = nil; + GTCommit *commit = [self lookUpObjectByOID:oid objectType:GTObjectTypeCommit error:&lookupError]; + if (commit == nil) { + if (error) { + *error = [NSError git_errorFor:GIT_ERROR + description:@"Failed to lookup one of the merge heads" + userInfo:@{ NSUnderlyingErrorKey: lookupError } + failureReason:nil]; + } + return NO; + } + [parents addObject:commit]; + } + + return [self finalizeMergeOfBranch:localBranch mergedTree:mergedTree parents:parents error:error]; +} + - (BOOL)finalizeMergeOfBranch:(GTBranch *)localBranch mergedTree:(GTTree *)mergedTree parents:(NSArray *)parents error:(NSError **)error { // Load the message to use