@@ -103,6 +103,32 @@ - (BOOL)analyzeMerge:(GTMergeAnalysis *)analysis preference:(GTMergePreference *
103
103
return YES ;
104
104
}
105
105
106
+ - (BOOL )mergeAnnotatedCommits : (NSArray <GTAnnotatedCommit *> *)annotatedCommits mergeOptions : (NSDictionary *)mergeOptions checkoutOptions : (GTCheckoutOptions *)checkoutOptions error : (NSError **)error {
107
+ NSParameterAssert (annotatedCommits);
108
+
109
+ git_merge_options merge_opts = GIT_MERGE_OPTIONS_INIT;
110
+
111
+ const git_annotated_commit **annotated_commits = NULL ;
112
+ if (annotatedCommits.count > 0 ) {
113
+ annotated_commits = calloc (annotatedCommits.count , sizeof (git_annotated_commit *));
114
+ for (NSUInteger i = 0 ; i < annotatedCommits.count ; i++){
115
+ annotated_commits[i] = [annotatedCommits[i] git_annotated_commit ];
116
+ }
117
+ }
118
+ @onExit {
119
+ free (annotated_commits);
120
+ };
121
+
122
+ int gitError = git_merge (self.git_repository , annotated_commits, annotatedCommits.count , &merge_opts, checkoutOptions.git_checkoutOptions );
123
+ if (gitError != GIT_OK) {
124
+ if (error != NULL ) {
125
+ *error = [NSError git_errorFor: gitError description: @" Merge failed" ];
126
+ }
127
+ return NO ;
128
+ }
129
+ return YES ;
130
+ }
131
+
106
132
- (BOOL )mergeBranchIntoCurrentBranch : (GTBranch *)branch withError : (NSError **)error {
107
133
// Check if merge is necessary
108
134
GTBranch *localBranch = [self currentBranchWithError: error];
@@ -156,54 +182,51 @@ - (BOOL)mergeBranchIntoCurrentBranch:(GTBranch *)branch withError:(NSError **)er
156
182
}
157
183
158
184
// Do normal merge
159
- GTTree *localTree = localCommit.tree ;
160
- GTTree *remoteTree = remoteCommit.tree ;
161
-
162
- // TODO: Find common ancestor
163
- GTTree *ancestorTree = nil ;
164
-
165
- // Merge
166
- GTIndex *index = [localTree merge: remoteTree ancestor: ancestorTree error: error];
167
- if (!index) {
185
+ GTIndex *index = [self indexWithError: error];
186
+ if (index == nil ) {
168
187
return NO ;
169
188
}
170
189
171
- // Check for conflict
172
- if (index.hasConflicts ) {
173
- NSMutableArray <NSString *>*files = [NSMutableArray array ];
174
- [index enumerateConflictedFilesWithError: error usingBlock: ^(GTIndexEntry * _Nonnull ancestor, GTIndexEntry * _Nonnull ours, GTIndexEntry * _Nonnull theirs, BOOL * _Nonnull stop) {
175
- [files addObject: ours.path];
176
- }];
190
+ NSError *mergeError = nil ;
191
+ GTCheckoutOptions *checkoutOptions = [GTCheckoutOptions checkoutOptionsWithStrategy: GTCheckoutStrategySafe|GTCheckoutStrategyAllowConflicts];
177
192
193
+ success = [self mergeAnnotatedCommits: @[remoteAnnotatedCommit]
194
+ mergeOptions: nil
195
+ checkoutOptions: checkoutOptions
196
+ error: &mergeError];
197
+ if (!success) {
178
198
if (error != NULL ) {
179
- NSDictionary *userInfo = @{GTPullMergeConflictedFiles: files};
180
- *error = [NSError git_errorFor: GIT_ECONFLICT description: @" Merge conflict" userInfo: userInfo failureReason: nil ];
199
+ *error = mergeError;
181
200
}
201
+ return NO ;
202
+ }
182
203
183
- // Write conflicts
184
- git_merge_options merge_opts = GIT_MERGE_OPTIONS_INIT;
185
- git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
186
- checkout_opts.checkout_strategy = (GIT_CHECKOUT_SAFE | GIT_CHECKOUT_ALLOW_CONFLICTS);
187
-
188
- git_annotated_commit *annotatedCommit;
189
- [self annotatedCommit: &annotatedCommit fromCommit: remoteCommit error: error];
190
-
191
- git_merge (self.git_repository , (const git_annotated_commit **)&annotatedCommit, 1 , &merge_opts, &checkout_opts);
204
+ if (![index refresh: error]) {
205
+ return NO ;
206
+ }
192
207
208
+ if (index.hasConflicts ) {
209
+ if (error) {
210
+ NSMutableArray <NSString *> *files = [NSMutableArray array ];
211
+ [index enumerateConflictedFilesWithError: error usingBlock: ^(GTIndexEntry * _Nonnull ancestor, GTIndexEntry * _Nonnull ours, GTIndexEntry * _Nonnull theirs, BOOL * _Nonnull stop) {
212
+ [files addObject: ours.path];
213
+ }];
214
+ NSDictionary *userInfo = @{GTPullMergeConflictedFiles: files};
215
+ *error = [NSError git_errorFor: GIT_EMERGECONFLICT description: @" Merge conflict" userInfo: userInfo failureReason: nil ];
216
+ }
193
217
return NO ;
194
218
}
195
219
196
- GTTree *newTree = [index writeTreeToRepository: self error : error];
197
- if (!newTree ) {
220
+ GTTree *mergedTree = [index writeTree : error];
221
+ if (mergedTree == nil ) {
198
222
return NO ;
199
223
}
200
224
201
225
// Create merge commit
202
226
NSString *message = [NSString stringWithFormat: @" Merge branch '%@ '" , localBranch.shortName];
203
227
NSArray *parents = @[ localCommit, remoteCommit ];
204
228
205
- // FIXME: This is stepping on the local tree
206
- GTCommit *mergeCommit = [self createCommitWithTree: newTree message: message parents: parents updatingReferenceNamed: localBranch.reference.name error: error];
229
+ GTCommit *mergeCommit = [self createCommitWithTree: mergedTree message: message parents: parents updatingReferenceNamed: localBranch.reference.name error: error];
207
230
if (!mergeCommit) {
208
231
return NO ;
209
232
}
@@ -287,16 +310,6 @@ - (NSString * _Nullable)contentsOfDiffWithAncestor:(GTIndexEntry *)ancestor ourS
287
310
return mergedContent;
288
311
}
289
312
290
- - (BOOL )annotatedCommit : (git_annotated_commit **)annotatedCommit fromCommit : (GTCommit *)fromCommit error : (NSError **)error {
291
- int gitError = git_annotated_commit_lookup (annotatedCommit, self.git_repository , fromCommit.OID .git_oid );
292
- if (gitError != GIT_OK) {
293
- if (error != NULL ) *error = [NSError git_errorFor: gitError description: @" Failed to lookup annotated commit for %@ " , fromCommit];
294
- return NO ;
295
- }
296
-
297
- return YES ;
298
- }
299
-
300
313
- (BOOL )analyzeMerge : (GTMergeAnalysis *)analysis fromBranch : (GTBranch *)fromBranch error : (NSError **)error {
301
314
NSParameterAssert (analysis != NULL );
302
315
NSParameterAssert (fromBranch != nil );
0 commit comments