-
Notifications
You must be signed in to change notification settings - Fork 280
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pull #464
Pull #464
Changes from 3 commits
4730e27
4f058f4
5aae55a
f713326
c7b439a
1a2fd36
b510505
ea66aa0
d88ba4d
2de17e1
0bd6b02
18b86b2
25c8d87
b9c8b8e
f8bd53e
ed5ca8b
935711a
accc3b4
1efd44d
4f85b27
0c611f4
696b4bd
4c50988
c712860
9331722
af571de
436204b
1300469
277e98d
64b6b9f
cc06002
369106f
1d141c6
2d989bc
12a173c
f2c6ea3
e18935e
878d2c3
3e69a1c
e8b2aca
31b39c7
ff601a6
2333aaa
f167004
d8bf6c2
1dd20ba
6b4d2e0
631df10
faa5a92
04f1c4c
6dbc38f
4feb8c6
dae0b10
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// | ||
// GTRepository+Pull.h | ||
// ObjectiveGitFramework | ||
// | ||
// Created by Ben Chatelain on 6/17/15. | ||
// Copyright © 2015 GitHub, Inc. All rights reserved. | ||
// | ||
|
||
#import "GTRepository.h" | ||
#import "git2/merge.h" | ||
|
||
NS_ASSUME_NONNULL_BEGIN | ||
|
||
/// An enum describing the result of the merge analysis. | ||
/// See `git_merge_analysis_t`. | ||
typedef NS_ENUM(NSInteger, GTMergeAnalysis) { | ||
GTMergeAnalysisNone = GIT_MERGE_ANALYSIS_NONE, | ||
GTMergeAnalysisNormal = GIT_MERGE_ANALYSIS_NORMAL, | ||
GTMergeAnalysisUpToDate = GIT_MERGE_ANALYSIS_UP_TO_DATE, | ||
GTMergeAnalysisUnborn = GIT_MERGE_ANALYSIS_UNBORN, | ||
GTMergeAnalysisFastForward = GIT_MERGE_ANALYSIS_FASTFORWARD, | ||
}; | ||
|
||
typedef void (^GTRemoteFetchTransferProgressBlock)(const git_transfer_progress *progress, BOOL *stop); | ||
|
||
@interface GTRepository (Pull) | ||
|
||
#pragma mark - Pull | ||
|
||
/// Pull a single branch from a remote. | ||
/// | ||
/// branch - The branch to pull. | ||
/// remote - The remote to pull from. | ||
/// options - Options applied to the fetch operation. | ||
/// Recognized options are: | ||
/// `GTRepositoryRemoteOptionsCredentialProvider` | ||
/// error - The error if one occurred. Can be NULL. | ||
/// progressBlock - An optional callback for monitoring progress. | ||
/// | ||
/// Returns YES if the pull was successful, NO otherwise (and `error`, if provided, | ||
/// will point to an error describing what happened). | ||
- (BOOL)pullBranch:(GTBranch *)branch fromRemote:(GTRemote *)remote withOptions:(nullable NSDictionary *)options error:(NSError **)error progress:(nullable GTRemoteFetchTransferProgressBlock)progressBlock; | ||
|
||
/// Analyse which merge to perform | ||
/// | ||
/// toBranch - The current branch. | ||
/// fromBranch - The remote to pull from. | ||
/// error - The error if one occurred. Can be NULL. | ||
/// | ||
/// Returns the result as a GTMergeAnalysis. | ||
- (GTMergeAnalysis)analyseMerge:(GTBranch *)toBranch fromBranch:(GTBranch *)fromBranch error:(NSError **)error; | ||
|
||
@end | ||
|
||
NS_ASSUME_NONNULL_END |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// | ||
// GTRepository+Pull.m | ||
// ObjectiveGitFramework | ||
// | ||
// Created by Ben Chatelain on 6/17/15. | ||
// Copyright © 2015 GitHub, Inc. All rights reserved. | ||
// | ||
|
||
#import "GTRepository+Pull.h" | ||
|
||
#import "GTCommit.h" | ||
#import "GTRemote.h" | ||
#import "GTRepository+Committing.h" | ||
#import "GTRepository+RemoteOperations.h" | ||
#import "git2/merge.h" | ||
|
||
@implementation GTRepository (Pull) | ||
|
||
#pragma mark - Pull | ||
|
||
- (BOOL)pullBranch:(GTBranch *)branch fromRemote:(GTRemote *)remote withOptions:(NSDictionary *)options | ||
error:(NSError **)error progress:(GTRemoteFetchTransferProgressBlock)progressBlock | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: opening curly on the preceding line. |
||
NSParameterAssert(branch); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: explicit comparison to |
||
NSParameterAssert(remote); | ||
|
||
GTRepository *repo = remote.repository; | ||
|
||
GTBranch *remoteBranch; | ||
if (branch.branchType == GTBranchTypeLocal) { | ||
BOOL success; | ||
remoteBranch = [branch trackingBranchWithError:error success:&success]; | ||
if (!success) { | ||
return NO; | ||
} | ||
} | ||
else { | ||
remoteBranch = branch; | ||
} | ||
|
||
if (![self fetchRemote:remote withOptions:options error:error progress:progressBlock]) { | ||
return NO; | ||
} | ||
|
||
// Check if merge is necessary | ||
GTBranch *localBranch = [repo currentBranchWithError:error]; | ||
if (*error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you should be checking for the return value, not the error — I fear a nice SEGV if I was to pass There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. Using the user-supplied error pointer for control flow is messy, and dangerous 💥 . |
||
return NO; | ||
} | ||
|
||
GTCommit *localCommit = [localBranch targetCommitAndReturnError:error]; | ||
if (*error) { | ||
return NO; | ||
} | ||
|
||
GTCommit *remoteCommit = [remoteBranch targetCommitAndReturnError:error]; | ||
if (*error) { | ||
return NO; | ||
} | ||
|
||
if ([localCommit.SHA isEqualToString:remoteCommit.SHA]) { | ||
return YES; | ||
} | ||
|
||
GTMergeAnalysis analysis = [self analyseMerge:branch fromBranch:remoteBranch error:error]; | ||
|
||
if (*error) { | ||
return NO; | ||
} | ||
|
||
if (analysis & GTMergeAnalysisUpToDate) { | ||
// Nothing to do | ||
return YES; | ||
} else if (analysis & GTMergeAnalysisFastForward) { | ||
// Do FastForward | ||
NSLog(@"Fast-Forward merge is not yet supported"); | ||
return NO; | ||
} else if (analysis & GTMergeAnalysisNormal) { | ||
// Do normal merge | ||
GTTree *remoteTree = remoteCommit.tree; | ||
NSString *message = [NSString stringWithFormat:@"Merge branch '%@'", localBranch.shortName]; | ||
NSArray *parents = @[ localCommit, remoteCommit ]; | ||
GTCommit *mergeCommit = [repo createCommitWithTree:remoteTree message:message | ||
parents:parents updatingReferenceNamed:localBranch.name | ||
error:error]; | ||
if (!mergeCommit) { | ||
return NO; | ||
} | ||
|
||
return YES; | ||
} else if (analysis & GTMergeAnalysisUnborn) { | ||
// Do unborn merge | ||
NSLog(@"Unborn merge is not yet supported"); | ||
return NO; | ||
} | ||
|
||
return NO; | ||
} | ||
|
||
- (GTMergeAnalysis)analyseMerge:(GTBranch *)toBranch fromBranch:(GTBranch *)fromBranch error:(NSError **)error | ||
{ | ||
git_merge_analysis_t analysis; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Do note that I find the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, agreed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI (because you had me wondering) : https://github.com/libgit2/libgit2/blob/master/src/merge.c#L2672. Not that it really matters though, it's just a default value. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, I was just reading the docks, not looking into the code. Then I will probably make a PR for |
||
git_merge_preference_t preference; | ||
git_annotated_commit *annotatedCommit; | ||
|
||
GTCommit *fromCommit = [fromBranch targetCommitAndReturnError:error]; | ||
if (*error) { | ||
return GTMergeAnalysisNone; | ||
} | ||
|
||
git_annotated_commit_lookup(&annotatedCommit, self.git_repository, git_object_id(fromCommit.git_object)); | ||
git_merge_analysis(&analysis, &preference, self.git_repository, (const git_annotated_commit **) &annotatedCommit, 1); | ||
git_annotated_commit_free(annotatedCommit); | ||
|
||
return (GTMergeAnalysis)analysis; | ||
} | ||
|
||
@end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/pull/merge?