Skip to content

Commit c0e98a2

Browse files
authoredFeb 27, 2017
Merge pull request #459 from libgit2/checkout-options
Wrap all the various way of doing checkouts in GTCheckoutOptions
2 parents 968396a + 3c515b0 commit c0e98a2

16 files changed

+331
-144
lines changed
 

‎ObjectiveGit/GTCheckoutOptions.h

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
//
2+
// GTCheckoutOptions.h
3+
// ObjectiveGitFramework
4+
//
5+
// Created by Etienne on 10/04/2015.
6+
// Copyright (c) 2015 GitHub, Inc. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
#import "git2/checkout.h"
11+
12+
@class GTDiffFile;
13+
14+
NS_ASSUME_NONNULL_BEGIN
15+
16+
/// Checkout strategies used by the various -checkout... methods
17+
/// See git_checkout_strategy_t
18+
typedef NS_OPTIONS(NSInteger, GTCheckoutStrategyType) {
19+
GTCheckoutStrategyNone = GIT_CHECKOUT_NONE,
20+
GTCheckoutStrategySafe = GIT_CHECKOUT_SAFE,
21+
GTCheckoutStrategyForce = GIT_CHECKOUT_FORCE,
22+
GTCheckoutStrategyRecreateMissing = GIT_CHECKOUT_RECREATE_MISSING,
23+
GTCheckoutStrategyAllowConflicts = GIT_CHECKOUT_ALLOW_CONFLICTS,
24+
GTCheckoutStrategyRemoveUntracked = GIT_CHECKOUT_REMOVE_UNTRACKED,
25+
GTCheckoutStrategyRemoveIgnored = GIT_CHECKOUT_REMOVE_IGNORED,
26+
GTCheckoutStrategyUpdateOnly = GIT_CHECKOUT_UPDATE_ONLY,
27+
GTCheckoutStrategyDontUpdateIndex = GIT_CHECKOUT_DONT_UPDATE_INDEX,
28+
GTCheckoutStrategyNoRefresh = GIT_CHECKOUT_NO_REFRESH,
29+
GTCheckoutStrategySkipUnmerged = GIT_CHECKOUT_SKIP_UNMERGED,
30+
GTCheckoutStrategyUseOurs = GIT_CHECKOUT_USE_OURS,
31+
GTCheckoutStrategyUseTheirs = GIT_CHECKOUT_USE_THEIRS,
32+
GTCheckoutStrategyDisablePathspecMatch = GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH,
33+
GTCheckoutStrategySkipLockedDirectories = GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES,
34+
GTCheckoutStrategyDoNotOverwriteIgnored = GIT_CHECKOUT_DONT_OVERWRITE_IGNORED,
35+
GTCheckoutStrategyConflictStyleMerge = GIT_CHECKOUT_CONFLICT_STYLE_MERGE,
36+
GTCheckoutStrategyCoflictStyleDiff3 = GIT_CHECKOUT_CONFLICT_STYLE_DIFF3,
37+
GTCheckoutStrategyDoNotRemoveExisting = GIT_CHECKOUT_DONT_REMOVE_EXISTING,
38+
GTCheckoutStrategyDoNotWriteIndex = GIT_CHECKOUT_DONT_WRITE_INDEX,
39+
};
40+
41+
/// Checkout notification flags used by the various -checkout... methods
42+
/// See git_checkout_notify_t
43+
typedef NS_OPTIONS(NSInteger, GTCheckoutNotifyFlags) {
44+
GTCheckoutNotifyNone = GIT_CHECKOUT_NOTIFY_NONE,
45+
GTCheckoutNotifyConflict = GIT_CHECKOUT_NOTIFY_CONFLICT,
46+
GTCheckoutNotifyDirty = GIT_CHECKOUT_NOTIFY_DIRTY,
47+
GTCheckoutNotifyUpdated = GIT_CHECKOUT_NOTIFY_UPDATED,
48+
GTCheckoutNotifyUntracked = GIT_CHECKOUT_NOTIFY_UNTRACKED,
49+
GTCheckoutNotifyIgnored = GIT_CHECKOUT_NOTIFY_IGNORED,
50+
51+
GTCheckoutNotifyAll = GIT_CHECKOUT_NOTIFY_ALL,
52+
};
53+
54+
@interface GTCheckoutOptions : NSObject
55+
56+
/// Create a checkout options object.
57+
///
58+
/// Since there are many places where we can checkout data, this object allow us
59+
/// to centralize all the various behaviors that checkout allow.
60+
///
61+
/// @param strategy The checkout strategy to use.
62+
/// @param notifyFlags The checkout events that will be notified via `notifyBlock`.
63+
/// @param progressBlock A block that will be called for each checkout step.
64+
/// @param notifyBlock A block that will be called for each event, @see `notifyFlags`.
65+
///
66+
/// @return A newly-initialized GTCheckoutOptions object.
67+
+ (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;
68+
69+
/// Create a checkout options object.
70+
/// @see +checkoutOptionsWithStrategy:notifyFlags:progressBlock:notifyBlock:
71+
+ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy notifyFlags:(GTCheckoutNotifyFlags)notifyFlags notifyBlock:(int (^)(GTCheckoutNotifyFlags why, NSString *path, GTDiffFile *baseline, GTDiffFile *target, GTDiffFile *workdir))notifyBlock;
72+
73+
/// Create a checkout options object.
74+
/// @see +checkoutOptionsWithStrategy:notifyFlags:progressBlock:notifyBlock:
75+
+ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy progressBlock:(void (^)(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps))progressBlock;
76+
77+
/// Create a checkout options object.
78+
/// @see +checkoutOptionsWithStrategy:notifyFlags:progressBlock:notifyBlock:
79+
+ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy;
80+
81+
/// Get the underlying git_checkout_options struct.
82+
///
83+
/// @return <#return value description#>
84+
- (git_checkout_options *)git_checkoutOptions NS_RETURNS_INNER_POINTER;
85+
86+
/// The checkout strategy to use.
87+
@property (assign) GTCheckoutStrategyType strategy;
88+
89+
/// The checkout progress block that was passed in.
90+
@property (copy) void (^progressBlock)(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps);
91+
92+
/// The notification flags currently enabled.
93+
@property (assign) GTCheckoutNotifyFlags notifyFlags;
94+
95+
/// The checkout notification block that was passed in.
96+
@property (copy) int (^notifyBlock)(GTCheckoutNotifyFlags why, NSString *path, GTDiffFile *baseline, GTDiffFile *target, GTDiffFile *workdir);
97+
98+
/// An array of strings used to restrict what will be checked out.
99+
@property (copy) NSArray <NSString *> *pathSpecs;
100+
101+
@end
102+
103+
NS_ASSUME_NONNULL_END

‎ObjectiveGit/GTCheckoutOptions.m

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//
2+
// GTCheckoutOptions.m
3+
// ObjectiveGitFramework
4+
//
5+
// Created by Etienne on 10/04/2015.
6+
// Copyright (c) 2015 GitHub, Inc. All rights reserved.
7+
//
8+
9+
#import "GTCheckoutOptions.h"
10+
#import "GTDiffFile.h"
11+
#import "NSError+Git.h"
12+
#import "NSArray+StringArray.h"
13+
#import "git2.h"
14+
15+
// The type of block set in progressBlock for progress reporting
16+
typedef void (^GTCheckoutProgressBlock)(NSString *path, NSUInteger completedSteps, NSUInteger totalSteps);
17+
18+
// The type of block set in notifyBlock for notification reporting
19+
typedef int (^GTCheckoutNotifyBlock)(GTCheckoutNotifyFlags why, NSString *path, GTDiffFile * __nullable baseline, GTDiffFile * __nullable target, GTDiffFile * __nullable workdir);
20+
21+
22+
@interface GTCheckoutOptions () {
23+
git_checkout_options _git_checkoutOptions;
24+
}
25+
@end
26+
27+
@implementation GTCheckoutOptions
28+
29+
+ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy notifyFlags:(GTCheckoutNotifyFlags)notifyFlags progressBlock:(nullable GTCheckoutProgressBlock)progressBlock notifyBlock:(nullable GTCheckoutNotifyBlock)notifyBlock {
30+
GTCheckoutOptions *options = [self checkoutOptionsWithStrategy:strategy];
31+
options.notifyFlags = notifyFlags;
32+
options.notifyBlock = notifyBlock;
33+
options.progressBlock = progressBlock;
34+
return options;
35+
}
36+
37+
+ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy progressBlock:(GTCheckoutProgressBlock)progressBlock {
38+
NSParameterAssert(progressBlock != nil);
39+
GTCheckoutOptions *options = [self checkoutOptionsWithStrategy:strategy];
40+
options.progressBlock = progressBlock;
41+
return options;
42+
}
43+
44+
+ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy notifyFlags:(GTCheckoutNotifyFlags)notifyFlags notifyBlock:(GTCheckoutNotifyBlock)notifyBlock {
45+
NSParameterAssert(notifyBlock != nil);
46+
return [self checkoutOptionsWithStrategy:strategy notifyFlags:notifyFlags progressBlock:nil notifyBlock:notifyBlock];
47+
}
48+
49+
+ (instancetype)checkoutOptionsWithStrategy:(GTCheckoutStrategyType)strategy {
50+
GTCheckoutOptions *options = [[self alloc] init];
51+
options.strategy = strategy;
52+
return options;
53+
}
54+
55+
- (instancetype)init {
56+
self = [super init];
57+
if (self == nil) return nil;
58+
59+
_git_checkoutOptions.version = GIT_CHECKOUT_OPTIONS_VERSION;
60+
61+
return self;
62+
}
63+
64+
static void GTCheckoutProgressCallback(const char *path, size_t completedSteps, size_t totalSteps, void *payload) {
65+
if (payload == NULL) return;
66+
void (^block)(NSString *, NSUInteger, NSUInteger) = (__bridge id)payload;
67+
NSString *nsPath = (path != NULL ? @(path) : nil);
68+
block(nsPath, completedSteps, totalSteps);
69+
}
70+
71+
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) {
72+
if (payload == NULL) return 0;
73+
GTCheckoutNotifyBlock block = (__bridge id)payload;
74+
NSString *nsPath = (path != NULL ? @(path) : nil);
75+
GTDiffFile *gtBaseline = (baseline != NULL ? [[GTDiffFile alloc] initWithGitDiffFile:*baseline] : nil);
76+
GTDiffFile *gtTarget = (target != NULL ? [[GTDiffFile alloc] initWithGitDiffFile:*target] : nil);
77+
GTDiffFile *gtWorkdir = (workdir != NULL ? [[GTDiffFile alloc] initWithGitDiffFile:*workdir] : nil);
78+
return block((GTCheckoutNotifyFlags)why, nsPath, gtBaseline, gtTarget, gtWorkdir);
79+
}
80+
81+
- (git_checkout_options *)git_checkoutOptions {
82+
_git_checkoutOptions.checkout_strategy = self.strategy;
83+
84+
if (self.progressBlock != nil) {
85+
_git_checkoutOptions.progress_cb = GTCheckoutProgressCallback;
86+
_git_checkoutOptions.progress_payload = (__bridge void *)self.progressBlock;
87+
}
88+
89+
if (self.notifyBlock != nil) {
90+
_git_checkoutOptions.notify_cb = GTCheckoutNotifyCallback;
91+
_git_checkoutOptions.notify_flags = self.notifyFlags;
92+
_git_checkoutOptions.notify_payload = (__bridge void *)self.notifyBlock;
93+
}
94+
95+
_git_checkoutOptions.paths = self.pathSpecs.git_strarray;
96+
97+
return &_git_checkoutOptions;
98+
}
99+
100+
@end

