diff --git a/External/libgit2 b/External/libgit2 index 211e117a0..2fcb8705e 160000 --- a/External/libgit2 +++ b/External/libgit2 @@ -1 +1 @@ -Subproject commit 211e117a0590583a720c53172406f34186c543bd +Subproject commit 2fcb8705e584ca61f6c4657525c9d2713f6a39d2 diff --git a/ObjectiveGit/GTCheckoutOptions.h b/ObjectiveGit/GTCheckoutOptions.h new file mode 100644 index 000000000..ae3897e03 --- /dev/null +++ b/ObjectiveGit/GTCheckoutOptions.h @@ -0,0 +1,103 @@ +// +// GTCheckoutOptions.h +// ObjectiveGitFramework +// +// Created by Etienne on 10/04/2015. +// Copyright (c) 2015 GitHub, Inc. All rights reserved. +// + +#import +#import "git2/checkout.h" + +@class GTDiffFile; + +NS_ASSUME_NONNULL_BEGIN + +/// Checkout strategies used by the various -checkout... methods +/// See git_checkout_strategy_t +typedef NS_OPTIONS(NSInteger, GTCheckoutStrategyType) { + GTCheckoutStrategyNone = GIT_CHECKOUT_NONE, + GTCheckoutStrategySafe = GIT_CHECKOUT_SAFE, + GTCheckoutStrategyForce = GIT_CHECKOUT_FORCE, + GTCheckoutStrategyRecreateMissing = GIT_CHECKOUT_RECREATE_MISSING, + GTCheckoutStrategyAllowConflicts = GIT_CHECKOUT_ALLOW_CONFLICTS, + GTCheckoutStrategyRemoveUntracked = GIT_CHECKOUT_REMOVE_UNTRACKED, + GTCheckoutStrategyRemoveIgnored = GIT_CHECKOUT_REMOVE_IGNORED, + GTCheckoutStrategyUpdateOnly = GIT_CHECKOUT_UPDATE_ONLY, + GTCheckoutStrategyDontUpdateIndex = GIT_CHECKOUT_DONT_UPDATE_INDEX, + GTCheckoutStrategyNoRefresh = GIT_CHECKOUT_NO_REFRESH, + GTCheckoutStrategySkipUnmerged = GIT_CHECKOUT_SKIP_UNMERGED, + GTCheckoutStrategyUseOurs = GIT_CHECKOUT_USE_OURS, + GTCheckoutStrategyUseTheirs = GIT_CHECKOUT_USE_THEIRS, + GTCheckoutStrategyDisablePathspecMatch = GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH, + GTCheckoutStrategySkipLockedDirectories = GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES, + GTCheckoutStrategyDoNotOverwriteIgnored = GIT_CHECKOUT_DONT_OVERWRITE_IGNORED, + GTCheckoutStrategyConflictStyleMerge = GIT_CHECKOUT_CONFLICT_STYLE_MERGE, + GTCheckoutStrategyCoflictStyleDiff3 = GIT_CHECKOUT_CONFLICT_STYLE_DIFF3, + GTCheckoutStrategyDoNotRemoveExisting = GIT_CHECKOUT_DONT_REMOVE_EXISTING, + GTCheckoutStrategyDoNotWriteIndex = GIT_CHECKOUT_DONT_WRITE_INDEX, +}; + +/// Checkout notification flags used by the various -checkout... methods +/// See git_checkout_notify_t +typedef NS_OPTIONS(NSInteger, GTCheckoutNotifyFlags) { + GTCheckoutNotifyNone = GIT_CHECKOUT_NOTIFY_NONE, + GTCheckoutNotifyConflict = GIT_CHECKOUT_NOTIFY_CONFLICT, + GTCheckoutNotifyDirty = GIT_CHECKOUT_NOTIFY_DIRTY, + GTCheckoutNotifyUpdated = GIT_CHECKOUT_NOTIFY_UPDATED, + GTCheckoutNotifyUntracked = GIT_CHECKOUT_NOTIFY_UNTRACKED, + GTCheckoutNotifyIgnored = GIT_CHECKOUT_NOTIFY_IGNORED, + + GTCheckoutNotifyAll = GIT_CHECKOUT_NOTIFY_ALL, +}; + +@interface GTCheckoutOptions : NSObject + +/// Create a checkout options object. +/// +/// Since there are many places where we can checkout data, this object allow us +/// to centralize all the various behaviors that checkout allow. +/// +/// @param strategy The checkout strategy to use. +/// @param notifyFlags The checkout events that will be notified via `notifyBlock`. +/// @param progressBlock A block that will be called for each checkout step. +/// @param notifyBlock A block that will be called for each event, @see `notifyFlags`. +/// +/// @return A newly-initialized GTCheckoutOptions object. ++ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy notifyFlags:(GTCheckoutNotifyFlags)notifyFlags progressBlock:(nullable void (^)(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps))progressBlock notifyBlock:(nullable int (^)(GTCheckoutNotifyFlags why, NSString *path, GTDiffFile *baseline, GTDiffFile *target, GTDiffFile *workdir))notifyBlock; + +/// Create a checkout options object. +/// @see +checkoutOptionsWithStrategy:notifyFlags:progressBlock:notifyBlock: ++ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy notifyFlags:(GTCheckoutNotifyFlags)notifyFlags notifyBlock:(int (^)(GTCheckoutNotifyFlags why, NSString *path, GTDiffFile *baseline, GTDiffFile *target, GTDiffFile *workdir))notifyBlock; + +/// Create a checkout options object. +/// @see +checkoutOptionsWithStrategy:notifyFlags:progressBlock:notifyBlock: ++ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy progressBlock:(void (^)(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps))progressBlock; + +/// Create a checkout options object. +/// @see +checkoutOptionsWithStrategy:notifyFlags:progressBlock:notifyBlock: ++ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy; + +/// Get the underlying git_checkout_options struct. +/// +/// @return <#return value description#> +- (git_checkout_options *)git_checkoutOptions NS_RETURNS_INNER_POINTER; + +/// The checkout strategy to use. +@property (assign) GTCheckoutStrategyType strategy; + +/// The checkout progress block that was passed in. +@property (copy) void (^progressBlock)(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps); + +/// The notification flags currently enabled. +@property (assign) GTCheckoutNotifyFlags notifyFlags; + +/// The checkout notification block that was passed in. +@property (copy) int (^notifyBlock)(GTCheckoutNotifyFlags why, NSString *path, GTDiffFile *baseline, GTDiffFile *target, GTDiffFile *workdir); + +/// An array of strings used to restrict what will be checked out. +@property (copy) NSArray *pathSpecs; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ObjectiveGit/GTCheckoutOptions.m b/ObjectiveGit/GTCheckoutOptions.m new file mode 100644 index 000000000..f4c18ed5e --- /dev/null +++ b/ObjectiveGit/GTCheckoutOptions.m @@ -0,0 +1,100 @@ +// +// GTCheckoutOptions.m +// ObjectiveGitFramework +// +// Created by Etienne on 10/04/2015. +// Copyright (c) 2015 GitHub, Inc. All rights reserved. +// + +#import "GTCheckoutOptions.h" +#import "GTDiffFile.h" +#import "NSError+Git.h" +#import "NSArray+StringArray.h" +#import "git2.h" + +// The type of block set in progressBlock for progress reporting +typedef void (^GTCheckoutProgressBlock)(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps); + +// The type of block set in notifyBlock for notification reporting +typedef int (^GTCheckoutNotifyBlock)(GTCheckoutNotifyFlags why, NSString *path, GTDiffFile * __nullable baseline, GTDiffFile * __nullable target, GTDiffFile * __nullable workdir); + + +@interface GTCheckoutOptions () { + git_checkout_options _git_checkoutOptions; +} +@end + +@implementation GTCheckoutOptions + ++ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy notifyFlags:(GTCheckoutNotifyFlags)notifyFlags progressBlock:(nullable GTCheckoutProgressBlock)progressBlock notifyBlock:(nullable GTCheckoutNotifyBlock)notifyBlock { + GTCheckoutOptions *options = [self checkoutOptionsWithStrategy:strategy]; + options.notifyFlags = notifyFlags; + options.notifyBlock = notifyBlock; + options.progressBlock = progressBlock; + return options; +} + ++ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy progressBlock:(GTCheckoutProgressBlock)progressBlock { + NSParameterAssert(progressBlock != nil); + GTCheckoutOptions *options = [self checkoutOptionsWithStrategy:strategy]; + options.progressBlock = progressBlock; + return options; +} + ++ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy notifyFlags:(GTCheckoutNotifyFlags)notifyFlags notifyBlock:(GTCheckoutNotifyBlock)notifyBlock { + NSParameterAssert(notifyBlock != nil); + return [self checkoutOptionsWithStrategy:strategy notifyFlags:notifyFlags progressBlock:nil notifyBlock:notifyBlock]; +} + ++ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy { + GTCheckoutOptions *options = [[self alloc] init]; + options.strategy = strategy; + return options; +} + +- (instancetype)init { + self = [super init]; + if (self == nil) return nil; + + _git_checkoutOptions.version = GIT_CHECKOUT_OPTIONS_VERSION; + + return self; +} + +static void GTCheckoutProgressCallback(const char *path, size_t completedSteps, size_t totalSteps, void *payload) { + if (payload == NULL) return; + void (^block)(NSString *, NSUInteger, NSUInteger) = (__bridge id)payload; + NSString *nsPath = (path != NULL ? @(path) : nil); + block(nsPath, completedSteps, totalSteps); +} + +static int GTCheckoutNotifyCallback(git_checkout_notify_t why, const char *path, const git_diff_file *baseline, const git_diff_file *target, const git_diff_file *workdir, void *payload) { + if (payload == NULL) return 0; + GTCheckoutNotifyBlock block = (__bridge id)payload; + NSString *nsPath = (path != NULL ? @(path) : nil); + GTDiffFile *gtBaseline = (baseline != NULL ? [[GTDiffFile alloc] initWithGitDiffFile:*baseline] : nil); + GTDiffFile *gtTarget = (target != NULL ? [[GTDiffFile alloc] initWithGitDiffFile:*target] : nil); + GTDiffFile *gtWorkdir = (workdir != NULL ? [[GTDiffFile alloc] initWithGitDiffFile:*workdir] : nil); + return block((GTCheckoutNotifyFlags)why, nsPath, gtBaseline, gtTarget, gtWorkdir); +} + +- (git_checkout_options *)git_checkoutOptions { + _git_checkoutOptions.checkout_strategy = self.strategy; + + if (self.progressBlock != nil) { + _git_checkoutOptions.progress_cb = GTCheckoutProgressCallback; + _git_checkoutOptions.progress_payload = (__bridge void *)self.progressBlock; + } + + if (self.notifyBlock != nil) { + _git_checkoutOptions.notify_cb = GTCheckoutNotifyCallback; + _git_checkoutOptions.notify_flags = self.notifyFlags; + _git_checkoutOptions.notify_payload = (__bridge void *)self.notifyBlock; + } + + _git_checkoutOptions.paths = self.pathSpecs.git_strarray; + + return &_git_checkoutOptions; +} + +@end diff --git a/ObjectiveGit/GTRepository+Merging.m b/ObjectiveGit/GTRepository+Merging.m index bb0c1fbb5..958f53ec6 100644 --- a/ObjectiveGit/GTRepository+Merging.m +++ b/ObjectiveGit/GTRepository+Merging.m @@ -107,8 +107,7 @@ - (BOOL)mergeBranchIntoCurrentBranch:(GTBranch *)branch withError:(NSError **)er // Fast-forward branch NSString *message = [NSString stringWithFormat:@"merge %@: Fast-forward", branch.name]; GTReference *reference = [localBranch.reference referenceByUpdatingTarget:remoteCommit.SHA message:message error:error]; - BOOL checkoutSuccess = [self checkoutReference:reference strategy:GTCheckoutStrategyForce error:error progressBlock:nil]; - + BOOL checkoutSuccess = [self checkoutReference:reference options:[GTCheckoutOptions checkoutOptionsWithStrategy:GTCheckoutStrategyForce] error:error]; return checkoutSuccess; } else if (analysis & GTMergeAnalysisNormal) { // Do normal merge @@ -164,7 +163,7 @@ - (BOOL)mergeBranchIntoCurrentBranch:(GTBranch *)branch withError:(NSError **)er return NO; } - BOOL success = [self checkoutReference:localBranch.reference strategy:GTCheckoutStrategyForce error:error progressBlock:nil]; + BOOL success = [self checkoutReference:localBranch.reference options:[GTCheckoutOptions checkoutOptionsWithStrategy:GTCheckoutStrategyForce] error:error]; return success; } diff --git a/ObjectiveGit/GTRepository+References.h b/ObjectiveGit/GTRepository+References.h index 6809d9876..89ba93ca3 100644 --- a/ObjectiveGit/GTRepository+References.h +++ b/ObjectiveGit/GTRepository+References.h @@ -6,7 +6,7 @@ // Copyright (c) 2015 GitHub, Inc. All rights reserved. // -#import "GTrepository.h" +#import "GTRepository.h" NS_ASSUME_NONNULL_BEGIN diff --git a/ObjectiveGit/GTRepository+RemoteOperations.m b/ObjectiveGit/GTRepository+RemoteOperations.m index 327dbcd30..1d3024ce2 100644 --- a/ObjectiveGit/GTRepository+RemoteOperations.m +++ b/ObjectiveGit/GTRepository+RemoteOperations.m @@ -270,7 +270,7 @@ - (BOOL)pushRefspecs:(NSArray *)refspecs toRemote:(GTRemote *)remote withOptions remote_callbacks.push_transfer_progress = GTRemotePushTransferProgressCallback; remote_callbacks.payload = &connectionInfo, - gitError = git_remote_connect(remote.git_remote, GIT_DIRECTION_PUSH, &remote_callbacks, NULL); + gitError = git_remote_connect(remote.git_remote, GIT_DIRECTION_PUSH, &remote_callbacks, NULL, NULL); if (gitError != GIT_OK) { if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Failed to connect remote"]; return NO; diff --git a/ObjectiveGit/GTRepository+Stashing.h b/ObjectiveGit/GTRepository+Stashing.h index 6169a9aef..0c06cb24c 100644 --- a/ObjectiveGit/GTRepository+Stashing.h +++ b/ObjectiveGit/GTRepository+Stashing.h @@ -35,7 +35,7 @@ typedef NS_ENUM(NSInteger, GTRepositoryStashApplyProgress) { GTRepositoryStashApplyProgressAnalyzeIndex = GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX, GTRepositoryStashApplyProgressAnalyzeModified = GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED, GTRepositoryStashApplyProgressAnalyzeUntracked = GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED, - GTRepositoryStashApplyProgressGheckoutUntracked = GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED, + GTRepositoryStashApplyProgressCheckoutUntracked = GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED, GTRepositoryStashApplyProgressCheckoutModified = GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED, GTRepositoryStashApplyProgressDone = GIT_STASH_APPLY_PROGRESS_DONE, }; @@ -64,41 +64,25 @@ NS_ASSUME_NONNULL_BEGIN /// Apply stashed changes (with a default checkout strategy). /// -/// index - The index of the stash to apply. 0 is the latest one. -/// flags - The flags to use when applying the stash. -/// error - If not NULL, set to any error that occurred. +/// index - The index of the stash to apply. 0 is the latest one. +/// flags - The flags to use when applying the stash. +/// options - The options to use when checking out. +/// error - If not NULL, set to any error that occurred. +/// progressBlock - A block that will be executed on each step of the stash application. /// /// Returns YES if the requested stash was successfully applied, NO otherwise. -- (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock; - -/// Apply stashed changes with a set checkout strategy. -/// -/// index - The index of the stash to apply. 0 is the latest one. -/// flags - The flags to use when applying the stash. -/// strategy - The checkout strategy to use when applying the stash. -/// error - If not NULL, set to any error that occurred. -/// -/// Returns YES if the requested stash was successfully applied, NO otherwise. -- (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags strategy:(GTCheckoutStrategyType)strategy error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock; +- (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags checkoutOptions:(nullable GTCheckoutOptions *)options error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock; /// Pop stashed changes (with a default checkout strategy). /// -/// index - The index of the stash to apply. 0 is the most recent stash. -/// flags - The flags to use when applying the stash. -/// error - If not NULL, set to any error that occurred. -/// -/// Returns YES if the requested stash was successfully applied, NO otherwise. -- (BOOL)popStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock; - -/// Pop stashed changes with a set checkout strategy. -/// -/// index - The index of the stash to apply. 0 is the most recent stash. -/// flags - The flags to use when applying the stash. -/// strategy - The checkout strategy to use when applying the stash. -/// error - If not NULL, set to any error that occurred. +/// index - The index of the stash to apply. 0 is the most recent stash. +/// flags - The flags to use when applying the stash. +/// options - The options to use when checking out. +/// error - If not NULL, set to any error that occurred. +/// progressBlock - A block that will be executed on each step of the stash application. /// /// Returns YES if the requested stash was successfully applied, NO otherwise. -- (BOOL)popStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags strategy:(GTCheckoutStrategyType)strategy error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock; +- (BOOL)popStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags checkoutOptions:(nullable GTCheckoutOptions *)options error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock; /// Drop a stash from the repository's list of stashes. /// diff --git a/ObjectiveGit/GTRepository+Stashing.m b/ObjectiveGit/GTRepository+Stashing.m index 2f3a43dc5..981a53d6f 100644 --- a/ObjectiveGit/GTRepository+Stashing.m +++ b/ObjectiveGit/GTRepository+Stashing.m @@ -59,22 +59,20 @@ static int stashApplyProgressCallback(git_stash_apply_progress_t progress, void return (stop ? GIT_EUSER : 0); } -- (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock { - // GTCheckoutStrategyNone may sound odd at first, but this is what was passed in before (de-facto), and libgit2 has a sanity check to set it to GIT_CHECKOUT_SAFE if it's 0. - return [self applyStashAtIndex:index flags:flags strategy:GTCheckoutStrategyNone error:error progressBlock:progressBlock]; -} - -- (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags strategy:(GTCheckoutStrategyType)strategy error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock { +- (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags checkoutOptions:(GTCheckoutOptions *)options error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock { git_stash_apply_options stash_options = GIT_STASH_APPLY_OPTIONS_INIT; stash_options.flags = (git_stash_apply_flags)flags; - stash_options.checkout_options.checkout_strategy = strategy; if (progressBlock != nil) { stash_options.progress_cb = stashApplyProgressCallback; stash_options.progress_payload = (__bridge void *)progressBlock; } + if (options != nil) { + stash_options.checkout_options = *options.git_checkoutOptions; + } + int gitError = git_stash_apply(self.git_repository, index, &stash_options); if (gitError != GIT_OK) { if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Stash apply failed" failureReason:@"The stash at index %ld couldn't be applied.", (unsigned long)index]; @@ -83,21 +81,20 @@ - (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)fl return YES; } -- (BOOL)popStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock { - // GTCheckoutStrategyNone may sound odd at first, but this is what was passed in before (de-facto), and libgit2 has a sanity check to set it to GIT_CHECKOUT_SAFE if it's 0. - return [self popStashAtIndex:index flags:flags strategy:GTCheckoutStrategyNone error:error progressBlock:progressBlock]; -} - -- (BOOL)popStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags strategy:(GTCheckoutStrategyType)strategy error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock { +- (BOOL)popStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags checkoutOptions:(GTCheckoutOptions *)options error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock{ git_stash_apply_options stash_options = GIT_STASH_APPLY_OPTIONS_INIT; stash_options.flags = (git_stash_apply_flags)flags; - stash_options.checkout_options.checkout_strategy = strategy; + if (progressBlock != nil) { stash_options.progress_cb = stashApplyProgressCallback; stash_options.progress_payload = (__bridge void *)progressBlock; } + if (options != nil) { + stash_options.checkout_options = *options.git_checkoutOptions; + } + int gitError = git_stash_pop(self.git_repository, index, &stash_options); if (gitError != GIT_OK) { if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Stash pop failed" failureReason:@"The stash at index %ld couldn't be applied.", (unsigned long)index]; diff --git a/ObjectiveGit/GTRepository.h b/ObjectiveGit/GTRepository.h index 1d9a69b6d..e822b2548 100644 --- a/ObjectiveGit/GTRepository.h +++ b/ObjectiveGit/GTRepository.h @@ -34,6 +34,7 @@ #import "GTObject.h" #import "GTReference.h" #import "GTFilterList.h" +#import "GTCheckoutOptions.h" #import "git2/checkout.h" #import "git2/repository.h" #import "git2/transport.h" @@ -55,35 +56,6 @@ NS_ASSUME_NONNULL_BEGIN -/// Checkout strategies used by the various -checkout... methods -/// See git_checkout_strategy_t -typedef NS_OPTIONS(NSInteger, GTCheckoutStrategyType) { - GTCheckoutStrategyNone = GIT_CHECKOUT_NONE, - GTCheckoutStrategySafe = GIT_CHECKOUT_SAFE, - GTCheckoutStrategyForce = GIT_CHECKOUT_FORCE, - GTCheckoutStrategyAllowConflicts = GIT_CHECKOUT_ALLOW_CONFLICTS, - GTCheckoutStrategyRemoveUntracked = GIT_CHECKOUT_REMOVE_UNTRACKED, - GTCheckoutStrategyRemoveIgnored = GIT_CHECKOUT_REMOVE_IGNORED, - GTCheckoutStrategyUpdateOnly = GIT_CHECKOUT_UPDATE_ONLY, - GTCheckoutStrategyDontUpdateIndex = GIT_CHECKOUT_DONT_UPDATE_INDEX, - GTCheckoutStrategyNoRefresh = GIT_CHECKOUT_NO_REFRESH, - GTCheckoutStrategyDisablePathspecMatch = GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH, - GTCheckoutStrategySkipLockedDirectories = GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES, -}; - -/// Checkout notification flags used by the various -checkout... methods -/// See git_checkout_notify_t -typedef NS_OPTIONS(NSInteger, GTCheckoutNotifyFlags) { - GTCheckoutNotifyNone = GIT_CHECKOUT_NOTIFY_NONE, - GTCheckoutNotifyConflict = GIT_CHECKOUT_NOTIFY_CONFLICT, - GTCheckoutNotifyDirty = GIT_CHECKOUT_NOTIFY_DIRTY, - GTCheckoutNotifyUpdated = GIT_CHECKOUT_NOTIFY_UPDATED, - GTCheckoutNotifyUntracked = GIT_CHECKOUT_NOTIFY_UNTRACKED, - GTCheckoutNotifyIgnored = GIT_CHECKOUT_NOTIFY_IGNORED, - - GTCheckoutNotifyAll = GIT_CHECKOUT_NOTIFY_ALL, -}; - /// Transport flags sent as options to +cloneFromURL... method typedef NS_OPTIONS(NSInteger, GTTransportFlags) { GTTransportFlagsNone = GIT_TRANSPORTFLAGS_NONE @@ -101,6 +73,9 @@ extern NSString * const GTRepositoryCloneOptionsBare; /// Default value is `YES`. extern NSString * const GTRepositoryCloneOptionsCheckout; +/// A `GTCheckoutOptions` object describing how to perform the checkout. +extern NSString * const GTRepositoryCloneCheckoutOptions; + /// A `GTCredentialProvider`, that will be used to authenticate against the /// remote. extern NSString * const GTRepositoryCloneOptionsCredentialProvider; @@ -253,7 +228,7 @@ typedef NS_ENUM(NSInteger, GTRepositoryStateType) { /// options - A dictionary consisting of the options: /// `GTRepositoryCloneOptionsTransportFlags`, /// `GTRepositoryCloneOptionsBare`, -/// `GTRepositoryCloneOptionsCheckout`, +/// `GTRepositoryCloneCheckoutOptions`, /// `GTRepositoryCloneOptionsCredentialProvider`, /// `GTRepositoryCloneOptionsCloneLocal`, /// `GTRepositoryCloneOptionsServerCertificateURL` @@ -265,7 +240,7 @@ typedef NS_ENUM(NSInteger, GTRepositoryStateType) { /// May be NULL. /// /// returns nil (and fills the error parameter) if an error occurred, or a GTRepository object if successful. -+ (nullable instancetype)cloneFromURL:(NSURL *)originURL toWorkingDirectory:(NSURL *)workdirURL options:(nullable NSDictionary *)options error:(NSError **)error transferProgressBlock:(nullable void (^)(const git_transfer_progress *, BOOL *stop))transferProgressBlock checkoutProgressBlock:(nullable void (^) (NSString *__nullable path, NSUInteger completedSteps, NSUInteger totalSteps))checkoutProgressBlock; ++ (nullable instancetype)cloneFromURL:(NSURL *)originURL toWorkingDirectory:(NSURL *)workdirURL options:(nullable NSDictionary *)options error:(NSError **)error transferProgressBlock:(nullable void (^)(const git_transfer_progress *, BOOL *stop))transferProgressBlock; /// Lookup objects in the repo by oid or sha1 - (nullable id)lookUpObjectByOID:(GTOID *)oid objectType:(GTObjectType)type error:(NSError **)error; @@ -536,34 +511,29 @@ typedef NS_ENUM(NSInteger, GTRepositoryStateType) { /// Checkout a commit /// /// targetCommit - The commit to checkout. Must not be nil. -/// strategy - The checkout strategy to use. -/// notifyFlags - Flags that indicate which notifications should cause `notifyBlock` -/// to be called. +/// options - The checkout options to use. Can be nil. /// error - The error if one occurred. Can be NULL. -/// notifyBlock - The block to call back for notification handling. Can be nil. -/// progressBlock - The block to call back for progress updates. Can be nil. /// /// Returns YES if operation was successful, NO otherwise -- (BOOL)checkoutCommit:(GTCommit *)targetCommit strategy:(GTCheckoutStrategyType)strategy notifyFlags:(GTCheckoutNotifyFlags)notifyFlags error:(NSError **)error progressBlock:(nullable void (^)(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps))progressBlock notifyBlock:(nullable int (^)(GTCheckoutNotifyFlags why, NSString *path, GTDiffFile *baseline, GTDiffFile *target, GTDiffFile *workdir))notifyBlock; +- (BOOL)checkoutCommit:(GTCommit *)targetCommit options:(nullable GTCheckoutOptions *)options error:(NSError **)error; /// Checkout a reference /// -/// targetCommit - The reference to checkout. -/// strategy - The checkout strategy to use. -/// notifyFlags - Flags that indicate which notifications should cause `notifyBlock` -/// to be called. -/// error - The error if one occurred. Can be NULL. -/// notifyBlock - The block to call back for notification handling. Can be nil. -/// progressBlock - The block to call back for progress updates. Can be nil. +/// targetReference - The reference to checkout. Must not be nil. +/// options - The checkout options to use. Can be nil. +/// error - The error if one occurred. Can be NULL. /// /// Returns YES if operation was successful, NO otherwise -- (BOOL)checkoutReference:(GTReference *)targetReference strategy:(GTCheckoutStrategyType)strategy notifyFlags:(GTCheckoutNotifyFlags)notifyFlags error:(NSError **)error progressBlock:(nullable void (^)(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps))progressBlock notifyBlock:(nullable int (^)(GTCheckoutNotifyFlags why, NSString *path, GTDiffFile *baseline, GTDiffFile *target, GTDiffFile *workdir))notifyBlock; - -/// Convenience wrapper for checkoutCommit:strategy:notifyFlags:error:notifyBlock:progressBlock without notifications -- (BOOL)checkoutCommit:(GTCommit *)target strategy:(GTCheckoutStrategyType)strategy error:(NSError **)error progressBlock:(nullable void (^)(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps))progressBlock; +- (BOOL)checkoutReference:(GTReference *)targetReference options:(nullable GTCheckoutOptions *)options error:(NSError **)error; -/// Convenience wrapper for checkoutReference:strategy:notifyFlags:error:notifyBlock:progressBlock without notifications -- (BOOL)checkoutReference:(GTReference *)target strategy:(GTCheckoutStrategyType)strategy error:(NSError **)error progressBlock:(nullable void (^)(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps))progressBlock; +/// Checkout an index +/// +/// index - The index to checkout. Must not be nil. +/// options - The checkout options to use. Can be nil. +/// error - The error if one occurred. Can be NULL. +/// +/// Returns YES if operation was successful, NO otherwise +- (BOOL)checkoutIndex:(GTIndex *)index options:(nullable GTCheckoutOptions *)options error:(NSError **)error; /// Flush the gitattributes cache. - (void)flushAttributesCache; diff --git a/ObjectiveGit/GTRepository.m b/ObjectiveGit/GTRepository.m index e983d4785..3d31f26d4 100644 --- a/ObjectiveGit/GTRepository.m +++ b/ObjectiveGit/GTRepository.m @@ -31,6 +31,7 @@ #import "GTBlob.h" #import "GTBranch.h" +#import "GTCheckoutOptions.h" #import "GTCommit.h" #import "GTConfiguration+Private.h" #import "GTConfiguration.h" @@ -59,7 +60,7 @@ #import "git2.h" NSString * const GTRepositoryCloneOptionsBare = @"GTRepositoryCloneOptionsBare"; -NSString * const GTRepositoryCloneOptionsCheckout = @"GTRepositoryCloneOptionsCheckout"; +NSString * const GTRepositoryCloneCheckoutOptions = @"GTRepositoryCloneCheckoutOptions"; NSString * const GTRepositoryCloneOptionsTransportFlags = @"GTRepositoryCloneOptionsTransportFlags"; NSString * const GTRepositoryCloneOptionsCredentialProvider = @"GTRepositoryCloneOptionsCredentialProvider"; NSString * const GTRepositoryCloneOptionsCloneLocal = @"GTRepositoryCloneOptionsCloneLocal"; @@ -212,18 +213,11 @@ - (instancetype)initWithURL:(NSURL *)localFileURL flags:(NSInteger)flags ceiling typedef void(^GTTransferProgressBlock)(const git_transfer_progress *progress, BOOL *stop); -static void checkoutProgressCallback(const char *path, size_t completedSteps, size_t totalSteps, void *payload) { - if (payload == NULL) return; - void (^block)(NSString *, NSUInteger, NSUInteger) = (__bridge id)payload; - NSString *nsPath = (path != NULL ? [NSString stringWithUTF8String:path] : nil); - block(nsPath, completedSteps, totalSteps); -} - static int transferProgressCallback(const git_transfer_progress *progress, void *payload) { if (payload == NULL) return 0; struct GTClonePayload *pld = payload; if (pld->transferProgressBlock == NULL) return 0; - + BOOL stop = NO; pld->transferProgressBlock(progress, &stop); return (stop ? GIT_EUSER : 0); @@ -243,22 +237,20 @@ static int remoteCreate(git_remote **remote, git_repository *repo, const char *n return GIT_OK; } -+ (instancetype)cloneFromURL:(NSURL *)originURL toWorkingDirectory:(NSURL *)workdirURL options:(NSDictionary *)options error:(NSError **)error transferProgressBlock:(void (^)(const git_transfer_progress *, BOOL *stop))transferProgressBlock checkoutProgressBlock:(void (^)(NSString *__nullable path, NSUInteger completedSteps, NSUInteger totalSteps))checkoutProgressBlock { +struct GTRemoteCreatePayload { + git_remote_callbacks remoteCallbacks; +}; + ++ (nullable instancetype)cloneFromURL:(NSURL *)originURL toWorkingDirectory:(NSURL *)workdirURL options:(nullable NSDictionary *)options error:(NSError **)error transferProgressBlock:(nullable void (^)(const git_transfer_progress *, BOOL *stop))transferProgressBlock { git_clone_options cloneOptions = GIT_CLONE_OPTIONS_INIT; NSNumber *bare = options[GTRepositoryCloneOptionsBare]; cloneOptions.bare = (bare == nil ? 0 : bare.boolValue); - NSNumber *checkout = options[GTRepositoryCloneOptionsCheckout]; - BOOL withCheckout = (checkout == nil ? YES : checkout.boolValue); - - if (withCheckout) { - git_checkout_options checkoutOptions = GIT_CHECKOUT_OPTIONS_INIT; - checkoutOptions.checkout_strategy = GIT_CHECKOUT_SAFE; - checkoutOptions.progress_cb = checkoutProgressCallback; - checkoutOptions.progress_payload = (__bridge void *)checkoutProgressBlock; - cloneOptions.checkout_opts = checkoutOptions; + GTCheckoutOptions *checkoutOptions = options[GTRepositoryCloneCheckoutOptions]; + if (checkoutOptions != nil) { + cloneOptions.checkout_opts = *(checkoutOptions.git_checkoutOptions); } GTCredentialProvider *provider = options[GTRepositoryCloneOptionsCredentialProvider]; @@ -284,7 +276,7 @@ + (instancetype)cloneFromURL:(NSURL *)originURL toWorkingDirectory:(NSURL *)work if (localClone) { cloneOptions.local = GIT_CLONE_NO_LOCAL; } - + NSURL *serverCertificateURL = options[GTRepositoryCloneOptionsServerCertificateURL]; if (serverCertificateURL) { int gitError = git_libgit2_opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, serverCertificateURL.fileSystemRepresentation, NULL); @@ -310,8 +302,6 @@ + (instancetype)cloneFromURL:(NSURL *)originURL toWorkingDirectory:(NSURL *)work } return [[self alloc] initWithGitRepository:repository]; - - return nil; } - (id)lookUpObjectByGitOid:(const git_oid *)oid objectType:(GTObjectType)type error:(NSError **)error { @@ -795,22 +785,6 @@ - (GTTag *)createTagNamed:(NSString *)tagName target:(GTObject *)theTarget tagge #pragma mark Checkout -// The type of block passed to -checkout:strategy:progressBlock:notifyBlock:notifyFlags:error: for progress reporting -typedef void (^GTCheckoutProgressBlock)(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps); - -// The type of block passed to -checkout:strategy:progressBlock:notifyBlock:notifyFlags:error: for notification reporting -typedef int (^GTCheckoutNotifyBlock)(GTCheckoutNotifyFlags why, NSString *path, GTDiffFile *baseline, GTDiffFile *target, GTDiffFile *workdir); - -static int checkoutNotifyCallback(git_checkout_notify_t why, const char *path, const git_diff_file *baseline, const git_diff_file *target, const git_diff_file *workdir, void *payload) { - if (payload == NULL) return 0; - GTCheckoutNotifyBlock block = (__bridge id)payload; - NSString *nsPath = (path != NULL ? @(path) : nil); - GTDiffFile *gtBaseline = (baseline != NULL ? [[GTDiffFile alloc] initWithGitDiffFile:*baseline] : nil); - GTDiffFile *gtTarget = (target != NULL ? [[GTDiffFile alloc] initWithGitDiffFile:*target] : nil); - GTDiffFile *gtWorkdir = (workdir != NULL ? [[GTDiffFile alloc] initWithGitDiffFile:*workdir] : nil); - return block((GTCheckoutNotifyFlags)why, nsPath, gtBaseline, gtTarget, gtWorkdir); -} - - (BOOL)moveHEADToReference:(GTReference *)reference error:(NSError **)error { NSParameterAssert(reference != nil); @@ -833,47 +807,36 @@ - (BOOL)moveHEADToCommit:(GTCommit *)commit error:(NSError **)error { return gitError == GIT_OK; } -- (BOOL)performCheckout:(GTObject *)target withStrategy:(GTCheckoutStrategyType)strategy notifyFlags:(GTCheckoutNotifyFlags)notifyFlags error:(NSError **)error progressBlock:(GTCheckoutProgressBlock)progressBlock notifyBlock:(GTCheckoutNotifyBlock)notifyBlock { - - git_checkout_options checkoutOptions = GIT_CHECKOUT_OPTIONS_INIT; - - checkoutOptions.checkout_strategy = strategy; - checkoutOptions.progress_cb = checkoutProgressCallback; - checkoutOptions.progress_payload = (__bridge void *)progressBlock; - - checkoutOptions.notify_cb = checkoutNotifyCallback; - checkoutOptions.notify_flags = notifyFlags; - checkoutOptions.notify_payload = (__bridge void *)notifyBlock; - - int gitError = git_checkout_tree(self.git_repository, target.git_object, &checkoutOptions); +- (BOOL)performCheckout:(GTObject *)target options:(nullable GTCheckoutOptions *)options error:(NSError **)error { + int gitError = git_checkout_tree(self.git_repository, target.git_object, options.git_checkoutOptions); if (gitError < GIT_OK) { if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Failed to checkout tree."]; } - return gitError == GIT_OK; } -- (BOOL)checkoutCommit:(GTCommit *)targetCommit strategy:(GTCheckoutStrategyType)strategy notifyFlags:(GTCheckoutNotifyFlags)notifyFlags error:(NSError **)error progressBlock:(GTCheckoutProgressBlock)progressBlock notifyBlock:(GTCheckoutNotifyBlock)notifyBlock { - BOOL success = [self performCheckout:targetCommit withStrategy:strategy notifyFlags:notifyFlags error:error progressBlock:progressBlock notifyBlock:notifyBlock]; +- (BOOL)checkoutCommit:(GTCommit *)targetCommit options:(GTCheckoutOptions *)options error:(NSError **)error { + BOOL success = [self performCheckout:targetCommit options:options error:error]; if (success == NO) return NO; return [self moveHEADToCommit:targetCommit error:error]; } -- (BOOL)checkoutReference:(GTReference *)targetReference strategy:(GTCheckoutStrategyType)strategy notifyFlags:(GTCheckoutNotifyFlags)notifyFlags error:(NSError **)error progressBlock:(GTCheckoutProgressBlock)progressBlock notifyBlock:(GTCheckoutNotifyBlock)notifyBlock { +- (BOOL)checkoutReference:(GTReference *)targetReference options:(GTCheckoutOptions *)options error:(NSError **)error { GTOID *targetOID = [targetReference targetOID]; GTObject *target = [self lookUpObjectByOID:targetOID error:error]; if (target == nil) return NO; - BOOL success = [self performCheckout:target withStrategy:strategy notifyFlags:notifyFlags error:error progressBlock:progressBlock notifyBlock:notifyBlock]; + BOOL success = [self performCheckout:target options:options error:error]; if (success == NO) return NO; return [self moveHEADToReference:targetReference error:error]; } -- (BOOL)checkoutCommit:(GTCommit *)target strategy:(GTCheckoutStrategyType)strategy error:(NSError **)error progressBlock:(GTCheckoutProgressBlock)progressBlock { - return [self checkoutCommit:target strategy:strategy notifyFlags:GTCheckoutNotifyNone error:error progressBlock:progressBlock notifyBlock:nil]; -} - -- (BOOL)checkoutReference:(GTReference *)target strategy:(GTCheckoutStrategyType)strategy error:(NSError **)error progressBlock:(GTCheckoutProgressBlock)progressBlock { - return [self checkoutReference:target strategy:strategy notifyFlags:GTCheckoutNotifyNone error:error progressBlock:progressBlock notifyBlock:nil]; +- (BOOL)checkoutIndex:(GTIndex *)index options:(GTCheckoutOptions *)options error:(NSError **)error { + int gitError = git_checkout_index(self.git_repository, index.git_index, options.git_checkoutOptions); + if (gitError < GIT_OK) { + if (error != NULL) *error = [NSError git_errorFor:gitError description:@"Failed to checkout index."]; + return NO; + } + return YES; } - (void)flushAttributesCache { diff --git a/ObjectiveGit/ObjectiveGit.h b/ObjectiveGit/ObjectiveGit.h index 4efa0e81f..5c8cba5bc 100644 --- a/ObjectiveGit/ObjectiveGit.h +++ b/ObjectiveGit/ObjectiveGit.h @@ -71,6 +71,7 @@ FOUNDATION_EXPORT const unsigned char ObjectiveGitVersionString[]; #import #import #import +#import #import #import diff --git a/ObjectiveGitFramework.xcodeproj/project.pbxproj b/ObjectiveGitFramework.xcodeproj/project.pbxproj index fb2b0912d..2f241ff67 100644 --- a/ObjectiveGitFramework.xcodeproj/project.pbxproj +++ b/ObjectiveGitFramework.xcodeproj/project.pbxproj @@ -94,6 +94,10 @@ 4D79C0EE17DF9F4D00997DE4 /* GTCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D79C0EC17DF9F4D00997DE4 /* GTCredential.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4D79C0EF17DF9F4D00997DE4 /* GTCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D79C0ED17DF9F4D00997DE4 /* GTCredential.m */; }; 4DBA4A3217DA73CE006CD5F5 /* GTRemoteSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DBA4A3117DA73CE006CD5F5 /* GTRemoteSpec.m */; }; + 4DC55AE51AD859AD0032563C /* GTCheckoutOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DC55AE31AD859AD0032563C /* GTCheckoutOptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4DC55AE61AD859AD0032563C /* GTCheckoutOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DC55AE31AD859AD0032563C /* GTCheckoutOptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4DC55AE71AD859AD0032563C /* GTCheckoutOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DC55AE41AD859AD0032563C /* GTCheckoutOptions.m */; }; + 4DC55AE81AD859AD0032563C /* GTCheckoutOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DC55AE41AD859AD0032563C /* GTCheckoutOptions.m */; }; 4DFFB15B183AA8D600D1565E /* GTRepository+RemoteOperations.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DFFB159183AA8D600D1565E /* GTRepository+RemoteOperations.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4DFFB15C183AA8D600D1565E /* GTRepository+RemoteOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DFFB15A183AA8D600D1565E /* GTRepository+RemoteOperations.m */; }; 55C8055013861FE7004DCB0F /* GTObjectDatabase.m in Sources */ = {isa = PBXBuildFile; fileRef = 55C8054D13861F34004DCB0F /* GTObjectDatabase.m */; }; @@ -487,6 +491,8 @@ 4D79C0ED17DF9F4D00997DE4 /* GTCredential.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTCredential.m; sourceTree = ""; }; 4D79C0F617DFAA7100997DE4 /* GTCredential+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTCredential+Private.h"; sourceTree = ""; }; 4DBA4A3117DA73CE006CD5F5 /* GTRemoteSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTRemoteSpec.m; sourceTree = ""; }; + 4DC55AE31AD859AD0032563C /* GTCheckoutOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTCheckoutOptions.h; sourceTree = ""; }; + 4DC55AE41AD859AD0032563C /* GTCheckoutOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTCheckoutOptions.m; sourceTree = ""; }; 4DE864341794A37E00371A65 /* GTRepository+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTRepository+Private.h"; sourceTree = ""; }; 4DFFB159183AA8D600D1565E /* GTRepository+RemoteOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTRepository+RemoteOperations.h"; sourceTree = ""; }; 4DFFB15A183AA8D600D1565E /* GTRepository+RemoteOperations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTRepository+RemoteOperations.m"; sourceTree = ""; }; @@ -959,6 +965,8 @@ 88E352FF1982E9160051001F /* GTRepository+Attributes.m */, 6EEB519F199D62B9001D72C0 /* GTFetchHeadEntry.h */, 6EEB51A0199D62B9001D72C0 /* GTFetchHeadEntry.m */, + 4DC55AE31AD859AD0032563C /* GTCheckoutOptions.h */, + 4DC55AE41AD859AD0032563C /* GTCheckoutOptions.m */, ); path = ObjectiveGit; sourceTree = ""; @@ -1077,6 +1085,7 @@ BDFAF9C3131C1845000508BC /* GTIndex.h in Headers */, BDFAF9C9131C1868000508BC /* GTIndexEntry.h in Headers */, 6EEB51A1199D62B9001D72C0 /* GTFetchHeadEntry.h in Headers */, + 4DC55AE51AD859AD0032563C /* GTCheckoutOptions.h in Headers */, BD441E08131ED0C300187010 /* GTReference.h in Headers */, 88F6D9D91320451F00CC0BA8 /* ObjectiveGit.h in Headers */, 88B2131C1B20E785005CF2C5 /* GTRepository+References.h in Headers */, @@ -1160,6 +1169,7 @@ D01B6F5919F82FA600D411BC /* GTOID.h in Headers */, D01B6F6D19F82FB300D411BC /* GTDiffFile.h in Headers */, D01B6F2F19F82F8700D411BC /* GTObject.h in Headers */, + 4DC55AE61AD859AD0032563C /* GTCheckoutOptions.h in Headers */, D01B6F4B19F82F8700D411BC /* GTConfiguration.h in Headers */, D01B6F6719F82FA600D411BC /* GTFetchHeadEntry.h in Headers */, D01B6F5F19F82FA600D411BC /* GTFilter.h in Headers */, @@ -1461,6 +1471,7 @@ 23F39FAE1C86DB1C00849F3C /* GTRepository+Merging.m in Sources */, 30DCBA6517B45A78009B0EBD /* GTRepository+Status.m in Sources */, BD6C235413146E6A00992935 /* GTObject.m in Sources */, + 4DC55AE71AD859AD0032563C /* GTCheckoutOptions.m in Sources */, BD6C254613148DD300992935 /* GTSignature.m in Sources */, BD6B0412131496B8001909D0 /* GTTree.m in Sources */, BD6B0418131496CC001909D0 /* GTTreeEntry.m in Sources */, @@ -1522,6 +1533,7 @@ 23F39FB01C86E01800849F3C /* GTRepository+Merging.m in Sources */, D019778A19F8307600F523DA /* ObjectiveGit.m in Sources */, D01B6F3219F82F8700D411BC /* GTCommit.m in Sources */, + 4DC55AE81AD859AD0032563C /* GTCheckoutOptions.m in Sources */, D01B6F3819F82F8700D411BC /* GTTree.m in Sources */, D01B6F6C19F82FB300D411BC /* GTDiff.m in Sources */, 884C8A3A19FF4B890017E98D /* EXTScope.m in Sources */, diff --git a/ObjectiveGitTests/GTFilterSpec.m b/ObjectiveGitTests/GTFilterSpec.m index 2f969e731..318a514a2 100644 --- a/ObjectiveGitTests/GTFilterSpec.m +++ b/ObjectiveGitTests/GTFilterSpec.m @@ -159,7 +159,7 @@ BOOL success = [NSFileManager.defaultManager removeItemAtURL:testFileURL error:NULL]; expect(@(success)).to(beTruthy()); - success = [repository checkoutCommit:newCommit strategy:GTCheckoutStrategyForce error:NULL progressBlock:NULL]; + success = [repository checkoutCommit:newCommit options:[GTCheckoutOptions checkoutOptionsWithStrategy:GTCheckoutStrategyForce] error:NULL]; expect(@(success)).to(beTruthy()); expect([NSData dataWithContentsOfURL:testFileURL]).to(equal(replacementData)); diff --git a/ObjectiveGitTests/GTRemotePushSpec.m b/ObjectiveGitTests/GTRemotePushSpec.m index 050cb10aa..4c14f946a 100644 --- a/ObjectiveGitTests/GTRemotePushSpec.m +++ b/ObjectiveGitTests/GTRemotePushSpec.m @@ -39,7 +39,7 @@ // Make a bare clone to serve as the remote remoteRepoURL = [notBareRepo.gitDirectoryURL.URLByDeletingLastPathComponent URLByAppendingPathComponent:@"bare_remote_repo.git"]; NSDictionary *options = @{ GTRepositoryCloneOptionsBare: @1 }; - remoteRepo = [GTRepository cloneFromURL:notBareRepo.gitDirectoryURL toWorkingDirectory:remoteRepoURL options:options error:&error transferProgressBlock:NULL checkoutProgressBlock:NULL]; + remoteRepo = [GTRepository cloneFromURL:notBareRepo.gitDirectoryURL toWorkingDirectory:remoteRepoURL options:options error:&error transferProgressBlock:NULL]; expect(error).to(beNil()); expect(remoteRepo).notTo(beNil()); expect(@(remoteRepo.isBare)).to(beTruthy()); // that's better @@ -48,7 +48,7 @@ expect(localRepoURL).notTo(beNil()); // Local clone for testing pushes - localRepo = [GTRepository cloneFromURL:remoteRepoURL toWorkingDirectory:localRepoURL options:nil error:&error transferProgressBlock:NULL checkoutProgressBlock:NULL]; + localRepo = [GTRepository cloneFromURL:remoteRepoURL toWorkingDirectory:localRepoURL options:nil error:&error transferProgressBlock:NULL]; expect(error).to(beNil()); expect(localRepo).notTo(beNil()); diff --git a/ObjectiveGitTests/GTRemoteSpec.m b/ObjectiveGitTests/GTRemoteSpec.m index 35a098edc..5f8449ca8 100644 --- a/ObjectiveGitTests/GTRemoteSpec.m +++ b/ObjectiveGitTests/GTRemoteSpec.m @@ -107,7 +107,7 @@ fetchingRepoURL = [fixturesURL URLByAppendingPathComponent:@"fetchrepo"]; NSError *error = nil; - fetchingRepo = [GTRepository cloneFromURL:repositoryURL toWorkingDirectory:fetchingRepoURL options:nil error:&error transferProgressBlock:nil checkoutProgressBlock:nil]; + fetchingRepo = [GTRepository cloneFromURL:repositoryURL toWorkingDirectory:fetchingRepoURL options:nil error:&error transferProgressBlock:nil]; expect(fetchingRepo).notTo(beNil()); expect(error).to(beNil()); diff --git a/ObjectiveGitTests/GTRepository+PullSpec.m b/ObjectiveGitTests/GTRepository+PullSpec.m index ef0999566..bb157454d 100644 --- a/ObjectiveGitTests/GTRepository+PullSpec.m +++ b/ObjectiveGitTests/GTRepository+PullSpec.m @@ -40,7 +40,7 @@ // Make a bare clone to serve as the remote remoteRepoURL = [notBareRepo.gitDirectoryURL.URLByDeletingLastPathComponent URLByAppendingPathComponent:@"bare_remote_repo.git"]; NSDictionary *options = @{ GTRepositoryCloneOptionsBare: @1 }; - remoteRepo = [GTRepository cloneFromURL:notBareRepo.gitDirectoryURL toWorkingDirectory:remoteRepoURL options:options error:&error transferProgressBlock:NULL checkoutProgressBlock:NULL]; + remoteRepo = [GTRepository cloneFromURL:notBareRepo.gitDirectoryURL toWorkingDirectory:remoteRepoURL options:options error:&error transferProgressBlock:NULL]; expect(error).to(beNil()); expect(remoteRepo).notTo(beNil()); expect(@(remoteRepo.isBare)).to(beTruthy()); // that's better @@ -49,7 +49,7 @@ expect(localRepoURL).notTo(beNil()); // Local clone for testing pushes - localRepo = [GTRepository cloneFromURL:remoteRepoURL toWorkingDirectory:localRepoURL options:nil error:&error transferProgressBlock:NULL checkoutProgressBlock:NULL]; + localRepo = [GTRepository cloneFromURL:remoteRepoURL toWorkingDirectory:localRepoURL options:nil error:&error transferProgressBlock:NULL]; expect(error).to(beNil()); expect(localRepo).notTo(beNil()); diff --git a/ObjectiveGitTests/GTRepositorySpec.m b/ObjectiveGitTests/GTRepositorySpec.m index 8c7740dcc..24fac195f 100644 --- a/ObjectiveGitTests/GTRepositorySpec.m +++ b/ObjectiveGitTests/GTRepositorySpec.m @@ -95,7 +95,14 @@ it(@"should handle normal clones", ^{ NSError *error = nil; - repository = [GTRepository cloneFromURL:originURL toWorkingDirectory:workdirURL options:@{ GTRepositoryCloneOptionsCloneLocal: @YES } error:&error transferProgressBlock:transferProgressBlock checkoutProgressBlock:checkoutProgressBlock]; + GTCheckoutOptions *checkoutOptions = [GTCheckoutOptions checkoutOptionsWithStrategy:GTCheckoutStrategySafe]; + checkoutOptions.progressBlock = checkoutProgressBlock; + + NSDictionary *cloneOptions = @{ + GTRepositoryCloneOptionsCloneLocal: @YES, + GTRepositoryCloneCheckoutOptions: checkoutOptions, + }; + repository = [GTRepository cloneFromURL:originURL toWorkingDirectory:workdirURL options:cloneOptions error:&error transferProgressBlock:transferProgressBlock]; expect(repository).notTo(beNil()); expect(error).to(beNil()); expect(@(transferProgressCalled)).to(beTruthy()); @@ -112,8 +119,15 @@ it(@"should handle bare clones", ^{ NSError *error = nil; - NSDictionary *options = @{ GTRepositoryCloneOptionsBare: @YES, GTRepositoryCloneOptionsCloneLocal: @YES }; - repository = [GTRepository cloneFromURL:originURL toWorkingDirectory:workdirURL options:options error:&error transferProgressBlock:transferProgressBlock checkoutProgressBlock:checkoutProgressBlock]; + GTCheckoutOptions *checkoutOptions = [GTCheckoutOptions checkoutOptionsWithStrategy:GTCheckoutStrategySafe]; + checkoutOptions.progressBlock = checkoutProgressBlock; + + NSDictionary *options = @{ + GTRepositoryCloneOptionsBare: @YES, + GTRepositoryCloneOptionsCloneLocal: @YES, + GTRepositoryCloneCheckoutOptions: checkoutOptions, + }; + repository = [GTRepository cloneFromURL:originURL toWorkingDirectory:workdirURL options:options error:&error transferProgressBlock:transferProgressBlock]; expect(repository).notTo(beNil()); expect(error).to(beNil()); expect(@(transferProgressCalled)).to(beTruthy()); @@ -130,7 +144,10 @@ it(@"should have set a valid remote URL", ^{ NSError *error = nil; - repository = [GTRepository cloneFromURL:originURL toWorkingDirectory:workdirURL options:nil error:&error transferProgressBlock:transferProgressBlock checkoutProgressBlock:checkoutProgressBlock]; + GTCheckoutOptions *checkoutOptions = [GTCheckoutOptions checkoutOptionsWithStrategy:GTCheckoutStrategySafe]; + checkoutOptions.progressBlock = checkoutProgressBlock; + + repository = [GTRepository cloneFromURL:originURL toWorkingDirectory:workdirURL options:@{ GTRepositoryCloneCheckoutOptions: checkoutOptions } error:&error transferProgressBlock:transferProgressBlock]; expect(repository).notTo(beNil()); expect(error).to(beNil()); @@ -167,7 +184,14 @@ return cred; }]; - repository = [GTRepository cloneFromURL:originURL toWorkingDirectory:workdirURL options:@{GTRepositoryCloneOptionsCredentialProvider: provider} error:&error transferProgressBlock:transferProgressBlock checkoutProgressBlock:checkoutProgressBlock]; + GTCheckoutOptions *checkoutOptions = [GTCheckoutOptions checkoutOptionsWithStrategy:GTCheckoutStrategySafe]; + checkoutOptions.progressBlock = checkoutProgressBlock; + NSDictionary *cloneOptions = @{ + GTRepositoryCloneOptionsCredentialProvider: provider, + GTRepositoryCloneCheckoutOptions: checkoutOptions, + }; + + repository = [GTRepository cloneFromURL:originURL toWorkingDirectory:workdirURL options:cloneOptions error:&error transferProgressBlock:transferProgressBlock]; expect(repository).notTo(beNil()); expect(error).to(beNil()); expect(@(transferProgressCalled)).to(beTruthy()); @@ -416,7 +440,7 @@ GTReference *ref = [repository lookUpReferenceWithName:@"refs/heads/other-branch" error:&error]; expect(ref).notTo(beNil()); expect(error.localizedDescription).to(beNil()); - BOOL result = [repository checkoutReference:ref strategy:GTCheckoutStrategyAllowConflicts error:&error progressBlock:nil]; + BOOL result = [repository checkoutReference:ref options:[GTCheckoutOptions checkoutOptionsWithStrategy:GTCheckoutStrategyAllowConflicts] error:&error]; expect(@(result)).to(beTruthy()); expect(error.localizedDescription).to(beNil()); }); @@ -426,7 +450,7 @@ GTCommit *commit = [repository lookUpObjectBySHA:@"1d69f3c0aeaf0d62e25591987b93b8ffc53abd77" objectType:GTObjectTypeCommit error:&error]; expect(commit).notTo(beNil()); expect(error.localizedDescription).to(beNil()); - BOOL result = [repository checkoutCommit:commit strategy:GTCheckoutStrategyAllowConflicts error:&error progressBlock:nil]; + BOOL result = [repository checkoutCommit:commit options:[GTCheckoutOptions checkoutOptionsWithStrategy:GTCheckoutStrategyAllowConflicts] error:&error]; expect(@(result)).to(beTruthy()); expect(error.localizedDescription).to(beNil()); }); @@ -451,7 +475,8 @@ return 0; }; - BOOL result = [repository checkoutReference:ref strategy:GTCheckoutStrategySafe notifyFlags:GTCheckoutNotifyConflict error:&error progressBlock:nil notifyBlock:notifyBlock]; + GTCheckoutOptions *options = [GTCheckoutOptions checkoutOptionsWithStrategy:GTCheckoutStrategySafe notifyFlags:GTCheckoutNotifyConflict notifyBlock:notifyBlock]; + BOOL result = [repository checkoutReference:ref options:options error:&error]; expect(@(notifyCount)).to(equal(@(1))); expect(@(readmeFileConflicted)).to(beTruthy()); expect(@(result)).to(beFalsy()); @@ -476,7 +501,9 @@ return 0; }; - BOOL result = [repository checkoutCommit:commit strategy:GTCheckoutStrategySafe notifyFlags:GTCheckoutNotifyConflict error:&error progressBlock:nil notifyBlock:notifyBlock]; + + GTCheckoutOptions *options = [GTCheckoutOptions checkoutOptionsWithStrategy:GTCheckoutStrategySafe notifyFlags:GTCheckoutNotifyConflict notifyBlock:notifyBlock]; + BOOL result = [repository checkoutCommit:commit options:options error:&error]; expect(@(notifyCount)).to(equal(@(1))); expect(@(readme1FileConflicted)).to(beTruthy()); expect(@(result)).to(beFalsy()); diff --git a/ObjectiveGitTests/GTRepositoryStashingSpec.m b/ObjectiveGitTests/GTRepositoryStashingSpec.m index 6f7a2d090..75a51a328 100644 --- a/ObjectiveGitTests/GTRepositoryStashingSpec.m +++ b/ObjectiveGitTests/GTRepositoryStashingSpec.m @@ -129,7 +129,7 @@ expect(error).to(beNil()); __block BOOL progressCalled = NO; - BOOL success = [repository applyStashAtIndex:0 flags:GTRepositoryStashApplyFlagDefault error:&error progressBlock:^void(GTRepositoryStashApplyProgress step, BOOL *stop) { + BOOL success = [repository applyStashAtIndex:0 flags:GTRepositoryStashApplyFlagDefault checkoutOptions:nil error:&error progressBlock:^void(GTRepositoryStashApplyProgress step, BOOL *stop) { progressCalled = YES; }]; expect(@(success)).to(beTruthy()); @@ -162,7 +162,7 @@ lastStashIndex = index; }]; - success = [repository applyStashAtIndex:(lastStashIndex + 1) flags:GTRepositoryStashApplyFlagDefault error:&error progressBlock:nil]; + success = [repository applyStashAtIndex:(lastStashIndex + 1) flags:GTRepositoryStashApplyFlagDefault checkoutOptions:nil error:&error progressBlock:nil]; expect(@(success)).to(beFalsy()); expect(error).notTo(beNil()); expect(error.domain).to(equal(GTGitErrorDomain)); @@ -186,7 +186,7 @@ expect(@([@"barfoo" writeToURL:[repository.fileURL URLByAppendingPathComponent:@"new-test-file"] atomically:YES encoding:NSUTF8StringEncoding error:NULL])).to(beTruthy()); - BOOL success = [repository applyStashAtIndex:0 flags:GTRepositoryStashApplyFlagDefault error:&error progressBlock:nil]; + BOOL success = [repository applyStashAtIndex:0 flags:GTRepositoryStashApplyFlagDefault checkoutOptions:nil error:&error progressBlock:nil]; expect(@(success)).to(beFalsy()); expect(error).notTo(beNil()); diff --git a/ObjectiveGitTests/GTSubmoduleSpec.m b/ObjectiveGitTests/GTSubmoduleSpec.m index 1039703ac..d246b1507 100644 --- a/ObjectiveGitTests/GTSubmoduleSpec.m +++ b/ObjectiveGitTests/GTSubmoduleSpec.m @@ -86,7 +86,7 @@ expect(submoduleRepository).notTo(beNil()); GTCommit *commit = [submoduleRepository lookUpObjectByRevParse:@"HEAD^" error:NULL]; - BOOL success = [submoduleRepository checkoutCommit:commit strategy:GTCheckoutStrategyForce error:NULL progressBlock:nil]; + BOOL success = [submoduleRepository checkoutCommit:commit options:[GTCheckoutOptions checkoutOptionsWithStrategy:GTCheckoutStrategyForce] error:NULL]; expect(@(success)).to(beTruthy()); success = [submodule addToIndex:NULL];