Skip to content
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

Merged
merged 53 commits into from
Sep 9, 2015
Merged

Pull #464

Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
4730e27
Initial pull implementation
phatblat Jun 17, 2015
4f058f4
Add GitMergeAnalysis handling
pietbrauer Jun 18, 2015
5aae55a
Convert GTRepository+Pull to tabs
pietbrauer Jun 18, 2015
f713326
Add fast-forward and unborn merge
pietbrauer Jun 18, 2015
c7b439a
Use GTMergeAnalysis as parameter instead of return type
pietbrauer Jun 18, 2015
1a2fd36
Checkout reference after updating HEAD
pietbrauer Jun 18, 2015
b510505
Remove new lines and use one line only for long method calls
pietbrauer Jun 18, 2015
ea66aa0
Make header public
pietbrauer Jun 18, 2015
d88ba4d
Also checkout after merge commit
pietbrauer Jun 18, 2015
2de17e1
Use return values to determine when to bail out
phatblat Jun 18, 2015
0bd6b02
Use referenceByUpdatingTarget:message:error
pietbrauer Jun 19, 2015
18b86b2
Abandon pull if tracking branch cannot be found
phatblat Jun 20, 2015
25c8d87
Merge branch 'master' into pull
phatblat Jun 28, 2015
b9c8b8e
Ignore Carthage/Build
phatblat Jun 27, 2015
f8bd53e
Change calls to targetCommitWithError:
phatblat Jun 28, 2015
ed5ca8b
Sort specs by name
phatblat Jun 28, 2015
935711a
Extract common testing functions
phatblat Jun 28, 2015
accc3b4
Add GTRepository+PullSpec with simplest case
phatblat Jun 28, 2015
1efd44d
Add test for pulling one commit
phatblat Jun 30, 2015
4f85b27
Add pending unborn test
phatblat Jul 2, 2015
0c611f4
Amend error description when GTBranch can't init due to HEAD being un…
phatblat Jul 3, 2015
696b4bd
Use updated reference to checkout at end of pull
phatblat Jul 3, 2015
4c50988
Include reflog message
phatblat Jul 3, 2015
c712860
Merge branch 'master' into pull
phatblat Jul 3, 2015
9331722
Merge branch 'master' into pull
phatblat Jul 15, 2015
af571de
Add test for pull with normal merge
phatblat Jul 15, 2015
436204b
#import Nimble-Swift.h
phatblat Jul 15, 2015
1300469
Add -description to GTRemote
phatblat Jul 15, 2015
277e98d
Better description for bare GTRepository
phatblat Jul 15, 2015
64b6b9f
Initialize GTMergeAnalysis with .None
phatblat Jul 16, 2015
cc06002
No preference on merge type
phatblat Jul 16, 2015
369106f
Fix issue preventing pull merge test from passing
phatblat Jul 17, 2015
1d141c6
Add more checks to merge test to detect lack of merge
phatblat Jul 17, 2015
2d989bc
Asserts and error feedback
phatblat Jul 17, 2015
12a173c
Add libgit2 folder reference to workspace
phatblat Jul 17, 2015
f2c6ea3
Ensure all non-happy paths return error info
phatblat Jul 18, 2015
e18935e
Fix createCommitInRepository to reuse tree from HEAD
phatblat Jul 18, 2015
878d2c3
Check for conflicts after merging trees
phatblat Jul 18, 2015
3e69a1c
Use hasConflicts
phatblat Jul 18, 2015
e8b2aca
Write merge tree to repo
phatblat Jul 18, 2015
31b39c7
Add test for merge conflict
phatblat Jul 18, 2015
ff601a6
Tabs
phatblat Jul 18, 2015
2333aaa
Analyse -> Analyze
phatblat Jul 23, 2015
f167004
Dial down the indentation
phatblat Jul 23, 2015
d8bf6c2
Doc revision
phatblat Jul 23, 2015
1dd20ba
Fix curly braces
phatblat Jul 23, 2015
6b4d2e0
Explicit comparison to nil
phatblat Jul 23, 2015
631df10
Merge branch 'master' into pull
phatblat Jul 23, 2015
faa5a92
Merge branch 'master' into pull
phatblat Aug 8, 2015
04f1c4c
🔥 the emoji from example name
phatblat Aug 9, 2015
6dbc38f
whene -> when
phatblat Aug 9, 2015
4feb8c6
Comment out pending test
phatblat Aug 24, 2015
dae0b10
Merge branch 'master' into pull
phatblat Sep 8, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions ObjectiveGit/GTRepository+Pull.h
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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/pull/merge?

