Skip to content

Worktree support #642

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

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion ObjectiveGit/GTBlameHunk.m
Original file line number Diff line number Diff line change
@@ -39,7 +39,9 @@ - (GTSignature *)finalSignature {
}

- (NSString *)originalPath {
return @(self.git_blame_hunk.orig_path);
NSString *path = @(self.git_blame_hunk.orig_path);
NSAssert(path, @"string was nil");
return path;
}

- (BOOL)isBoundary {
5 changes: 4 additions & 1 deletion ObjectiveGit/GTConfiguration.m
Original file line number Diff line number Diff line change
@@ -112,7 +112,10 @@ - (BOOL)deleteValueForKey:(NSString *)key error:(NSError **)error {
static int configCallback(const git_config_entry *entry, void *payload) {
NSMutableArray *configurationKeysArray = (__bridge NSMutableArray *)payload;

[configurationKeysArray addObject:@(entry->name)];
NSString *name = @(entry->name);
NSCAssert(name, @"string was nil");

[configurationKeysArray addObject:name];

return 0;
}
5 changes: 3 additions & 2 deletions ObjectiveGit/GTDiffFile.m
Original file line number Diff line number Diff line change
@@ -22,8 +22,9 @@ - (instancetype)initWithGitDiffFile:(git_diff_file)file {
self = [super init];
if (self == nil) return nil;

_path = @(file.path);
if (_path == nil) return nil;
NSString *path = @(file.path);
if (path == nil) return nil;
_path = path;

_git_diff_file = file;
_size = (NSUInteger)file.size;
11 changes: 7 additions & 4 deletions ObjectiveGit/GTFilterSource.m
Original file line number Diff line number Diff line change
@@ -27,10 +27,13 @@ - (instancetype)initWithGitFilterSource:(const git_filter_source *)source {
self = [super init];
if (self == nil) return nil;

const char *path = git_repository_workdir(git_filter_source_repo(source));
_repositoryURL = [NSURL fileURLWithPath:@(path)];

_path = @(git_filter_source_path(source));
NSString *path = @(git_repository_workdir(git_filter_source_repo(source)));
NSAssert(path, @"workdir was nil");
_repositoryURL = [NSURL fileURLWithPath:path];

path = @(git_filter_source_path(source));
NSAssert(path, @"path was nil");
_path = path;

const git_oid *gitOid = git_filter_source_id(source);
if (gitOid != NULL) _OID = [[GTOID alloc] initWithGitOid:gitOid];
4 changes: 3 additions & 1 deletion ObjectiveGit/GTIndexEntry.m
Original file line number Diff line number Diff line change
@@ -74,7 +74,9 @@ - (instancetype)initWithGitIndexEntry:(const git_index_entry *)entry {
#pragma mark Properties

- (NSString *)path {
return @(self.git_index_entry->path);
NSString *path = @(self.git_index_entry->path);
NSAssert(path, @"path is nil");
return path;
}

- (int)flags {
4 changes: 3 additions & 1 deletion ObjectiveGit/GTNote.m
Original file line number Diff line number Diff line change
@@ -42,7 +42,9 @@ - (git_note *)git_note {
}

- (NSString *)note {
return @(git_note_message(self.git_note));
NSString *message = @(git_note_message(self.git_note));
NSAssert(message, @"message is nil");
return message;
}

- (GTSignature *)author {
8 changes: 5 additions & 3 deletions ObjectiveGit/GTReference.m
Original file line number Diff line number Diff line change
@@ -118,10 +118,12 @@ - (BOOL)isNote {
}

- (NSString *)name {
const char *refName = git_reference_name(self.git_reference);
NSAssert(refName != nil, @"Unexpected nil name");
const char *cRefName = git_reference_name(self.git_reference);
NSAssert(cRefName != nil, @"Unexpected nil name");

return @(refName);
NSString *refName = @(cRefName);
NSAssert(refName, @"refname is nil");
return refName;
}

- (GTReference *)referenceByRenaming:(NSString *)newName error:(NSError **)error {
10 changes: 8 additions & 2 deletions ObjectiveGit/GTRepository+RemoteOperations.m
Original file line number Diff line number Diff line change
@@ -126,9 +126,15 @@ int GTFetchHeadEntriesCallback(const char *ref_name, const char *remote_url, con
GTRepository *repository = entriesPayload->repository;
GTRemoteEnumerateFetchHeadEntryBlock enumerationBlock = entriesPayload->enumerationBlock;

GTReference *reference = [repository lookUpReferenceWithName:@(ref_name) error:NULL];
NSString *refName = @(ref_name);
NSCAssert(refName, @"refName is nil");

GTFetchHeadEntry *entry = [[GTFetchHeadEntry alloc] initWithReference:reference remoteURLString:@(remote_url) targetOID:[GTOID oidWithGitOid:oid] isMerge:(BOOL)is_merge];
NSString *remoteURL = @(remote_url);
NSCAssert(remote_url, @"remoteURL is nil");

GTReference *reference = [repository lookUpReferenceWithName:refName error:NULL];

GTFetchHeadEntry *entry = [[GTFetchHeadEntry alloc] initWithReference:reference remoteURLString:remoteURL targetOID:[GTOID oidWithGitOid:oid] isMerge:(BOOL)is_merge];

BOOL stop = NO;

42 changes: 42 additions & 0 deletions ObjectiveGit/GTRepository+Worktree.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// GTRepository+GTRepository_Worktree.h
// ObjectiveGitFramework
//
// Created by Etienne on 25/07/2017.
// Copyright © 2017 GitHub, Inc. All rights reserved.
//

#import <ObjectiveGit/ObjectiveGit.h>

@class GTWorktree;

NS_ASSUME_NONNULL_BEGIN

@interface GTRepository (Worktree)

/// Is this the worktree of another repository ?
@property (nonatomic, readonly, getter = isWorktree) BOOL worktree;

/// The URL for the underlying repository's git directory.
/// Returns the same as -gitDirectoryURL if this is not a worktree.
@property (nonatomic, readonly, strong) NSURL *commonGitDirectoryURL;

+ (instancetype _Nullable)repositoryWithWorktree:(GTWorktree *)worktree error:(NSError **)error;

- (instancetype _Nullable)initWithWorktree:(GTWorktree *)worktree error:(NSError **)error;

- (GTReference * _Nullable)HEADReferenceInWorktreeWithName:(NSString *)name error:(NSError **)error;

- (BOOL)isHEADDetached:(BOOL *)detached inWorktreeWithName:(NSString *)name error:(NSError **)error;

- (BOOL)setWorkingDirectoryURL:(NSURL *)URL updateGitLink:(BOOL)update error:(NSError **)error;

- (NSArray <NSString *> * _Nullable)worktreeNamesWithError:(NSError **)error;

- (GTWorktree * _Nullable)lookupWorktreeWithName:(NSString *)name error:(NSError **)error;

- (GTWorktree * _Nullable)openWorktree:(NSError **)error;

@end

NS_ASSUME_NONNULL_END
117 changes: 117 additions & 0 deletions ObjectiveGit/GTRepository+Worktree.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
//
// GTRepository+Worktree.m
// ObjectiveGitFramework
//
// Created by Etienne on 25/07/2017.
// Copyright © 2017 GitHub, Inc. All rights reserved.
//

#import "GTRepository+Worktree.h"

@implementation GTRepository (Worktree)

+ (instancetype)repositoryWithWorktree:(GTWorktree *)worktree error:(NSError **)error {
return [[self alloc] initWithWorktree:worktree error:error];
}

- (instancetype)initWithWorktree:(GTWorktree *)worktree error:(NSError **)error {
NSParameterAssert(worktree != nil);

git_repository *repo;
int gitError = git_repository_open_from_worktree(&repo, worktree.git_worktree);
if (gitError != GIT_OK) {
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to open worktree"];
return nil;
}
return [self initWithGitRepository:repo];
}

- (BOOL)isWorktree {
return (BOOL)git_repository_is_worktree(self.git_repository);
}

- (NSURL *)commonGitDirectoryURL {
const char *cPath = git_repository_commondir(self.git_repository);
NSAssert(cPath, @"commondir is nil");

NSString *path = @(cPath);
NSAssert(path, @"commondir is nil");
return [NSURL fileURLWithPath:path isDirectory:YES];
}

- (GTReference *)HEADReferenceInWorktreeWithName:(NSString *)name error:(NSError **)error {
NSParameterAssert(name != nil);

git_reference *ref;
int gitError = git_repository_head_for_worktree(&ref, self.git_repository, name.UTF8String);
if (gitError != GIT_OK) {
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to resolve HEAD in worktree"];
return nil;
}

return [[GTReference alloc] initWithGitReference:ref repository:self];
}

- (BOOL)isHEADDetached:(BOOL *)detached inWorktreeWithName:(NSString *)name error:(NSError **)error {
NSParameterAssert(detached != nil);
NSParameterAssert(name != nil);

int gitError = git_repository_head_detached_for_worktree(self.git_repository, name.UTF8String);
if (gitError < 0) {
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to resolve HEAD in worktree"];
return NO;
}

*detached = (gitError == 1);

return YES;
}

- (BOOL)setWorkingDirectoryURL:(NSURL *)URL updateGitLink:(BOOL)update error:(NSError **)error {
NSParameterAssert(URL != nil);

int gitError = git_repository_set_workdir(self.git_repository, URL.fileSystemRepresentation, update);
if (gitError != GIT_OK) {
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to set workdir"];
return NO;
}

return YES;
}

- (NSArray<NSString *> *)worktreeNamesWithError:(NSError **)error {
git_strarray names;
int gitError = git_worktree_list(&names, self.git_repository);
if (gitError != GIT_OK) {
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to load worktree names"];
return nil;
}

return [NSArray git_arrayWithStrarray:names];
}

- (GTWorktree *)lookupWorktreeWithName:(NSString *)name error:(NSError **)error {
NSParameterAssert(name != nil);

git_worktree *worktree;
int gitError = git_worktree_lookup(&worktree, self.git_repository, name.UTF8String);
if (gitError != GIT_OK) {
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to lookup worktree"];
return nil;
}

return [[GTWorktree alloc] initWithGitWorktree:worktree];
}

- (GTWorktree *)openWorktree:(NSError **)error {
git_worktree *worktree;
int gitError = git_worktree_open_from_repository(&worktree, self.git_repository);
if (gitError != GIT_OK) {
if (error) *error = [NSError git_errorFor:gitError description:@"Failed to open worktree"];
return nil;
}

return [[GTWorktree alloc] initWithGitWorktree:worktree];
}

@end
2 changes: 1 addition & 1 deletion ObjectiveGit/GTRepository.h
Original file line number Diff line number Diff line change
@@ -156,7 +156,7 @@ typedef NS_ENUM(NSInteger, GTRepositoryStateType) {
/// Returns nil for a bare repository.
@property (nonatomic, readonly, strong) NSURL * _Nullable fileURL;
/// The file URL for the repository's .git directory.
@property (nonatomic, readonly, strong) NSURL * _Nullable gitDirectoryURL;
@property (nonatomic, readonly, strong) NSURL *gitDirectoryURL;

/// Is this a bare repository (one without a working directory)?
@property (nonatomic, readonly, getter = isBare) BOOL bare;
20 changes: 13 additions & 7 deletions ObjectiveGit/GTRepository.m
Original file line number Diff line number Diff line change
@@ -637,18 +637,22 @@ - (NSArray *)referenceNamesWithError:(NSError **)error {
}

- (NSURL *)fileURL {
const char *path = git_repository_workdir(self.git_repository);
const char *cPath = git_repository_workdir(self.git_repository);
// bare repository, you may be looking for gitDirectoryURL
if (path == NULL) return nil;
if (cPath == NULL) return nil;

return [NSURL fileURLWithPath:@(path) isDirectory:YES];
NSString *path = @(cPath);
NSAssert(path, @"workdir is nil");
return [NSURL fileURLWithPath:path isDirectory:YES];
}

- (NSURL *)gitDirectoryURL {
const char *path = git_repository_path(self.git_repository);
if (path == NULL) return nil;
const char *cPath = git_repository_path(self.git_repository);
NSAssert(cPath, @"gitdirectory is nil");

return [NSURL fileURLWithPath:@(path) isDirectory:YES];
NSString *path = @(cPath);
NSAssert(path, @"gitdirectory is nil");
return [NSURL fileURLWithPath:path isDirectory:YES];
}

- (BOOL)isBare {
@@ -737,7 +741,9 @@ static int submoduleEnumerationCallback(git_submodule *git_submodule, const char

NSError *error;
// Use -submoduleWithName:error: so that we get a git_submodule that we own.
GTSubmodule *submodule = [info->parentRepository submoduleWithName:@(name) error:&error];
NSString *submoduleName = @(name);
NSCAssert(submoduleName, @"submodule name is nil");
GTSubmodule *submodule = [info->parentRepository submoduleWithName:submoduleName error:&error];

BOOL stop = NO;
info->block(submodule, error, &stop);
15 changes: 12 additions & 3 deletions ObjectiveGit/GTSubmodule.m
Original file line number Diff line number Diff line change
@@ -62,21 +62,30 @@ - (NSString *)name {
const char *cName = git_submodule_name(self.git_submodule);
NSAssert(cName != NULL, @"Unexpected nil submodule name");

return @(cName);
NSString *name = @(cName);
NSAssert(name, @"name is nil");

return name;
}

- (NSString *)path {
const char *cPath = git_submodule_path(self.git_submodule);
NSAssert(cPath != NULL, @"Unexpected nil submodule path");

return @(cPath);
NSString *path = @(cPath);
NSAssert(path, @"message is nil");

return path;
}

- (NSString *)URLString {
const char *cURL = git_submodule_url(self.git_submodule);
NSAssert(cURL != NULL, @"Unexpected nil submodule URL");

return @(cURL);
NSString *URL = @(cURL);
NSAssert(URL, @"URL is nil");

return URL;
}

#pragma mark Lifecycle
8 changes: 6 additions & 2 deletions ObjectiveGit/GTTag.m
Original file line number Diff line number Diff line change
@@ -47,11 +47,15 @@ - (NSString *)description {
#pragma mark API

- (NSString *)message {
return @(git_tag_message(self.git_tag));
NSString *message = @(git_tag_message(self.git_tag));
NSAssert(message, @"message is nil");
return message;
}

- (NSString *)name {
return @(git_tag_name(self.git_tag));
NSString *name = @(git_tag_name(self.git_tag));
NSAssert(name, @"message is nil");
return name;
}

- (GTObject *)target {
4 changes: 3 additions & 1 deletion ObjectiveGit/GTTreeEntry.m
Original file line number Diff line number Diff line change
@@ -94,7 +94,9 @@ + (instancetype)entryWithEntry:(const git_tree_entry *)theEntry parentTree:(GTTr
}

- (NSString *)name {
return @(git_tree_entry_name(self.git_tree_entry));
NSString *name = @(git_tree_entry_name(self.git_tree_entry));
NSAssert(name, @"name was nil");
return name;
}

- (NSInteger)attributes {
Loading