From 9b3a0fcc55665d0d2f181de04e72005b511a1fcf Mon Sep 17 00:00:00 2001 From: Mac Morgan Date: Tue, 14 May 2013 19:26:41 -0400 Subject: [PATCH 1/6] added stash command --- Classes/GTRepository.h | 16 ++++++++++++++++ Classes/GTRepository.m | 13 +++++++++++++ 2 files changed, 29 insertions(+) diff --git a/Classes/GTRepository.h b/Classes/GTRepository.h index 1330c1eaa..cd97e2290 100644 --- a/Classes/GTRepository.h +++ b/Classes/GTRepository.h @@ -61,6 +61,13 @@ typedef enum : git_reset_t { GTRepositoryResetTypeHard = GIT_RESET_HARD } GTRepositoryResetType; +typedef enum : git_stash_flags { + GTRepositoryStashFlagDefault = GIT_STASH_DEFAULT, + GTRepositoryStashFlagKeepIndex = GIT_STASH_KEEP_INDEX, + GTRepositoryStashFlagIncludeUntracked = GIT_STASH_INCLUDE_UNTRACKED, + GTRepositoryStashFlagIncludeIgnored = GIT_STASH_INCLUDE_IGNORED +} GTRepositoryStashFlag; + typedef void (^GTRepositoryStatusBlock)(NSURL *fileURL, GTRepositoryFileStatus status, BOOL *stop); @interface GTRepository : NSObject @@ -212,4 +219,13 @@ typedef void (^GTRepositoryStatusBlock)(NSURL *fileURL, GTRepositoryFileStatus s // Returns the signature. - (GTSignature *)userSignatureForNow; +// Stash the repository's changes. +// +// message - the message to be attributed to the item in the stash. +// stashFlag - The flag of stash to be used. +// error(out) - in the event of an error this may be set. +// +// Returns commit of the stashed changes if successful, nil in the even of an error +- (GTCommit*)stashChangesWithMessage:(NSString *)message withStashFlag:(GTRepositoryStashFlag)stashFlag error:(NSError **)error; + @end diff --git a/Classes/GTRepository.m b/Classes/GTRepository.m index 032acfeac..91032f412 100644 --- a/Classes/GTRepository.m +++ b/Classes/GTRepository.m @@ -657,4 +657,17 @@ - (GTSignature *)userSignatureForNow { return [[GTSignature alloc] initWithName:name email:email time:[NSDate date]]; } +#pragma mark Stash + +- (GTCommit*)stashChangesWithMessage:(NSString *)message withStashFlag:(GTRepositoryStashFlag)stashFlag error:(NSError **)error +{ + git_oid oid; + + git_stash_save(&oid, self.git_repository, [self userSignatureForNow].git_signature, [message cStringUsingEncoding:NSUTF8StringEncoding], stashFlag); + + GTCommit* commit = (GTCommit*)[self lookupObjectByOid:&oid error:error]; + + return commit; +} + @end From daee703475f02324b647de374efebb113206baef Mon Sep 17 00:00:00 2001 From: Dmitry Golomidov Date: Tue, 14 May 2013 17:09:24 -0700 Subject: [PATCH 2/6] better formatting --- Classes/GTRepository.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Classes/GTRepository.h b/Classes/GTRepository.h index cd97e2290..5e456de04 100644 --- a/Classes/GTRepository.h +++ b/Classes/GTRepository.h @@ -62,10 +62,10 @@ typedef enum : git_reset_t { } GTRepositoryResetType; typedef enum : git_stash_flags { - GTRepositoryStashFlagDefault = GIT_STASH_DEFAULT, - GTRepositoryStashFlagKeepIndex = GIT_STASH_KEEP_INDEX, + GTRepositoryStashFlagDefault = GIT_STASH_DEFAULT, + GTRepositoryStashFlagKeepIndex = GIT_STASH_KEEP_INDEX, GTRepositoryStashFlagIncludeUntracked = GIT_STASH_INCLUDE_UNTRACKED, - GTRepositoryStashFlagIncludeIgnored = GIT_STASH_INCLUDE_IGNORED + GTRepositoryStashFlagIncludeIgnored = GIT_STASH_INCLUDE_IGNORED } GTRepositoryStashFlag; typedef void (^GTRepositoryStatusBlock)(NSURL *fileURL, GTRepositoryFileStatus status, BOOL *stop); From a40faca500f9d3acde996e35dfa97cf93aa67b74 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Tue, 2 Jul 2013 12:30:08 +0200 Subject: [PATCH 3/6] Fix issues raised in review. --- Classes/GTRepository.h | 2 +- Classes/GTRepository.m | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Classes/GTRepository.h b/Classes/GTRepository.h index 8f095c215..b01dcbe38 100644 --- a/Classes/GTRepository.h +++ b/Classes/GTRepository.h @@ -213,7 +213,7 @@ typedef void (^GTRepositoryStatusBlock)(NSURL *fileURL, GTRepositoryFileStatus s // // message - the message to be attributed to the item in the stash. // stashFlag - The flag of stash to be used. -// error(out) - in the event of an error this may be set. +// error - in the event of an error this may be set. // // Returns commit of the stashed changes if successful, nil in the even of an error - (GTCommit*)stashChangesWithMessage:(NSString *)message withStashFlag:(GTRepositoryStashFlag)stashFlag error:(NSError **)error; diff --git a/Classes/GTRepository.m b/Classes/GTRepository.m index c21b7aaab..fc3b7bd4a 100644 --- a/Classes/GTRepository.m +++ b/Classes/GTRepository.m @@ -619,8 +619,13 @@ - (GTSignature *)userSignatureForNow { - (GTCommit*)stashChangesWithMessage:(NSString *)message withStashFlag:(GTRepositoryStashFlag)stashFlag error:(NSError **)error { git_oid oid; - - git_stash_save(&oid, self.git_repository, [self userSignatureForNow].git_signature, [message cStringUsingEncoding:NSUTF8StringEncoding], stashFlag); + git_signature *sign = (git_signature *)[self userSignatureForNow].git_signature; + + int gitError = git_stash_save(&oid, self.git_repository, sign, [message UTF8String], stashFlag); + if (gitError != GIT_OK) { + if (error != NULL) *error = [NSError git_errorFor:gitError withAdditionalDescription:@"Failed to stash."]; + return nil; + } GTCommit* commit = (GTCommit*)[self lookupObjectByOid:&oid error:error]; From fe57e005d5b3ecf3e31e24b4285daa91c36b9407 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Tue, 2 Jul 2013 12:30:26 +0200 Subject: [PATCH 4/6] Add stash drop & enumeration support. --- Classes/GTRepository.h | 16 ++++++++++++++++ Classes/GTRepository.m | 28 ++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/Classes/GTRepository.h b/Classes/GTRepository.h index b01dcbe38..2dbf8eee7 100644 --- a/Classes/GTRepository.h +++ b/Classes/GTRepository.h @@ -218,6 +218,22 @@ typedef void (^GTRepositoryStatusBlock)(NSURL *fileURL, GTRepositoryFileStatus s // Returns commit of the stashed changes if successful, nil in the even of an error - (GTCommit*)stashChangesWithMessage:(NSString *)message withStashFlag:(GTRepositoryStashFlag)stashFlag error:(NSError **)error; +// Enumerate over all the stashes in the repository +// +// block - A block to execute for each stash found, giving the stash's index and +// message along with its OID. Setting `stop` to YES will cause enumeration +// to stop after the block returns. +// +- (void)enumerateStashes:(void (^)(size_t index, NSString *message, GTOID *oid, BOOL *stop))block; + +// Drop a stash from the repository's list of stashes +// +// index - The index of the stash to drop +// error - If not NULL, set to any error that occurs +// +// Returns YES if the stash was successfully dropped, NO otherwise +- (BOOL)dropStashAtIndex:(size_t)index error:(NSError **)error; + // Reloads all cached information about the receiver's submodules. // // Existing GTSubmodule objects from this repository will be mutated as part of diff --git a/Classes/GTRepository.m b/Classes/GTRepository.m index fc3b7bd4a..40afd0e2a 100644 --- a/Classes/GTRepository.m +++ b/Classes/GTRepository.m @@ -45,6 +45,7 @@ // The type of block passed to -enumerateSubmodulesRecursively:usingBlock:. typedef void (^GTRepositorySubmoduleEnumerationBlock)(GTSubmodule *submodule, BOOL *stop); +typedef void (^GTRepositoryStashEnumerationBlock)(size_t index, NSString *message, GTOID *oid, BOOL *stop); // Used as a payload for submodule enumeration. // @@ -631,5 +632,32 @@ - (GTCommit*)stashChangesWithMessage:(NSString *)message withStashFlag:(GTReposi return commit; } + +static int stashEnumerationCallback(size_t index, const char* message, const git_oid *stash_id, void *payload) { + GTRepositoryStashEnumerationBlock block = (__bridge GTRepositoryStashEnumerationBlock)payload; + + NSString *messageString = @(message); + GTOID *stash_oid = [[GTOID alloc] initWithGitOid:stash_id]; + BOOL stop = NO; + + block(index, messageString, stash_oid, &stop); + + return stop; +} + +- (void)enumerateStashes:(GTRepositoryStashEnumerationBlock)block { + NSParameterAssert(block != nil); + + git_stash_foreach(self.git_repository, &stashEnumerationCallback, &block); +} + +- (BOOL)dropStashAtIndex:(size_t)index error:(NSError **)error { + int gitError = git_stash_drop(self.git_repository, index); + if (gitError != GIT_OK) { + if (error != NULL) *error = [NSError git_errorFor:gitError withAdditionalDescription:@"Failed to drop stash."]; + return FALSE; + } + return TRUE; +} @end From aeda0329be4d95e492832e1aba31e04b5dae8f96 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Wed, 3 Jul 2013 17:30:04 +0200 Subject: [PATCH 5/6] Review. --- Classes/GTRepository.h | 18 ++++++++++-------- Classes/GTRepository.m | 13 +++++++------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/Classes/GTRepository.h b/Classes/GTRepository.h index 2dbf8eee7..c38d678de 100644 --- a/Classes/GTRepository.h +++ b/Classes/GTRepository.h @@ -62,7 +62,9 @@ typedef enum { GTRepositoryResetTypeHard = GIT_RESET_HARD } GTRepositoryResetType; -typedef enum : git_stash_flags { +// Flags for -stashChangesWithMessage:flags:error:. +// Those can be ORed together. See git_stash_flags for additional information. +typedef enum { GTRepositoryStashFlagDefault = GIT_STASH_DEFAULT, GTRepositoryStashFlagKeepIndex = GIT_STASH_KEEP_INDEX, GTRepositoryStashFlagIncludeUntracked = GIT_STASH_INCLUDE_UNTRACKED, @@ -211,20 +213,20 @@ typedef void (^GTRepositoryStatusBlock)(NSURL *fileURL, GTRepositoryFileStatus s // Stash the repository's changes. // -// message - the message to be attributed to the item in the stash. -// stashFlag - The flag of stash to be used. -// error - in the event of an error this may be set. +// message - Optional message to be attributed to the item in the stash. +// stashFlag - The flags of stash to be used. +// error - If not NULL, it will be set on return to any error that occurred // -// Returns commit of the stashed changes if successful, nil in the even of an error -- (GTCommit*)stashChangesWithMessage:(NSString *)message withStashFlag:(GTRepositoryStashFlag)stashFlag error:(NSError **)error; +// Returns commit of the stashed changes if successful, nil otherwise +- (GTCommit *)stashChangesWithMessage:(NSString *)message flags:(GTRepositoryStashFlag)flags error:(NSError **)error; // Enumerate over all the stashes in the repository // // block - A block to execute for each stash found, giving the stash's index and -// message along with its OID. Setting `stop` to YES will cause enumeration +// message along with its OID. Setting `stop` to YES will cause enumeration // to stop after the block returns. // -- (void)enumerateStashes:(void (^)(size_t index, NSString *message, GTOID *oid, BOOL *stop))block; +- (void)enumerateStashesUsingBlock:(void (^)(size_t index, NSString *message, GTOID *oid, BOOL *stop))block; // Drop a stash from the repository's list of stashes // diff --git a/Classes/GTRepository.m b/Classes/GTRepository.m index 40afd0e2a..9238323e2 100644 --- a/Classes/GTRepository.m +++ b/Classes/GTRepository.m @@ -43,7 +43,8 @@ #import "NSError+Git.h" #import "NSString+Git.h" -// The type of block passed to -enumerateSubmodulesRecursively:usingBlock:. +// Blocks typedef for -enumerateSubmodulesRecursively:usingBlock: and +// -enumerateStashesWithBlock:flags:error:. typedef void (^GTRepositorySubmoduleEnumerationBlock)(GTSubmodule *submodule, BOOL *stop); typedef void (^GTRepositoryStashEnumerationBlock)(size_t index, NSString *message, GTOID *oid, BOOL *stop); @@ -617,12 +618,12 @@ - (GTSignature *)userSignatureForNow { #pragma mark Stash -- (GTCommit*)stashChangesWithMessage:(NSString *)message withStashFlag:(GTRepositoryStashFlag)stashFlag error:(NSError **)error +- (GTCommit*)stashChangesWithMessage:(NSString *)message flags:(GTRepositoryStashFlag)flags error:(NSError **)error { git_oid oid; git_signature *sign = (git_signature *)[self userSignatureForNow].git_signature; - int gitError = git_stash_save(&oid, self.git_repository, sign, [message UTF8String], stashFlag); + int gitError = git_stash_save(&oid, self.git_repository, sign, [message UTF8String], flags); if (gitError != GIT_OK) { if (error != NULL) *error = [NSError git_errorFor:gitError withAdditionalDescription:@"Failed to stash."]; return nil; @@ -645,7 +646,7 @@ static int stashEnumerationCallback(size_t index, const char* message, const git return stop; } -- (void)enumerateStashes:(GTRepositoryStashEnumerationBlock)block { +- (void)enumerateStashesUsingBlock:(GTRepositoryStashEnumerationBlock)block { NSParameterAssert(block != nil); git_stash_foreach(self.git_repository, &stashEnumerationCallback, &block); @@ -655,9 +656,9 @@ - (BOOL)dropStashAtIndex:(size_t)index error:(NSError **)error { int gitError = git_stash_drop(self.git_repository, index); if (gitError != GIT_OK) { if (error != NULL) *error = [NSError git_errorFor:gitError withAdditionalDescription:@"Failed to drop stash."]; - return FALSE; + return NO; } - return TRUE; + return YES; } @end From 9b6770395c7cd86b79e1801bc13f688404f7158e Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 6 Jul 2013 10:50:50 +0200 Subject: [PATCH 6/6] Test stashes with empty workdir. --- ObjectiveGitTests/GTRepositorySpec.m | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ObjectiveGitTests/GTRepositorySpec.m b/ObjectiveGitTests/GTRepositorySpec.m index 9f52a3cec..b1146f8d1 100644 --- a/ObjectiveGitTests/GTRepositorySpec.m +++ b/ObjectiveGitTests/GTRepositorySpec.m @@ -51,4 +51,14 @@ }); }); +describe(@"-stashChangesWithMessage:flags:error:", ^{ + it(@"should fail if there's nothing to stash (with default options)", ^{ + NSError *error = nil; + GTCommit *stash = [repository stashChangesWithMessage:nil flags:GTRepositoryStashFlagDefault error:&error]; + expect(stash).to.beNil(); + expect(error).notTo.beNil(); + expect(error.code).to.equal(GIT_ENOTFOUND); + }); +}); + SpecEnd