‎ObjectiveGit/GTRepository+Merging.m

+2-3
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,7 @@ - (BOOL)mergeBranchIntoCurrentBranch:(GTBranch *)branch withError:(NSError **)er
107107
// Fast-forward branch
108108
NSString *message = [NSString stringWithFormat:@"merge %@: Fast-forward", branch.name];
109109
GTReference *reference = [localBranch.reference referenceByUpdatingTarget:remoteCommit.SHA message:message error:error];
110-
BOOL checkoutSuccess = [self checkoutReference:reference strategy:GTCheckoutStrategyForce error:error progressBlock:nil];
111-
110+
BOOL checkoutSuccess = [self checkoutReference:reference options:[GTCheckoutOptions checkoutOptionsWithStrategy:GTCheckoutStrategyForce] error:error];
112111
return checkoutSuccess;
113112
} else if (analysis & GTMergeAnalysisNormal) {
114113
// Do normal merge
@@ -164,7 +163,7 @@ - (BOOL)mergeBranchIntoCurrentBranch:(GTBranch *)branch withError:(NSError **)er
164163
return NO;
165164
}
166165

167-
BOOL success = [self checkoutReference:localBranch.reference strategy:GTCheckoutStrategyForce error:error progressBlock:nil];
166+
BOOL success = [self checkoutReference:localBranch.reference options:[GTCheckoutOptions checkoutOptionsWithStrategy:GTCheckoutStrategyForce] error:error];
168167
return success;
169168
}
170169

