diff --git a/ObjectiveGit/GTBranch.h b/ObjectiveGit/GTBranch.h index 43734ffb4..27c26e632 100644 --- a/ObjectiveGit/GTBranch.h +++ b/ObjectiveGit/GTBranch.h @@ -43,7 +43,7 @@ typedef NS_ENUM(NSInteger, GTBranchType) { @property (nonatomic, readonly) NSString *name; @property (nonatomic, readonly) NSString *shortName; -@property (nonatomic, readonly) NSString *SHA; +@property (nonatomic, copy, readonly) GTOID *OID; @property (nonatomic, readonly) NSString *remoteName; @property (nonatomic, readonly) GTBranchType branchType; @property (nonatomic, readonly, strong) GTRepository *repository; diff --git a/ObjectiveGit/GTBranch.m b/ObjectiveGit/GTBranch.m index f5762bb01..fbcaa5380 100644 --- a/ObjectiveGit/GTBranch.m +++ b/ObjectiveGit/GTBranch.m @@ -24,11 +24,13 @@ // #import "GTBranch.h" -#import "GTReference.h" -#import "GTEnumerator.h" -#import "GTRepository.h" + #import "GTCommit.h" +#import "GTEnumerator.h" +#import "GTOID.h" +#import "GTReference.h" #import "GTRemote.h" +#import "GTRepository.h" #import "NSError+Git.h" #import "git2/branch.h" @@ -38,18 +40,18 @@ @implementation GTBranch - (NSString *)description { - return [NSString stringWithFormat:@"<%@: %p> name: %@, shortName: %@, sha: %@, remoteName: %@, repository: %@", NSStringFromClass([self class]), self, self.name, self.shortName, self.SHA, self.remoteName, self.repository]; + return [NSString stringWithFormat:@"<%@: %p> name: %@, shortName: %@, sha: %@, remoteName: %@, repository: %@", NSStringFromClass([self class]), self, self.name, self.shortName, self.OID, self.remoteName, self.repository]; } - (BOOL)isEqual:(GTBranch *)otherBranch { if (otherBranch == self) return YES; if (![otherBranch isKindOfClass:self.class]) return NO; - return [self.name isEqual:otherBranch.name] && [self.SHA isEqual:otherBranch.SHA]; + return [self.name isEqual:otherBranch.name] && [self.OID isEqual:otherBranch.OID]; } - (NSUInteger)hash { - return self.name.hash ^ self.SHA.hash; + return self.name.hash ^ self.OID.hash; } @@ -100,8 +102,8 @@ - (NSString *)shortName { return @(name); } -- (NSString *)SHA { - return self.reference.targetSHA; +- (GTOID *)OID { + return self.reference.targetOID; } - (NSString *)remoteName { @@ -119,19 +121,19 @@ - (NSString *)remoteName { } - (GTCommit *)targetCommitAndReturnError:(NSError **)error { - if (self.SHA == nil) { + if (self.OID == nil) { if (error != NULL) *error = GTReference.invalidReferenceError; return nil; } - return [self.repository lookUpObjectBySHA:self.SHA objectType:GTObjectTypeCommit error:error]; + return [self.repository lookUpObjectByOID:self.OID objectType:GTObjectTypeCommit error:error]; } - (NSUInteger)numberOfCommitsWithError:(NSError **)error { GTEnumerator *enumerator = [[GTEnumerator alloc] initWithRepository:self.repository error:error]; if (enumerator == nil) return NSNotFound; - if (![enumerator pushSHA:self.SHA error:error]) return NSNotFound; + if (![enumerator pushSHA:self.OID.SHA error:error]) return NSNotFound; return [enumerator countRemainingObjects:error]; } @@ -144,22 +146,7 @@ - (GTBranchType)branchType { } - (NSArray *)uniqueCommitsRelativeToBranch:(GTBranch *)otherBranch error:(NSError **)error { - NSParameterAssert(otherBranch != nil); - - GTCommit *mergeBase = [self.repository mergeBaseBetweenFirstOID:self.reference.OID secondOID:otherBranch.reference.OID error:error]; - if (mergeBase == nil) return nil; - - GTEnumerator *enumerator = [[GTEnumerator alloc] initWithRepository:self.repository error:error]; - if (enumerator == nil) return nil; - - [enumerator resetWithOptions:GTEnumeratorOptionsTimeSort]; - - BOOL success = [enumerator pushSHA:self.SHA error:error]; - if (!success) return nil; - - success = [enumerator hideSHA:mergeBase.SHA error:error]; - if (!success) return nil; - + GTEnumerator *enumerator = [self.repository enumerateUniqueCommitsUpToOID:self.OID relativeToOID:otherBranch.OID error:error]; return [enumerator allObjectsWithError:error]; } @@ -223,19 +210,7 @@ - (GTBranch *)reloadedBranchWithError:(NSError **)error { } - (BOOL)calculateAhead:(size_t *)ahead behind:(size_t *)behind relativeTo:(GTBranch *)branch error:(NSError **)error { - if (branch == nil) { - *ahead = 0; - *behind = 0; - return YES; - } - - int errorCode = git_graph_ahead_behind(ahead, behind, self.repository.git_repository, self.reference.git_oid, branch.reference.git_oid); - if (errorCode != GIT_OK && error != NULL) { - *error = [NSError git_errorFor:errorCode description:@"Failed to calculate ahead/behind count of %@ relative to %@", self, branch]; - return NO; - } - - return YES; + return [self.repository calculateAhead:ahead behind:behind ofOID:self.OID relativeToOID:branch.OID error:error]; } @end diff --git a/ObjectiveGit/GTReference.h b/ObjectiveGit/GTReference.h index c97d7f96a..d6965d650 100644 --- a/ObjectiveGit/GTReference.h +++ b/ObjectiveGit/GTReference.h @@ -79,8 +79,8 @@ typedef NS_OPTIONS(NSInteger, GTReferenceType) { /// The last direct reference in a chain @property (nonatomic, readonly, copy) GTReference *resolvedReference; -/// The SHA of the target object -@property (nonatomic, readonly, copy) NSString *targetSHA; +/// The OID of the target object. +@property (nonatomic, readonly, copy) GTOID *targetOID; /// Updates the on-disk reference to point to the target and returns the updated /// reference. diff --git a/ObjectiveGit/GTReference.m b/ObjectiveGit/GTReference.m index 7f667cc2f..c3100655e 100644 --- a/ObjectiveGit/GTReference.m +++ b/ObjectiveGit/GTReference.m @@ -169,8 +169,8 @@ - (GTReference *)resolvedReference { return [self.class referenceByResolvingSymbolicReference:self error:NULL]; } -- (NSString *)targetSHA { - return [self.resolvedTarget SHA]; +- (GTOID *)targetOID { + return [self.resolvedTarget OID]; } - (GTReference *)referenceByUpdatingTarget:(NSString *)newTarget message:(NSString *)message error:(NSError **)error { diff --git a/ObjectiveGit/GTRepository.h b/ObjectiveGit/GTRepository.h index 950406491..11c5df28f 100644 --- a/ObjectiveGit/GTRepository.h +++ b/ObjectiveGit/GTRepository.h @@ -498,4 +498,16 @@ extern NSString * const GTRepositoryInitOptionsOriginURLString; /// distinguished using the value of `success`. - (GTFilterList *)filterListWithPath:(NSString *)path blob:(GTBlob *)blob mode:(GTFilterSourceMode)mode options:(GTFilterListOptions)options success:(BOOL *)success error:(NSError **)error; +/// Creates an enumerator for finding all commits in the history of `headOID` +/// that do not exist in the history of `baseOID`. +/// +/// Returns the created enumerator upon success, or `nil` if an error occurred. +- (GTEnumerator *)enumerateUniqueCommitsUpToOID:(GTOID *)headOID relativeToOID:(GTOID *)baseOID error:(NSError **)error; + +/// Calculates how far ahead/behind the commit represented by `headOID` is, +/// relative to the commit represented by `baseOID`. +/// +/// Returns whether `ahead` and `behind` were successfully calculated. +- (BOOL)calculateAhead:(size_t *)ahead behind:(size_t *)behind ofOID:(GTOID *)headOID relativeToOID:(GTOID *)baseOID error:(NSError **)error; + @end diff --git a/ObjectiveGit/GTRepository.m b/ObjectiveGit/GTRepository.m index c60917896..c9f3d6b9b 100644 --- a/ObjectiveGit/GTRepository.m +++ b/ObjectiveGit/GTRepository.m @@ -885,4 +885,36 @@ - (GTFilterList *)filterListWithPath:(NSString *)path blob:(GTBlob *)blob mode:( } } +- (GTEnumerator *)enumerateUniqueCommitsUpToOID:(GTOID *)headOID relativeToOID:(GTOID *)baseOID error:(NSError **)error { + NSParameterAssert(headOID != nil); + NSParameterAssert(baseOID != nil); + + GTCommit *mergeBase = [self mergeBaseBetweenFirstOID:headOID secondOID:baseOID error:error]; + if (mergeBase == nil) return nil; + + GTEnumerator *enumerator = [[GTEnumerator alloc] initWithRepository:self error:error]; + if (enumerator == nil) return nil; + + [enumerator resetWithOptions:GTEnumeratorOptionsTimeSort]; + + if (![enumerator pushSHA:headOID.SHA error:error]) return nil; + if (![enumerator hideSHA:mergeBase.OID.SHA error:error]) return nil; + + return enumerator; +} + +- (BOOL)calculateAhead:(size_t *)ahead behind:(size_t *)behind ofOID:(GTOID *)headOID relativeToOID:(GTOID *)baseOID error:(NSError **)error { + NSParameterAssert(headOID != nil); + NSParameterAssert(baseOID != nil); + + int errorCode = git_graph_ahead_behind(ahead, behind, self.git_repository, headOID.git_oid, baseOID.git_oid); + if (errorCode != GIT_OK) { + if (error != NULL) *error = [NSError git_errorFor:errorCode description:@"Failed to calculate ahead/behind count of %@ relative to %@", headOID, baseOID]; + + return NO; + } + + return YES; +} + @end diff --git a/ObjectiveGitTests/GTEnumeratorSpec.m b/ObjectiveGitTests/GTEnumeratorSpec.m index c88abcc8e..dda0d67b6 100644 --- a/ObjectiveGitTests/GTEnumeratorSpec.m +++ b/ObjectiveGitTests/GTEnumeratorSpec.m @@ -31,7 +31,7 @@ GTReference *HEADRef = [repo headReferenceWithError:NULL]; expect(HEADRef).notTo(beNil()); - [enumerator pushSHA:HEADRef.targetSHA error:NULL]; + [enumerator pushSHA:HEADRef.targetOID.SHA error:NULL]; NSUInteger count = [enumerator allObjects].count; expect(@(count)).to(equal(@3)); expect(error).to(beNil()); diff --git a/ObjectiveGitTests/GTReferenceSpec.m b/ObjectiveGitTests/GTReferenceSpec.m index e8f75d77e..2bf041d77 100644 --- a/ObjectiveGitTests/GTReferenceSpec.m +++ b/ObjectiveGitTests/GTReferenceSpec.m @@ -65,7 +65,7 @@ reference = [repository createReferenceNamed:testRefName fromOID:testRefOID message:nil error:&error]; expect(reference).notTo(beNil()); expect(reference.name).to(equal(testRefName)); - expect(reference.targetSHA).to(equal(testRefOID.SHA)); + expect(reference.targetOID).to(equal(testRefOID)); }); it(@"should be able to be renamed", ^{ @@ -74,7 +74,7 @@ GTReference *renamedRef = [reference referenceByRenaming:newRefName error:NULL]; expect(renamedRef).notTo(beNil()); expect(renamedRef.name).to(equal(newRefName)); - expect(renamedRef.targetSHA).to(equal(testRefOID.SHA)); + expect(renamedRef.targetOID).to(equal(testRefOID)); }); it(@"should be able to change the target", ^{ @@ -83,7 +83,7 @@ GTReference *updatedRef = [reference referenceByUpdatingTarget:newRefTarget message:nil error:NULL]; expect(updatedRef).notTo(beNil()); expect(updatedRef.name).to(equal(testRefName)); - expect(updatedRef.targetSHA).to(equal(newRefTarget)); + expect(updatedRef.targetOID.SHA).to(equal(newRefTarget)); }); }); @@ -119,7 +119,7 @@ void (^expectValidReference)(GTReference *ref, NSString *SHA, GTReferenceType type, NSString *name) = ^(GTReference *ref, NSString *SHA, GTReferenceType type, NSString *name) { expect(ref).notTo(beNil()); - expect(ref.targetSHA).to(equal(SHA)); + expect(ref.targetOID.SHA).to(equal(SHA)); expect(@(ref.referenceType)).to(equal(@(type))); expect(ref.name).to(equal(name)); }; diff --git a/ObjectiveGitTests/GTRemotePushSpec.m b/ObjectiveGitTests/GTRemotePushSpec.m index 1c1b1265d..b84466493 100644 --- a/ObjectiveGitTests/GTRemotePushSpec.m +++ b/ObjectiveGitTests/GTRemotePushSpec.m @@ -23,7 +23,7 @@ GTReference *headReference = [repo headReferenceWithError:nil]; GTEnumerator *commitEnum = [[GTEnumerator alloc] initWithRepository:repo error:nil]; - [commitEnum pushSHA:[headReference targetSHA] error:nil]; + [commitEnum pushSHA:[headReference targetOID].SHA error:nil]; GTCommit *parent = [commitEnum nextObject]; GTCommit *testCommit = [repo createCommitWithTree:testTree message:message parents:@[ parent ] updatingReferenceNamed:headReference.name error:nil]; diff --git a/ObjectiveGitTests/GTRemoteSpec.m b/ObjectiveGitTests/GTRemoteSpec.m index 915cbc509..c08622174 100644 --- a/ObjectiveGitTests/GTRemoteSpec.m +++ b/ObjectiveGitTests/GTRemoteSpec.m @@ -144,7 +144,7 @@ GTReference *headReference = [repo headReferenceWithError:nil]; GTEnumerator *commitEnum = [[GTEnumerator alloc] initWithRepository:repo error:nil]; - [commitEnum pushSHA:[headReference targetSHA] error:nil]; + [commitEnum pushSHA:headReference.targetOID.SHA error:nil]; GTCommit *parent = [commitEnum nextObject]; GTCommit *testCommit = [repo createCommitWithTree:testTree message:message parents:@[parent] updatingReferenceNamed:headReference.name error:nil]; diff --git a/ObjectiveGitTests/GTRepositoryResetSpec.m b/ObjectiveGitTests/GTRepositoryResetSpec.m index 976437b28..99bee463a 100644 --- a/ObjectiveGitTests/GTRepositoryResetSpec.m +++ b/ObjectiveGitTests/GTRepositoryResetSpec.m @@ -68,7 +68,7 @@ GTCommit *commit = [repository lookUpObjectBySHA:resetTargetSHA error:NULL]; expect(commit).notTo(beNil()); - GTCommit *originalHeadCommit = [repository lookUpObjectBySHA:originalHead.targetSHA error:NULL]; + GTCommit *originalHeadCommit = [repository lookUpObjectByOID:originalHead.targetOID error:NULL]; expect(originalHeadCommit).notTo(beNil()); BOOL success = [repository resetToCommit:commit resetType:GTRepositoryResetTypeSoft error:&error]; @@ -77,14 +77,14 @@ GTReference *head = [repository headReferenceWithError:&error]; expect(head).notTo(beNil()); - expect(head.targetSHA).to(equal(resetTargetSHA)); + expect(head.targetOID.SHA).to(equal(resetTargetSHA)); success = [repository resetToCommit:originalHeadCommit resetType:GTRepositoryResetTypeSoft error:&error]; expect(@(success)).to(beTruthy()); expect(error).to(beNil()); head = [repository headReferenceWithError:&error]; - expect(head.targetSHA).to(equal(originalHead.targetSHA)); + expect(head.targetOID).to(equal(originalHead.targetOID)); }); }); diff --git a/ObjectiveGitTests/GTRepositorySpec.m b/ObjectiveGitTests/GTRepositorySpec.m index bab83c79e..589d2e11f 100644 --- a/ObjectiveGitTests/GTRepositorySpec.m +++ b/ObjectiveGitTests/GTRepositorySpec.m @@ -102,7 +102,7 @@ GTReference *head = [repository headReferenceWithError:&error]; expect(head).notTo(beNil()); expect(error).to(beNil()); - expect(head.targetSHA).to(equal(@"36060c58702ed4c2a40832c51758d5344201d89a")); + expect(head.targetOID.SHA).to(equal(@"36060c58702ed4c2a40832c51758d5344201d89a")); expect(@(head.referenceType)).to(equal(@(GTReferenceTypeOid))); }); @@ -120,7 +120,7 @@ GTReference *head = [repository headReferenceWithError:&error]; expect(head).notTo(beNil()); expect(error).to(beNil()); - expect(head.targetSHA).to(equal(@"36060c58702ed4c2a40832c51758d5344201d89a")); + expect(head.targetOID.SHA).to(equal(@"36060c58702ed4c2a40832c51758d5344201d89a")); expect(@(head.referenceType)).to(equal(@(GTReferenceTypeOid))); }); @@ -183,7 +183,7 @@ GTReference *head = [self.bareFixtureRepository headReferenceWithError:&error]; expect(head).notTo(beNil()); expect(error).to(beNil()); - expect(head.targetSHA).to(equal(@"36060c58702ed4c2a40832c51758d5344201d89a")); + expect(head.targetOID.SHA).to(equal(@"36060c58702ed4c2a40832c51758d5344201d89a")); expect(@(head.referenceType)).to(equal(@(GTReferenceTypeOid))); }); @@ -276,13 +276,13 @@ NSString *branchName = @"new-test-branch"; NSError *error = nil; - GTBranch *newBranch = [repository createBranchNamed:branchName fromOID:[[GTOID alloc] initWithSHA:currentBranch.SHA] message:nil error:&error]; + GTBranch *newBranch = [repository createBranchNamed:branchName fromOID:currentBranch.OID message:nil error:&error]; expect(newBranch).notTo(beNil()); expect(error).to(beNil()); expect(newBranch.shortName).to(equal(branchName)); expect(@(newBranch.branchType)).to(equal(@(GTBranchTypeLocal))); - expect(newBranch.SHA).to(equal(currentBranch.SHA)); + expect(newBranch.OID).to(equal(currentBranch.OID)); }); }); @@ -409,7 +409,7 @@ GTCommit *commit = [repository lookUpObjectBySHA:resetTargetSHA error:NULL]; expect(commit).notTo(beNil()); - GTCommit *originalHeadCommit = [repository lookUpObjectBySHA:originalHead.targetSHA error:NULL]; + GTCommit *originalHeadCommit = [repository lookUpObjectByOID:originalHead.targetOID error:NULL]; expect(originalHeadCommit).notTo(beNil()); BOOL success = [repository resetToCommit:commit resetType:GTRepositoryResetTypeSoft error:&error]; @@ -418,14 +418,14 @@ GTReference *head = [repository headReferenceWithError:&error]; expect(head).notTo(beNil()); - expect(head.targetSHA).to(equal(resetTargetSHA)); + expect(head.targetOID.SHA).to(equal(resetTargetSHA)); success = [repository resetToCommit:originalHeadCommit resetType:GTRepositoryResetTypeSoft error:&error]; expect(@(success)).to(beTruthy()); expect(error).to(beNil()); head = [repository headReferenceWithError:&error]; - expect(head.targetSHA).to(equal(originalHead.targetSHA)); + expect(head.targetOID).to(equal(originalHead.targetOID)); }); });