diff options
-rw-r--r-- | include/git2/rebase.h | 74 | ||||
-rw-r--r-- | src/rebase.c | 11 | ||||
-rw-r--r-- | tests/rebase/merge.c | 51 |
3 files changed, 111 insertions, 25 deletions
diff --git a/include/git2/rebase.h b/include/git2/rebase.h index d9cf2318e..3b4f44709 100644 --- a/include/git2/rebase.h +++ b/include/git2/rebase.h @@ -39,9 +39,67 @@ typedef struct { const char *rewrite_notes_ref; } git_rebase_options; +/** Type of rebase operation in-progress after calling `git_rebase_next`. */ +typedef enum { + /** + * The given commit is to be cherry-picked. The client should commit + * the changes and continue if there are no conflicts. + */ + GIT_REBASE_OPERATION_PICK = 0, + + /** + * The given commit is to be cherry-picked, but the client should prompt + * the user to provide an updated commit message. + */ + GIT_REBASE_OPERATION_REWORD, + + /** + * The given commit is to be cherry-picked, but the client should stop + * to allow the user to edit the changes before committing them. + */ + GIT_REBASE_OPERATION_EDIT, + + /** + * The given commit is to be squashed into the previous commit. The + * commit message will be merged with the previous message. + */ + GIT_REBASE_OPERATION_SQUASH, + + /** + * The given commit is to be squashed into the previous commit. The + * commit message from this commit will be discarded. + */ + GIT_REBASE_OPERATION_FIXUP, + + /** + * No commit will be cherry-picked. The client should run the given + * command and (if successful) continue. + */ + GIT_REBASE_OPERATION_EXEC, +} git_rebase_operation_t; + #define GIT_REBASE_OPTIONS_VERSION 1 #define GIT_REBASE_OPTIONS_INIT {GIT_REBASE_OPTIONS_VERSION} +typedef struct { + /** The type of rebase operation. */ + unsigned int type; + + union { + /** + * The commit ID being cherry-picked. This will be populated for + * all operations except those of type `GIT_REBASE_OPERATION_EXEC`. + */ + git_oid id; + + /** + * The executable the user has requested be run. This will only + * be populated for operations of type `GIT_REBASE_OPERATION_EXEC`. + */ + const char *exec; + }; +} git_rebase_operation; + /** * Initializes a `git_rebase_options` with default values. Equivalent to * creating an instance with GIT_REBASE_OPTIONS_INIT. @@ -78,15 +136,19 @@ GIT_EXTERN(int) git_rebase( const git_rebase_options *opts); /** - * Applies the next patch, updating the index and working directory with the - * changes. If there are conflicts, you will need to address those before - * committing the changes. + * Performs the next rebase operation and returns the information about it. + * If the operation is one that applies a patch (which is any operation except + * GIT_REBASE_OPERATION_EXEC) then the patch will be applied and the index and + * working directory will be updated with the changes. If there are conflicts, + * you will need to address those before committing the changes. * + * @param out The rebase operation that is to be performed next * @param repo The repository with a rebase in progress * @param checkout_opts Options to specify how the patch should be checked out * @return Zero on success; -1 on failure. */ GIT_EXTERN(int) git_rebase_next( + git_rebase_operation *operation, git_repository *repo, git_checkout_options *checkout_opts); @@ -94,7 +156,7 @@ GIT_EXTERN(int) git_rebase_next( * Commits the current patch. You must have resolved any conflicts that * were introduced during the patch application from the `git_rebase_next` * invocation. - * + * * @param id Pointer in which to store the OID of the newly created commit * @param repo The repository with the in-progress rebase * @param author The author of the updated commit, or NULL to keep the @@ -105,8 +167,8 @@ GIT_EXTERN(int) git_rebase_next( * this should also be NULL, and the encoding from the original * commit will be maintained. If message is specified, this may be * NULL to indicate that "UTF-8" is to be used. - * @param message The message for this commit, or NULL to keep the message - * from the original commit + * @param message The message for this commit, or NULL to use the message + * from the original commit. * @return Zero on success, GIT_EUNMERGED if there are unmerged changes in * the index, GIT_EAPPLIED if the current commit has already * been applied to the upstream and there is nothing to commit, diff --git a/src/rebase.c b/src/rebase.c index 3384a14f2..c6bbfbfb8 100644 --- a/src/rebase.c +++ b/src/rebase.c @@ -624,6 +624,7 @@ static int normalize_checkout_opts( } static int rebase_next_merge( + git_rebase_operation *out, git_repository *repo, git_rebase_state *state, git_checkout_options *given_checkout_opts) @@ -678,6 +679,9 @@ static int rebase_next_merge( (error = git_checkout_index(repo, index, &checkout_opts)) < 0) goto done; + out->type = GIT_REBASE_OPERATION_PICK; + memcpy(&out->id, ¤t_id, sizeof(git_oid)); + done: git_index_free(index); git_tree_free(current_tree); @@ -691,20 +695,23 @@ done: } int git_rebase_next( + git_rebase_operation *out, git_repository *repo, git_checkout_options *checkout_opts) { git_rebase_state state = GIT_REBASE_STATE_INIT; int error; - assert(repo); + assert(out && repo); + + memset(out, 0, sizeof(git_rebase_operation)); if ((error = rebase_state(&state, repo)) < 0) return -1; switch (state.type) { case GIT_REBASE_TYPE_MERGE: - error = rebase_next_merge(repo, &state, checkout_opts); + error = rebase_next_merge(out, repo, &state, checkout_opts); break; default: abort(); diff --git a/tests/rebase/merge.c b/tests/rebase/merge.c index fddab8397..a3bb711b2 100644 --- a/tests/rebase/merge.c +++ b/tests/rebase/merge.c @@ -26,10 +26,11 @@ void test_rebase_merge__next(void) { git_reference *branch_ref, *upstream_ref; git_merge_head *branch_head, *upstream_head; + git_rebase_operation rebase_operation; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; git_status_list *status_list; const git_status_entry *status_entry; - git_oid file1_id; + git_oid pick_id, file1_id; checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; @@ -41,8 +42,12 @@ void test_rebase_merge__next(void) cl_git_pass(git_rebase(repo, branch_head, upstream_head, NULL, signature, NULL)); - cl_git_pass(git_rebase_next(repo, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, repo, &checkout_opts)); + git_oid_fromstr(&pick_id, "da9c51a23d02d931a486f45ad18cda05cf5d2b94"); + + cl_assert_equal_i(GIT_REBASE_OPERATION_PICK, rebase_operation.type); + cl_assert_equal_oid(&pick_id, &rebase_operation.id); cl_assert_equal_file("da9c51a23d02d931a486f45ad18cda05cf5d2b94\n", 41, "rebase/.git/rebase-merge/current"); cl_assert_equal_file("1\n", 2, "rebase/.git/rebase-merge/msgnum"); @@ -66,9 +71,11 @@ void test_rebase_merge__next_with_conflicts(void) { git_reference *branch_ref, *upstream_ref; git_merge_head *branch_head, *upstream_head; + git_rebase_operation rebase_operation; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; git_status_list *status_list; const git_status_entry *status_entry; + git_oid pick_id; const char *expected_merge = "ASPARAGUS SOUP.\n" @@ -100,8 +107,12 @@ void test_rebase_merge__next_with_conflicts(void) cl_git_pass(git_rebase(repo, branch_head, upstream_head, NULL, signature, NULL)); - cl_git_pass(git_rebase_next(repo, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, repo, &checkout_opts)); + + git_oid_fromstr(&pick_id, "33f915f9e4dbd9f4b24430e48731a59b45b15500"); + cl_assert_equal_i(GIT_REBASE_OPERATION_PICK, rebase_operation.type); + cl_assert_equal_oid(&pick_id, &rebase_operation.id); cl_assert_equal_file("33f915f9e4dbd9f4b24430e48731a59b45b15500\n", 41, "rebase/.git/rebase-merge/current"); cl_assert_equal_file("1\n", 2, "rebase/.git/rebase-merge/msgnum"); @@ -124,6 +135,7 @@ void test_rebase_merge__next_stops_with_iterover(void) { git_reference *branch_ref, *upstream_ref; git_merge_head *branch_head, *upstream_head; + git_rebase_operation rebase_operation; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; git_oid commit_id; int error; @@ -138,27 +150,27 @@ void test_rebase_merge__next_stops_with_iterover(void) cl_git_pass(git_rebase(repo, branch_head, upstream_head, NULL, signature, NULL)); - cl_git_pass(git_rebase_next(repo, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, repo, &checkout_opts)); cl_git_pass(git_rebase_commit(&commit_id, repo, NULL, signature, NULL, NULL)); - cl_git_pass(git_rebase_next(repo, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, repo, &checkout_opts)); cl_git_pass(git_rebase_commit(&commit_id, repo, NULL, signature, NULL, NULL)); - cl_git_pass(git_rebase_next(repo, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, repo, &checkout_opts)); cl_git_pass(git_rebase_commit(&commit_id, repo, NULL, signature, NULL, NULL)); - cl_git_pass(git_rebase_next(repo, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, repo, &checkout_opts)); cl_git_pass(git_rebase_commit(&commit_id, repo, NULL, signature, NULL, NULL)); - cl_git_pass(git_rebase_next(repo, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, repo, &checkout_opts)); cl_git_pass(git_rebase_commit(&commit_id, repo, NULL, signature, NULL, NULL)); - cl_git_fail(error = git_rebase_next(repo, &checkout_opts)); + cl_git_fail(error = git_rebase_next(&rebase_operation, repo, &checkout_opts)); cl_assert_equal_i(GIT_ITEROVER, error); cl_assert_equal_file("5\n", 2, "rebase/.git/rebase-merge/end"); @@ -174,6 +186,7 @@ void test_rebase_merge__commit(void) { git_reference *branch_ref, *upstream_ref; git_merge_head *branch_head, *upstream_head; + git_rebase_operation rebase_operation; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; git_oid commit_id, tree_id, parent_id; git_signature *author; @@ -191,7 +204,7 @@ void test_rebase_merge__commit(void) cl_git_pass(git_rebase(repo, branch_head, upstream_head, NULL, signature, NULL)); - cl_git_pass(git_rebase_next(repo, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, repo, &checkout_opts)); cl_git_pass(git_rebase_commit(&commit_id, repo, NULL, signature, NULL, NULL)); @@ -233,6 +246,7 @@ void test_rebase_merge__commit_updates_rewritten(void) { git_reference *branch_ref, *upstream_ref; git_merge_head *branch_head, *upstream_head; + git_rebase_operation rebase_operation; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; git_oid commit_id; @@ -246,11 +260,11 @@ void test_rebase_merge__commit_updates_rewritten(void) cl_git_pass(git_rebase(repo, branch_head, upstream_head, NULL, signature, NULL)); - cl_git_pass(git_rebase_next(repo, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, repo, &checkout_opts)); cl_git_pass(git_rebase_commit(&commit_id, repo, NULL, signature, NULL, NULL)); - cl_git_pass(git_rebase_next(repo, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, repo, &checkout_opts)); cl_git_pass(git_rebase_commit(&commit_id, repo, NULL, signature, NULL, NULL)); @@ -269,6 +283,7 @@ void test_rebase_merge__commit_drops_already_applied(void) { git_reference *branch_ref, *upstream_ref; git_merge_head *branch_head, *upstream_head; + git_rebase_operation rebase_operation; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; git_oid commit_id; int error; @@ -283,13 +298,13 @@ void test_rebase_merge__commit_drops_already_applied(void) cl_git_pass(git_rebase(repo, branch_head, upstream_head, NULL, signature, NULL)); - cl_git_pass(git_rebase_next(repo, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, repo, &checkout_opts)); cl_git_fail(error = git_rebase_commit(&commit_id, repo, NULL, signature, NULL, NULL)); cl_assert_equal_i(GIT_EAPPLIED, error); - cl_git_pass(git_rebase_next(repo, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, repo, &checkout_opts)); cl_git_pass(git_rebase_commit(&commit_id, repo, NULL, signature, NULL, NULL)); @@ -307,6 +322,7 @@ void test_rebase_merge__finish(void) { git_reference *branch_ref, *upstream_ref, *head_ref; git_merge_head *branch_head, *upstream_head; + git_rebase_operation rebase_operation; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; git_oid commit_id; git_reflog *reflog; @@ -323,11 +339,11 @@ void test_rebase_merge__finish(void) cl_git_pass(git_rebase(repo, branch_head, upstream_head, NULL, signature, NULL)); - cl_git_pass(git_rebase_next(repo, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, repo, &checkout_opts)); cl_git_pass(git_rebase_commit(&commit_id, repo, NULL, signature, NULL, NULL)); - cl_git_fail(error = git_rebase_next(repo, &checkout_opts)); + cl_git_fail(error = git_rebase_next(&rebase_operation, repo, &checkout_opts)); cl_assert_equal_i(GIT_ITEROVER, error); cl_git_pass(git_rebase_finish(repo, signature, NULL)); @@ -367,6 +383,7 @@ static void test_copy_note( git_reference *branch_ref, *upstream_ref; git_merge_head *branch_head, *upstream_head; git_commit *branch_commit; + git_rebase_operation rebase_operation; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; git_oid note_id, commit_id; git_note *note = NULL; @@ -391,7 +408,7 @@ static void test_copy_note( cl_git_pass(git_rebase(repo, branch_head, upstream_head, NULL, signature, opts)); - cl_git_pass(git_rebase_next(repo, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, repo, &checkout_opts)); cl_git_pass(git_rebase_commit(&commit_id, repo, NULL, signature, NULL, NULL)); |