/// 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
118 changes: 118 additions & 0 deletions ObjectiveGit/GTRepository+Pull.m
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
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: opening curly on the preceding line.

NSParameterAssert(branch);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: explicit comparison to nil.

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) {
Copy link
Contributor

Choose a reason for hiding this comment

The 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 NULL here. There are other cases below.

Copy link
Member Author

Choose a reason for hiding this comment

The 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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toBranch looks unused ? (I do realize it's WIP, feel free to ignore that if you're still 'writing').

Do note that I find the GTMergeAnalysis as a return value strange. I mean, how can we tell between GTMergeAnalysisNone, or "some kind of convoluted error occurred". Usually this means that you'll need to pass a pointer to a caller-supplied GTMergeAnalysis like so :
-(BOOL)analyseMerge:(GTMergeAnalysis *)result fromBranch:f toBranch:t error:....

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, agreed. toBranch is unused and I will remove it. git_merge_analysis() works with current branch AFAIK. I will also convert it to your suggested signature as it looks more like the existing APIs although GITMergeAnalysisNone is not in use currently see: https://github.com/libgit2/libgit2/blob/master/include/git2/merge.h#L273-L274

Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Member

Choose a reason for hiding this comment

The 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 libgit2 to change the docs. Nevertheless it is safer to handle GITMergeAnalysisNone than omitting it. 😉

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
13 changes: 13 additions & 0 deletions ObjectiveGitFramework.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,10 @@
DD3D9513182A81E1004AF532 /* GTBlame.m in Sources */ = {isa = PBXBuildFile; fileRef = DD3D9511182A81E1004AF532 /* GTBlame.m */; };
DD3D951C182AB25C004AF532 /* GTBlameHunk.h in Headers */ = {isa = PBXBuildFile; fileRef = DD3D951A182AB25C004AF532 /* GTBlameHunk.h */; settings = {ATTRIBUTES = (Public, ); }; };
DD3D951D182AB25C004AF532 /* GTBlameHunk.m in Sources */ = {isa = PBXBuildFile; fileRef = DD3D951B182AB25C004AF532 /* GTBlameHunk.m */; };
F8D1BDEE1B31FE7C00CDEC90 /* GTRepository+Pull.h in Headers */ = {isa = PBXBuildFile; fileRef = F8D1BDEC1B31FE7C00CDEC90 /* GTRepository+Pull.h */; };
F8D1BDEF1B31FE7C00CDEC90 /* GTRepository+Pull.h in Headers */ = {isa = PBXBuildFile; fileRef = F8D1BDEC1B31FE7C00CDEC90 /* GTRepository+Pull.h */; };
F8D1BDF01B31FE7C00CDEC90 /* GTRepository+Pull.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D1BDED1B31FE7C00CDEC90 /* GTRepository+Pull.m */; };
F8D1BDF11B31FE7C00CDEC90 /* GTRepository+Pull.m in Sources */ = {isa = PBXBuildFile; fileRef = F8D1BDED1B31FE7C00CDEC90 /* GTRepository+Pull.m */; };
F8E4A2911A170CA6006485A8 /* GTRemotePushSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = F8E4A2901A170CA6006485A8 /* GTRemotePushSpec.m */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -574,6 +578,8 @@
DD3D951B182AB25C004AF532 /* GTBlameHunk.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTBlameHunk.m; sourceTree = "<group>"; };
E46931A7172740D300F2077D /* update_libgit2 */ = {isa = PBXFileReference; lastKnownFileType = text; name = update_libgit2; path = script/update_libgit2; sourceTree = "<group>"; };
E46931A8172740D300F2077D /* update_libgit2_ios */ = {isa = PBXFileReference; lastKnownFileType = text; name = update_libgit2_ios; path = script/update_libgit2_ios; sourceTree = "<group>"; };
F8D1BDEC1B31FE7C00CDEC90 /* GTRepository+Pull.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTRepository+Pull.h"; sourceTree = "<group>"; };
F8D1BDED1B31FE7C00CDEC90 /* GTRepository+Pull.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTRepository+Pull.m"; sourceTree = "<group>"; };
F8E4A2901A170CA6006485A8 /* GTRemotePushSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTRemotePushSpec.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -783,6 +789,8 @@
D015F7C917F695E800AD5E1F /* GTRepository+Stashing.m */,
88746CC217FA1C950005888A /* GTRepository+Committing.h */,
88746CC317FA1C950005888A /* GTRepository+Committing.m */,
F8D1BDEC1B31FE7C00CDEC90 /* GTRepository+Pull.h */,
F8D1BDED1B31FE7C00CDEC90 /* GTRepository+Pull.m */,
4DFFB159183AA8D600D1565E /* GTRepository+RemoteOperations.h */,
4DFFB15A183AA8D600D1565E /* GTRepository+RemoteOperations.m */,
88B2131A1B20E785005CF2C5 /* GTRepository+References.h */,
Expand Down Expand Up @@ -1000,6 +1008,7 @@
8821547D17147B3600D76B76 /* GTOID.h in Headers */,
20F43DE318A2F668007D3621 /* GTRepository+Blame.h in Headers */,
D0CE552018B6C58F008EB8E0 /* GTFilterList.h in Headers */,
F8D1BDEE1B31FE7C00CDEC90 /* GTRepository+Pull.h in Headers */,
D021DF4F1806899000934E32 /* NSArray+StringArray.h in Headers */,
30DCBA6317B45A78009B0EBD /* GTRepository+Status.h in Headers */,
8821547617147A5200D76B76 /* GTReflogEntry.h in Headers */,
Expand All @@ -1015,6 +1024,7 @@
buildActionMask = 2147483647;
files = (
D01B6F3D19F82F8700D411BC /* GTTag.h in Headers */,
F8D1BDEF1B31FE7C00CDEC90 /* GTRepository+Pull.h in Headers */,
D01B6F4119F82F8700D411BC /* GTIndexEntry.h in Headers */,
D01B6F2319F82F8700D411BC /* GTRepository+Reset.h in Headers */,
D01B6F2D19F82F8700D411BC /* GTEnumerator.h in Headers */,
Expand Down Expand Up @@ -1136,6 +1146,7 @@
0867D690FE84028FC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastTestingUpgradeCheck = 0510;
LastUpgradeCheck = 0620;
ORGANIZATIONNAME = "GitHub, Inc";
Expand Down Expand Up @@ -1306,6 +1317,7 @@
BD6B0418131496CC001909D0 /* GTTreeEntry.m in Sources */,
DD3D951D182AB25C004AF532 /* GTBlameHunk.m in Sources */,
306123AE17EA5261006591D4 /* EXTScope.m in Sources */,
F8D1BDF01B31FE7C00CDEC90 /* GTRepository+Pull.m in Sources */,
BDD6279A1318391200DE34D1 /* GTBlob.m in Sources */,
BDD62925131C03D600DE34D1 /* GTTag.m in Sources */,
BDFAF9C4131C1845000508BC /* GTIndex.m in Sources */,
Expand Down Expand Up @@ -1364,6 +1376,7 @@
884C8A3A19FF4B890017E98D /* EXTScope.m in Sources */,
D01B6F4E19F82F8700D411BC /* GTRemote.m in Sources */,
D01B6F3019F82F8700D411BC /* GTObject.m in Sources */,
F8D1BDF11B31FE7C00CDEC90 /* GTRepository+Pull.m in Sources */,
D01B6F4619F82F8700D411BC /* GTBranch.m in Sources */,
D01B6F3A19F82F8700D411BC /* GTTreeEntry.m in Sources */,
D01B6F2419F82F8700D411BC /* GTRepository+Reset.m in Sources */,
Expand Down