‎ObjectiveGit/GTRepository+Stashing.h

+12-8
Original file line numberDiff line numberDiff line change
@@ -64,21 +64,25 @@ NS_ASSUME_NONNULL_BEGIN
6464

6565
/// Apply stashed changes.
6666
///
67-
/// index - The index of the stash to apply. 0 is the latest one.
68-
/// flags - The flags to use when applying the stash.
69-
/// error - If not NULL, set to any error that occurred.
67+
/// index - The index of the stash to apply. 0 is the latest one.
68+
/// flags - The flags to use when applying the stash.
69+
/// options - The options to use when checking out.
70+
/// error - If not NULL, set to any error that occurred.
71+
/// progressBlock - A block that will be executed on each step of the stash application.
7072
///
7173
/// Returns YES if the requested stash was successfully applied, NO otherwise.
72-
- (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock;
74+
- (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags checkoutOptions:(nullable GTCheckoutOptions *)options error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock;
7375

7476
/// Pop stashed changes.
7577
///
76-
/// index - The index of the stash to apply. 0 is the most recent stash.
77-
/// flags - The flags to use when applying the stash.
78-
/// error - If not NULL, set to any error that occurred.
78+
/// index - The index of the stash to apply. 0 is the most recent stash.
79+
/// flags - The flags to use when applying the stash.
80+
/// options - The options to use when checking out.
81+
/// error - If not NULL, set to any error that occurred.
82+
/// progressBlock - A block that will be executed on each step of the stash application.
7983
///
8084
/// Returns YES if the requested stash was successfully applied, NO otherwise.
81-
- (BOOL)popStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock;
85+
- (BOOL)popStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags checkoutOptions:(nullable GTCheckoutOptions *)options error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock;
8286

8387
/// Drop a stash from the repository's list of stashes.
8488
///

‎ObjectiveGit/GTRepository+Stashing.m

+10-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ static int stashApplyProgressCallback(git_stash_apply_progress_t progress, void
5959
return (stop ? GIT_EUSER : 0);
6060
}
6161

62-
- (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock {
62+
- (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags checkoutOptions:(GTCheckoutOptions *)options error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock {
6363
git_stash_apply_options stash_options = GIT_STASH_APPLY_OPTIONS_INIT;
6464

6565
stash_options.flags = (git_stash_apply_flags)flags;
@@ -68,6 +68,10 @@ - (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)fl
6868
stash_options.progress_payload = (__bridge void *)progressBlock;
6969
}
7070

71+
if (options != nil) {
72+
stash_options.checkout_options = *options.git_checkoutOptions;
73+
}
74+
7175
int gitError = git_stash_apply(self.git_repository, index, &stash_options);
7276
if (gitError != GIT_OK) {
7377
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];
@@ -76,7 +80,7 @@ - (BOOL)applyStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)fl
7680
return YES;
7781
}
7882

79-
- (BOOL)popStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock {
83+
- (BOOL)popStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flags checkoutOptions:(GTCheckoutOptions *)options error:(NSError **)error progressBlock:(nullable void (^)(GTRepositoryStashApplyProgress progress, BOOL *stop))progressBlock{
8084
git_stash_apply_options stash_options = GIT_STASH_APPLY_OPTIONS_INIT;
8185

8286
stash_options.flags = (git_stash_apply_flags)flags;
@@ -85,6 +89,10 @@ - (BOOL)popStashAtIndex:(NSUInteger)index flags:(GTRepositoryStashApplyFlag)flag
8589
stash_options.progress_payload = (__bridge void *)progressBlock;
8690
}
8791

92+
if (options != nil) {
93+
stash_options.checkout_options = *options.git_checkoutOptions;
94+
}
95+
8896
int gitError = git_stash_pop(self.git_repository, index, &stash_options);
8997
if (gitError != GIT_OK) {
9098
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];

0 commit comments

Comments
 (0)
Please sign in to comment.