diff --git a/PBGitRepository.h b/PBGitRepository.h index 7b8c9c5..d60fca4 100644 --- a/PBGitRepository.h +++ b/PBGitRepository.h @@ -36,6 +36,7 @@ extern NSString* PBGitRepositoryErrorDomain; - (BOOL) rebaseBranch:(id )branch onRefish:(id )upstream; - (BOOL) createBranch:(NSString *)branchName atRefish:(id )ref; - (BOOL) createTag:(NSString *)tagName message:(NSString *)message atRefish:(id )commitSHA; +- (BOOL) deleteRemote:(PBGitRef *)ref; - (BOOL) deleteRef:(PBGitRef *)ref; - (NSFileHandle*) handleForCommand:(NSString*) cmd; @@ -72,6 +73,11 @@ extern NSString* PBGitRepositoryErrorDomain; - (BOOL) checkRefFormat:(NSString *)refName; - (BOOL) refExists:(PBGitRef *)ref; +- (NSArray *) remotes; +- (BOOL) hasRemotes; +- (PBGitRef *) remoteRefForBranch:(PBGitRef *)branch error:(NSError **)error; +- (NSString *) infoForRemote:(NSString *)remoteName; + - (void) readCurrentBranch; - (PBGitRevSpecifier*) addBranch: (PBGitRevSpecifier*) rev; - (BOOL)removeBranch:(PBGitRevSpecifier *)rev; diff --git a/PBGitRepository.m b/PBGitRepository.m index ed95618..13f8a06 100644 --- a/PBGitRepository.m +++ b/PBGitRepository.m @@ -426,6 +426,60 @@ NSString* PBGitRepositoryErrorDomain = @"GitXErrorDomain"; return nil; } +#pragma mark Remotes + +- (NSArray *) remotes +{ + int retValue = 1; + NSString *remotes = [self outputInWorkdirForArguments:[NSArray arrayWithObject:@"remote"] retValue:&retValue]; + if (retValue || [remotes isEqualToString:@""]) + return nil; + + return [remotes componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; +} + +- (BOOL) hasRemotes +{ + return ([self remotes] != nil); +} + +- (PBGitRef *) remoteRefForBranch:(PBGitRef *)branch error:(NSError **)error +{ + if ([branch isRemote]) + return [branch remoteRef]; + + NSString *branchName = [branch branchName]; + if (branchName) { + NSString *remoteName = [[self config] valueForKeyPath:[NSString stringWithFormat:@"branch.%@.remote", branchName]]; + if (remoteName && ([remoteName isKindOfClass:[NSString class]] && ![remoteName isEqualToString:@""])) { + PBGitRef *remoteRef = [PBGitRef refFromString:[kGitXRemoteRefPrefix stringByAppendingString:remoteName]]; + // check that the remote is a valid ref and exists + if ([self checkRefFormat:[remoteRef ref]] && [self refExists:remoteRef]) + return remoteRef; + } + } + + if (error != NULL) { + NSString *info = [NSString stringWithFormat:@"There is no remote configured for the %@ '%@'.\n\nPlease select a branch from the popup menu, which has a corresponding remote tracking branch set up.\n\nYou can also use a contextual menu to choose a branch by right clicking on its label in the commit history list.", [branch refishType], [branch shortName]]; + *error = [NSError errorWithDomain:PBGitRepositoryErrorDomain code:0 + userInfo:[NSDictionary dictionaryWithObjectsAndKeys: + @"No remote configured for branch", NSLocalizedDescriptionKey, + info, NSLocalizedRecoverySuggestionErrorKey, + nil]]; + } + return nil; +} + +- (NSString *) infoForRemote:(NSString *)remoteName +{ + int retValue = 1; + NSString *output = [self outputInWorkdirForArguments:[NSArray arrayWithObjects:@"remote", @"show", remoteName, nil] retValue:&retValue]; + if (retValue) + return nil; + + return output; +} + #pragma mark Repository commands - (BOOL) checkoutRefish:(id )ref @@ -593,11 +647,43 @@ NSString* PBGitRepositoryErrorDomain = @"GitXErrorDomain"; return YES; } +- (BOOL) deleteRemote:(PBGitRef *)ref +{ + if (!ref || ([ref refishType] != kGitXRemoteType)) + return NO; + + int retValue = 1; + NSArray *arguments = [NSArray arrayWithObjects:@"remote", @"rm", [ref remoteName], nil]; + NSString * output = [self outputForArguments:arguments retValue:&retValue]; + if (retValue) { + NSString *message = [NSString stringWithFormat:@"There was an error deleting the remote: %@\n\n", [ref remoteName]]; + [self.windowController showErrorSheetTitle:@"Delete remote failed!" message:message arguments:arguments output:output]; + return NO; + } + + // remove the remote's branches + NSString *remoteRef = [kGitXRemoteRefPrefix stringByAppendingString:[ref remoteName]]; + for (PBGitRevSpecifier *rev in [branches copy]) { + PBGitRef *branch = [rev ref]; + if ([[branch ref] hasPrefix:remoteRef]) { + [self removeBranch:rev]; + PBGitCommit *commit = [self commitForRef:branch]; + [commit removeRef:branch]; + } + } + + [self reloadRefs]; + return YES; +} + - (BOOL) deleteRef:(PBGitRef *)ref { if (!ref) return NO; + if ([ref refishType] == kGitXRemoteType) + return [self deleteRemote:ref]; + int retValue = 1; NSArray *arguments = [NSArray arrayWithObjects:@"update-ref", @"-d", [ref ref], nil]; NSString * output = [self outputForArguments:arguments retValue:&retValue]; diff --git a/PBRefMenuItem.m b/PBRefMenuItem.m index 376a8cb..6d27972 100644 --- a/PBRefMenuItem.m +++ b/PBRefMenuItem.m @@ -39,36 +39,43 @@ NSMutableArray *items = [NSMutableArray array]; NSString *targetRefName = [ref shortName]; - PBGitCommit *commit = [repo commitForRef:ref]; - BOOL isOnHeadBranch = [commit isOnHeadBranch]; PBGitRef *headRef = [[repo headRef] ref]; NSString *headRefName = [headRef shortName]; BOOL isHead = [ref isEqualToRef:headRef]; + BOOL isOnHeadBranch = isHead ? YES : [repo isRefOnHeadBranch:ref]; - // checkout ref - NSString *checkoutTitle = [@"Checkout " stringByAppendingString:targetRefName]; - [items addObject:[PBRefMenuItem itemWithTitle:checkoutTitle action:@selector(checkout:) enabled:!isHead]]; - [items addObject:[PBRefMenuItem separatorItem]]; + NSString *remoteName = [ref remoteName]; + if (!remoteName && [ref isBranch]) + remoteName = [[repo remoteRefForBranch:ref error:NULL] remoteName]; + BOOL hasRemote = (remoteName ? YES : NO); + BOOL isRemote = ([ref isRemote] && ![ref isRemoteBranch]); - // create branch - [items addObject:[PBRefMenuItem itemWithTitle:@"Create branch…" action:@selector(createBranch:) enabled:YES]]; + if (!isRemote) { + // checkout ref + NSString *checkoutTitle = [@"Checkout " stringByAppendingString:targetRefName]; + [items addObject:[PBRefMenuItem itemWithTitle:checkoutTitle action:@selector(checkout:) enabled:!isHead]]; + [items addObject:[PBRefMenuItem separatorItem]]; - // create tag - [items addObject:[PBRefMenuItem itemWithTitle:@"Create Tag…" action:@selector(createTag:) enabled:YES]]; + // create branch + [items addObject:[PBRefMenuItem itemWithTitle:@"Create branch…" action:@selector(createBranch:) enabled:YES]]; - // view tag info - if ([ref isTag]) - [items addObject:[PBRefMenuItem itemWithTitle:@"View tag info…" action:@selector(showTagInfoSheet:) enabled:YES]]; - [items addObject:[PBRefMenuItem separatorItem]]; + // create tag + [items addObject:[PBRefMenuItem itemWithTitle:@"Create Tag…" action:@selector(createTag:) enabled:YES]]; - // merge ref - NSString *mergeTitle = isOnHeadBranch ? @"Merge" : [NSString stringWithFormat:@"Merge %@ into %@", targetRefName, headRefName]; - [items addObject:[PBRefMenuItem itemWithTitle:mergeTitle action:@selector(merge:) enabled:!isOnHeadBranch]]; + // view tag info + if ([ref isTag]) + [items addObject:[PBRefMenuItem itemWithTitle:@"View tag info…" action:@selector(showTagInfoSheet:) enabled:YES]]; + [items addObject:[PBRefMenuItem separatorItem]]; - // rebase - NSString *rebaseTitle = isOnHeadBranch ? @"Rebase" : [NSString stringWithFormat:@"Rebase %@ on %@", headRefName, targetRefName]; - [items addObject:[PBRefMenuItem itemWithTitle:rebaseTitle action:@selector(rebaseHeadBranch:) enabled:!isOnHeadBranch]]; + // merge ref + NSString *mergeTitle = isOnHeadBranch ? @"Merge" : [NSString stringWithFormat:@"Merge %@ into %@", targetRefName, headRefName]; + [items addObject:[PBRefMenuItem itemWithTitle:mergeTitle action:@selector(merge:) enabled:!isOnHeadBranch]]; + + // rebase + NSString *rebaseTitle = isOnHeadBranch ? @"Rebase" : [NSString stringWithFormat:@"Rebase %@ on %@", headRefName, targetRefName]; + [items addObject:[PBRefMenuItem itemWithTitle:rebaseTitle action:@selector(rebaseHeadBranch:) enabled:!isOnHeadBranch]]; + } // delete ref [items addObject:[PBRefMenuItem separatorItem]];