diff --git a/PBGitCommit.h b/PBGitCommit.h index 6f55b77..3e361e9 100644 --- a/PBGitCommit.h +++ b/PBGitCommit.h @@ -26,6 +26,7 @@ extern NSString * const kGitXCommitType; NSString* details; NSString *_patch; NSArray* parents; + NSString *realSHA; int timestamp; char sign; @@ -33,12 +34,16 @@ extern NSString * const kGitXCommitType; PBGitRepository* repository; } ++ commitWithRepository:(PBGitRepository*)repo andSha:(git_oid)newSha; - initWithRepository:(PBGitRepository *)repo andSha:(git_oid)sha; - (void)addRef:(PBGitRef *)ref; - (void)removeRef:(id)ref; +- (BOOL) hasRef:(PBGitRef *)ref; - (NSString *)realSha; +- (BOOL) isOnSameBranchAs:(PBGitCommit *)other; +- (BOOL) isOnHeadBranch; // - (NSString *) refishName; diff --git a/PBGitCommit.m b/PBGitCommit.m index a8c56ad..28abcda 100644 --- a/PBGitCommit.m +++ b/PBGitCommit.m @@ -54,6 +54,11 @@ NSString * const kGitXCommitType = @"commit"; return &sha; } ++ commitWithRepository:(PBGitRepository*)repo andSha:(git_oid)newSha +{ + return [[[self alloc] initWithRepository:repo andSha:newSha] autorelease]; +} + - initWithRepository:(PBGitRepository*) repo andSha:(git_oid)newSha { details = nil; @@ -64,10 +69,42 @@ NSString * const kGitXCommitType = @"commit"; - (NSString *)realSha { - char *hex = git_oid_mkhex(&sha); - NSString *str = [NSString stringWithUTF8String:hex]; - free(hex); - return str; + if (!realSHA) { + char *hex = git_oid_mkhex(&sha); + realSHA = [NSString stringWithUTF8String:hex]; + free(hex); + } + + return realSHA; +} + +- (BOOL) isOnSameBranchAs:(PBGitCommit *)other +{ + if (!other) + return NO; + + NSString *mySHA = [self realSha]; + NSString *otherSHA = [other realSha]; + + if ([otherSHA isEqualToString:mySHA]) + return YES; + + NSString *commitRange = [NSString stringWithFormat:@"%@..%@", mySHA, otherSHA]; + NSString *parentsOutput = [repository outputForArguments:[NSArray arrayWithObjects:@"rev-list", @"--parents", @"-1", commitRange, nil]]; + if ([parentsOutput isEqualToString:@""]) { + return NO; + } + + NSString *mergeSHA = [repository outputForArguments:[NSArray arrayWithObjects:@"merge-base", mySHA, otherSHA, nil]]; + if ([mergeSHA isEqualToString:mySHA] || [mergeSHA isEqualToString:otherSHA]) + return YES; + + return NO; +} + +- (BOOL) isOnHeadBranch +{ + return [self isOnSameBranchAs:[repository headCommit]]; } // FIXME: Remove this method once it's unused. @@ -108,6 +145,18 @@ NSString * const kGitXCommitType = @"commit"; [self.refs removeObject:ref]; } +- (BOOL) hasRef:(PBGitRef *)ref +{ + if (!self.refs) + return NO; + + for (PBGitRef *existingRef in self.refs) + if ([existingRef isEqualToRef:ref]) + return YES; + + return NO; +} + - (NSMutableArray *)refs { return [[repository refs] objectForKey:[self realSha]]; diff --git a/PBGitRepository.h b/PBGitRepository.h index 93c38c9..c8bd680 100644 --- a/PBGitRepository.h +++ b/PBGitRepository.h @@ -14,6 +14,7 @@ extern NSString* PBGitRepositoryErrorDomain; @class PBGitWindowController; +@class PBGitCommit; @interface PBGitRepository : NSDocument { PBGitRevList* revisionList; @@ -51,6 +52,15 @@ extern NSString* PBGitRepositoryErrorDomain; - (void) addRef:(PBGitRef *)ref fromParameters:(NSArray *)params; - (void) lazyReload; - (PBGitRevSpecifier*) headRef; +- (NSString *) headSHA; +- (PBGitCommit *) headCommit; +- (NSString *) shaForRef:(PBGitRef *)ref; +- (PBGitCommit *) commitForRef:(PBGitRef *)ref; +- (PBGitCommit *) commitForSHA:(NSString *)sha; +- (BOOL) isSHAOnHeadBranch:(NSString *)testSHA; +- (BOOL) isRefOnHeadBranch:(PBGitRef *)testRef; +- (BOOL) checkRefFormat:(NSString *)refName; +- (BOOL) refExists:(PBGitRef *)ref; - (void) readCurrentBranch; - (PBGitRevSpecifier*) addBranch: (PBGitRevSpecifier*) rev; diff --git a/PBGitRepository.m b/PBGitRepository.m index 2e74040..477d15b 100644 --- a/PBGitRepository.m +++ b/PBGitRepository.m @@ -281,6 +281,105 @@ NSString* PBGitRepositoryErrorDomain = @"GitXErrorDomain"; return _headRef; } + +- (NSString *) headSHA +{ + return [self shaForRef:[[self headRef] ref]]; +} + +- (PBGitCommit *) headCommit +{ + return [self commitForSHA:[self headSHA]]; +} + +- (NSString *) shaForRef:(PBGitRef *)ref +{ + if (!ref) + return nil; + + for (NSString *sha in refs) + for (PBGitRef *existingRef in [refs objectForKey:sha]) + if ([existingRef isEqualToRef:ref]) + return sha; + + int retValue = 1; + NSArray *args = [NSArray arrayWithObjects:@"rev-list", @"-1", [ref ref], nil]; + NSString *shaForRef = [self outputInWorkdirForArguments:args retValue:&retValue]; + if (retValue || [shaForRef isEqualToString:@""]) + return nil; + + return shaForRef; +} + +- (PBGitCommit *) commitForRef:(PBGitRef *)ref +{ + if (!ref) + return nil; + + return [self commitForSHA:[self shaForRef:ref]]; +} + +- (PBGitCommit *) commitForSHA:(NSString *)sha +{ + if (!sha) + return nil; + NSArray *revList = [self.revisionList.commits copy]; + + for (PBGitCommit *commit in revList) + if ([[commit realSha] isEqualToString:sha]) + return commit; + + return nil; +} + +- (BOOL) isSHAOnHeadBranch:(NSString *)testSHA +{ + if (!testSHA) + return NO; + + NSString *headSHA = [self headSHA]; + + if ([testSHA isEqualToString:headSHA]) + return YES; + + NSString *commitRange = [NSString stringWithFormat:@"%@..%@", testSHA, headSHA]; + NSString *parentsOutput = [self outputForArguments:[NSArray arrayWithObjects:@"rev-list", @"--parents", @"-1", commitRange, nil]]; + if ([parentsOutput isEqualToString:@""]) { + return NO; + } + + NSString *mergeSHA = [self outputForArguments:[NSArray arrayWithObjects:@"merge-base", testSHA, headSHA, nil]]; + if ([mergeSHA isEqualToString:testSHA] || [mergeSHA isEqualToString:headSHA]) + return YES; + + return NO; +} + +- (BOOL) isRefOnHeadBranch:(PBGitRef *)testRef +{ + if (!testRef) + return NO; + + return [self isSHAOnHeadBranch:[self shaForRef:testRef]]; +} + +- (BOOL) checkRefFormat:(NSString *)refName +{ + int retValue = 1; + [self outputInWorkdirForArguments:[NSArray arrayWithObjects:@"check-ref-format", refName, nil] retValue:&retValue]; + if (retValue) + return NO; + return YES; +} + +- (BOOL) refExists:(PBGitRef *)ref +{ + int retValue = 1; + NSString *output = [self outputInWorkdirForArguments:[NSArray arrayWithObjects:@"for-each-ref", [ref ref], nil] retValue:&retValue]; + if (retValue || [output isEqualToString:@""]) + return NO; + return YES; +} // Returns either this object, or an existing, equal object - (PBGitRevSpecifier*) addBranch: (PBGitRevSpecifier*) rev diff --git a/PBGitRevSpecifier.h b/PBGitRevSpecifier.h index 0461908..bc2724c 100644 --- a/PBGitRevSpecifier.h +++ b/PBGitRevSpecifier.h @@ -20,10 +20,13 @@ - (BOOL) isSimpleRef; - (NSString*) simpleRef; +- (PBGitRef *) ref; - (BOOL) hasPathLimiter; - (BOOL) hasLeftRight; - (BOOL) isEqualTo: (PBGitRevSpecifier*) other; +- (BOOL) isAllBranchesRev; +- (BOOL) isLocalBranchesRev; + (PBGitRevSpecifier *)allBranchesRevSpec; + (PBGitRevSpecifier *)localBranchesRevSpec; diff --git a/PBGitRevSpecifier.m b/PBGitRevSpecifier.m index 0fe9093..529275d 100644 --- a/PBGitRevSpecifier.m +++ b/PBGitRevSpecifier.m @@ -59,6 +59,14 @@ return [parameters objectAtIndex:0]; } +- (PBGitRef *) ref +{ + if (![self isSimpleRef]) + return nil; + + return [PBGitRef refFromString:[self simpleRef]]; +} + - (NSString*) description { if (description) @@ -95,6 +103,16 @@ (!description || [description isEqualToString:other.description])); } +- (BOOL) isAllBranchesRev +{ + return [self isEqualTo:[PBGitRevSpecifier allBranchesRevSpec]]; +} + +- (BOOL) isLocalBranchesRev +{ + return [self isEqualTo:[PBGitRevSpecifier localBranchesRevSpec]]; +} + - (void) encodeWithCoder:(NSCoder *)coder { [coder encodeObject:description forKey:@"Description"];