From 30640aa9ad574761a3a69244c6194eb626e69d40 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 17 Mar 2015 10:04:08 -0400 Subject: [PATCH 1/9] rebase: identify a rebase that has not started In `git_rebase_operation_current()`, indicate when a rebase has not started (with `GIT_REBASE_NO_OPERATION`) rather than conflating that with the first operation being in-progress. --- CHANGELOG.md | 4 ++++ include/git2/rebase.h | 6 ++++++ src/rebase.c | 2 +- tests/rebase/iterator.c | 2 +- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be8e92400..69c69912d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -101,6 +101,10 @@ v0.22 + 1 * `git_note_default_ref()` now uses a `git_buf` to return the string, as the string is otherwise not guaranteed to stay allocated. +* `git_rebase_operation_current()` will return `GIT_REBASE_NO_OPERATION` + if it is called immediately after creating a rebase session but before + you have applied the first patch. + v0.22 ------ diff --git a/include/git2/rebase.h b/include/git2/rebase.h index 58b66b7fa..3d8d180a5 100644 --- a/include/git2/rebase.h +++ b/include/git2/rebase.h @@ -89,6 +89,9 @@ typedef enum { #define GIT_REBASE_OPTIONS_VERSION 1 #define GIT_REBASE_OPTIONS_INIT {GIT_REBASE_OPTIONS_VERSION} +/** Indicates that a rebase operation is not (yet) in progress. */ +#define GIT_REBASE_NO_OPERATION SIZE_MAX + /** * A rebase operation * @@ -170,6 +173,9 @@ GIT_EXTERN(size_t) git_rebase_operation_entrycount(git_rebase *rebase); /** * Gets the index of the rebase operation that is currently being applied. + * If the first operation has not yet been applied (because you have + * called `init` but not yet `next`) then this returns + * `GIT_REBASE_NO_OPERATION`. * * @param rebase The in-progress rebase * @return The index of the rebase operation currently being applied. diff --git a/src/rebase.c b/src/rebase.c index eb25d4c3a..3bc10f4af 100644 --- a/src/rebase.c +++ b/src/rebase.c @@ -1148,7 +1148,7 @@ size_t git_rebase_operation_current(git_rebase *rebase) { assert(rebase); - return rebase->current; + return rebase->started ? rebase->current : GIT_REBASE_NO_OPERATION; } git_rebase_operation *git_rebase_operation_byindex(git_rebase *rebase, size_t idx) diff --git a/tests/rebase/iterator.c b/tests/rebase/iterator.c index 2cff82ced..23272d51c 100644 --- a/tests/rebase/iterator.c +++ b/tests/rebase/iterator.c @@ -65,7 +65,7 @@ void test_rebase_iterator__iterates(void) cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); - test_operations(rebase, 0); + test_operations(rebase, GIT_REBASE_NO_OPERATION); git_rebase_free(rebase); cl_git_pass(git_rebase_open(&rebase, repo)); From 49b3ddf2167156352eabce9a169fa6649b900631 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 17 Mar 2015 17:45:31 -0400 Subject: [PATCH 2/9] rebase: commit should return GIT_EUNMERGED git_rebase_commit should return `GIT_EUNMERGED` when unmerged items exist in the index, per the documentation. Test that this is correct. --- tests/rebase/merge.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/rebase/merge.c b/tests/rebase/merge.c index f820e96c6..e9390567e 100644 --- a/tests/rebase/merge.c +++ b/tests/rebase/merge.c @@ -90,7 +90,7 @@ void test_rebase_merge__next_with_conflicts(void) git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; git_status_list *status_list; const git_status_entry *status_entry; - git_oid pick_id; + git_oid pick_id, commit_id; const char *expected_merge = "ASPARAGUS SOUP.\n" @@ -139,6 +139,8 @@ void test_rebase_merge__next_with_conflicts(void) cl_assert_equal_file(expected_merge, strlen(expected_merge), "rebase/asparagus.txt"); + cl_git_fail_with(GIT_EUNMERGED, git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); + git_status_list_free(status_list); git_annotated_commit_free(branch_head); git_annotated_commit_free(upstream_head); From eaf0d68830cc8fc56c92733a550ea5f6bc15101d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 17 Mar 2015 17:53:07 -0400 Subject: [PATCH 3/9] rebase: block rebase_commit with unstaged changes --- CHANGELOG.md | 3 +++ src/rebase.c | 50 ++++++++++++++++++++++++++------------------ tests/rebase/merge.c | 35 +++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69c69912d..b7d4aa497 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,9 @@ v0.22 + 1 allow for specifying the expression from the user to be put into the reflog. +* `git_rebase_commit` now return `GIT_EUNMERGED` when you attempt to + commit with unstaged changes. + ### API additions * The `git_merge_options` gained a `file_flags` member. diff --git a/src/rebase.c b/src/rebase.c index 3bc10f4af..f8f4a1b33 100644 --- a/src/rebase.c +++ b/src/rebase.c @@ -504,33 +504,42 @@ static int rebase_ensure_not_in_progress(git_repository *repo) return 0; } -static int rebase_ensure_not_dirty(git_repository *repo) +static int rebase_ensure_not_dirty( + git_repository *repo, + bool check_index, + bool check_workdir, + int fail_with) { git_tree *head = NULL; git_index *index = NULL; git_diff *diff = NULL; int error; - if ((error = git_repository_head_tree(&head, repo)) < 0 || - (error = git_repository_index(&index, repo)) < 0 || - (error = git_diff_tree_to_index(&diff, repo, head, index, NULL)) < 0) - goto done; + if (check_index) { + if ((error = git_repository_head_tree(&head, repo)) < 0 || + (error = git_repository_index(&index, repo)) < 0 || + (error = git_diff_tree_to_index(&diff, repo, head, index, NULL)) < 0) + goto done; - if (git_diff_num_deltas(diff) > 0) { - giterr_set(GITERR_REBASE, "Uncommitted changes exist in index"); - error = -1; - goto done; + if (git_diff_num_deltas(diff) > 0) { + giterr_set(GITERR_REBASE, "Uncommitted changes exist in index"); + error = fail_with; + goto done; + } + + git_diff_free(diff); + diff = NULL; } - git_diff_free(diff); - diff = NULL; + if (check_workdir) { + if ((error = git_diff_index_to_workdir(&diff, repo, index, NULL)) < 0) + goto done; - if ((error = git_diff_index_to_workdir(&diff, repo, index, NULL)) < 0) - goto done; - - if (git_diff_num_deltas(diff) > 0) { - giterr_set(GITERR_REBASE, "Unstaged changes exist in workdir"); - error = -1; + if (git_diff_num_deltas(diff) > 0) { + giterr_set(GITERR_REBASE, "Unstaged changes exist in workdir"); + error = fail_with; + goto done; + } } done: @@ -679,7 +688,7 @@ int git_rebase_init( if ((error = rebase_normalize_opts(repo, &opts, given_opts)) < 0 || (error = git_repository__ensure_not_bare(repo, "rebase")) < 0 || (error = rebase_ensure_not_in_progress(repo)) < 0 || - (error = rebase_ensure_not_dirty(repo)) < 0 || + (error = rebase_ensure_not_dirty(repo, true, true, GIT_ERROR)) < 0 || (error = git_commit_lookup( &onto_commit, repo, git_annotated_commit_id(onto))) < 0) return error; @@ -869,11 +878,12 @@ static int rebase_commit_merge( if (git_index_has_conflicts(index)) { giterr_set(GITERR_REBASE, "Conflicts have not been resolved"); - error = GIT_EMERGECONFLICT; + error = GIT_EUNMERGED; goto done; } - if ((error = git_commit_lookup(¤t_commit, rebase->repo, &operation->id)) < 0 || + if ((error = rebase_ensure_not_dirty(rebase->repo, false, true, GIT_EUNMERGED)) < 0 || + (error = git_commit_lookup(¤t_commit, rebase->repo, &operation->id)) < 0 || (error = git_repository_head(&head, rebase->repo)) < 0 || (error = git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)) < 0 || (error = git_commit_tree(&head_tree, head_commit)) < 0 || diff --git a/tests/rebase/merge.c b/tests/rebase/merge.c index e9390567e..02c39609e 100644 --- a/tests/rebase/merge.c +++ b/tests/rebase/merge.c @@ -264,6 +264,41 @@ void test_rebase_merge__commit(void) git_rebase_free(rebase); } +void test_rebase_merge__blocked_when_dirty(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + git_rebase_operation *rebase_operation; + git_oid commit_id; + + cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef")); + cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); + + cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); + cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); + + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); + + /* Allow untracked files */ + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); + cl_git_mkfile("rebase/untracked_file.txt", "This is untracked\n"); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + /* Do not allow unstaged */ + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); + cl_git_mkfile("rebase/veal.txt", "This is an unstaged change\n"); + cl_git_fail_with(GIT_EUNMERGED, git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + git_annotated_commit_free(branch_head); + git_annotated_commit_free(upstream_head); + git_reference_free(branch_ref); + git_reference_free(upstream_ref); + git_rebase_free(rebase); +} + void test_rebase_merge__commit_updates_rewritten(void) { git_rebase *rebase; From 649834fd6edd5ee2f7cb3e791081b2d57a4d7c41 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 17 Mar 2015 11:46:55 -0400 Subject: [PATCH 4/9] reset: `git_checkout_options` is `const` --- include/git2/reset.h | 4 ++-- src/reset.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/git2/reset.h b/include/git2/reset.h index c03dbed8c..37e578e58 100644 --- a/include/git2/reset.h +++ b/include/git2/reset.h @@ -62,7 +62,7 @@ GIT_EXTERN(int) git_reset( git_repository *repo, git_object *target, git_reset_t reset_type, - git_checkout_options *checkout_opts); + const git_checkout_options *checkout_opts); /** * Sets the current head to the specified commit oid and optionally @@ -80,7 +80,7 @@ GIT_EXTERN(int) git_reset_from_annotated( git_repository *repo, git_annotated_commit *commit, git_reset_t reset_type, - git_checkout_options *checkout_opts); + const git_checkout_options *checkout_opts); /** * Updates some entries in the index from the target commit tree. diff --git a/src/reset.c b/src/reset.c index aaebf4198..d08e48cd7 100644 --- a/src/reset.c +++ b/src/reset.c @@ -102,7 +102,7 @@ static int reset( git_object *target, const char *to, git_reset_t reset_type, - git_checkout_options *checkout_opts) + const git_checkout_options *checkout_opts) { git_object *commit = NULL; git_index *index = NULL; @@ -183,7 +183,7 @@ int git_reset( git_repository *repo, git_object *target, git_reset_t reset_type, - git_checkout_options *checkout_opts) + const git_checkout_options *checkout_opts) { return reset(repo, target, git_oid_tostr_s(git_object_id(target)), reset_type, checkout_opts); } @@ -192,7 +192,7 @@ int git_reset_from_annotated( git_repository *repo, git_annotated_commit *commit, git_reset_t reset_type, - git_checkout_options *checkout_opts) + const git_checkout_options *checkout_opts) { return reset(repo, (git_object *) commit->commit, commit->ref_name, reset_type, checkout_opts); } From 5ae38538c6dd88cca058fac1b84e29df4fed60e4 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 17 Mar 2015 11:47:16 -0400 Subject: [PATCH 5/9] rebase: take `checkout_options` where appropriate --- include/git2/rebase.h | 11 +++++++++-- src/rebase.c | 44 +++++++++++++++++++++++++++-------------- tests/rebase/abort.c | 8 ++++---- tests/rebase/iterator.c | 2 +- tests/rebase/merge.c | 16 +++++++-------- tests/rebase/setup.c | 18 ++++++++--------- 6 files changed, 60 insertions(+), 39 deletions(-) diff --git a/include/git2/rebase.h b/include/git2/rebase.h index 3d8d180a5..8171682e4 100644 --- a/include/git2/rebase.h +++ b/include/git2/rebase.h @@ -143,6 +143,8 @@ GIT_EXTERN(int) git_rebase_init_options( * @param onto The branch to rebase onto, or NULL to rebase onto the given * upstream * @param opts Options to specify how rebase is performed + * @param checkout_opts Options to specify how the checkout to the `onto` + * branch is performed * @return Zero on success; -1 on failure. */ GIT_EXTERN(int) git_rebase_init( @@ -151,7 +153,8 @@ GIT_EXTERN(int) git_rebase_init( const git_annotated_commit *branch, const git_annotated_commit *upstream, const git_annotated_commit *onto, - const git_rebase_options *opts); + const git_rebase_options *opts, + const git_checkout_options *checkout_opts); /** * Opens an existing rebase that was previously started by either an @@ -245,10 +248,14 @@ GIT_EXTERN(int) git_rebase_commit( * and working directory to their state before rebase began. * * @param rebase The rebase that is in-progress + * @param checkout_opts The checkout options that will be used to influence a + * hard reset of the working directory. * @return Zero on success; GIT_ENOTFOUND if a rebase is not in progress, * -1 on other errors. */ -GIT_EXTERN(int) git_rebase_abort(git_rebase *rebase); +GIT_EXTERN(int) git_rebase_abort( + git_rebase *rebase, + const git_checkout_options *checkout_opts); /** * Finishes a rebase that is currently in progress once all patches have diff --git a/src/rebase.c b/src/rebase.c index f8f4a1b33..c51bf6094 100644 --- a/src/rebase.c +++ b/src/rebase.c @@ -658,19 +658,37 @@ done: return error; } +static void normalize_checkout_opts( + git_checkout_options *checkout_opts, + const git_checkout_options *given_checkout_opts) +{ + if (given_checkout_opts != NULL) + memcpy(checkout_opts, given_checkout_opts, sizeof(git_checkout_options)); + else { + git_checkout_options default_checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; + default_checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; + + memcpy(checkout_opts, &default_checkout_opts, sizeof(git_checkout_options)); + } + + if (! (checkout_opts->checkout_strategy & (GIT_CHECKOUT_SAFE | GIT_CHECKOUT_FORCE))) + checkout_opts->checkout_strategy |= GIT_CHECKOUT_SAFE; +} + int git_rebase_init( git_rebase **out, git_repository *repo, const git_annotated_commit *branch, const git_annotated_commit *upstream, const git_annotated_commit *onto, - const git_rebase_options *given_opts) + const git_rebase_options *given_opts, + const git_checkout_options *given_checkout_opts) { git_rebase *rebase = NULL; git_rebase_options opts; git_buf reflog = GIT_BUF_INIT; git_commit *onto_commit = NULL; - git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; + git_checkout_options checkout_opts; git_reference *head_ref = NULL; int error; @@ -679,11 +697,12 @@ int git_rebase_init( *out = NULL; GITERR_CHECK_VERSION(given_opts, GIT_REBASE_OPTIONS_VERSION, "git_rebase_options"); + GITERR_CHECK_VERSION(given_checkout_opts, GIT_CHECKOUT_OPTIONS_VERSION, "git_checkout_options"); if (!onto) onto = upstream; - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; + normalize_checkout_opts(&checkout_opts, given_checkout_opts); if ((error = rebase_normalize_opts(repo, &opts, given_opts)) < 0 || (error = git_repository__ensure_not_bare(repo, "rebase")) < 0 || @@ -723,20 +742,13 @@ done: return error; } -static void normalize_checkout_opts( +static void normalize_checkout_opts_for_apply( git_rebase *rebase, git_commit *current_commit, git_checkout_options *checkout_opts, const git_checkout_options *given_checkout_opts) { - if (given_checkout_opts != NULL) - memcpy(checkout_opts, given_checkout_opts, sizeof(git_checkout_options)); - else { - git_checkout_options default_checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; - default_checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; - - memcpy(checkout_opts, &default_checkout_opts, sizeof(git_checkout_options)); - } + normalize_checkout_opts(checkout_opts, given_checkout_opts); if (!checkout_opts->ancestor_label) checkout_opts->ancestor_label = "ancestor"; @@ -805,7 +817,7 @@ static int rebase_next_merge( git_oid_fmt(current_idstr, &operation->id); - normalize_checkout_opts(rebase, current_commit, &checkout_opts, given_checkout_opts); + normalize_checkout_opts_for_apply(rebase, current_commit, &checkout_opts, given_checkout_opts); if ((error = git_indexwriter_init_for_operation(&indexwriter, rebase->repo, &checkout_opts.checkout_strategy)) < 0 || (error = rebase_setupfile(rebase, MSGNUM_FILE, -1, "%d\n", rebase->current+1)) < 0 || @@ -960,7 +972,9 @@ int git_rebase_commit( return error; } -int git_rebase_abort(git_rebase *rebase) +int git_rebase_abort( + git_rebase *rebase, + const git_checkout_options *checkout_opts) { git_reference *orig_head_ref = NULL; git_commit *orig_head_commit = NULL; @@ -981,7 +995,7 @@ int git_rebase_abort(git_rebase *rebase) if ((error = git_commit_lookup( &orig_head_commit, rebase->repo, &rebase->orig_head_id)) < 0 || (error = git_reset(rebase->repo, (git_object *)orig_head_commit, - GIT_RESET_HARD, NULL)) < 0) + GIT_RESET_HARD, checkout_opts)) < 0) goto done; error = rebase_cleanup(rebase); diff --git a/tests/rebase/abort.c b/tests/rebase/abort.c index 24af2d140..a04a34b5c 100644 --- a/tests/rebase/abort.c +++ b/tests/rebase/abort.c @@ -28,7 +28,7 @@ static void test_abort(git_annotated_commit *branch, git_annotated_commit *onto) const git_reflog_entry *reflog_entry; cl_git_pass(git_rebase_open(&rebase, repo)); - cl_git_pass(git_rebase_abort(rebase)); + cl_git_pass(git_rebase_abort(rebase, NULL)); cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo)); @@ -73,7 +73,7 @@ void test_rebase_abort__merge(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&onto_head, repo, onto_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL, NULL)); cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); test_abort(branch_head, onto_head); @@ -102,7 +102,7 @@ void test_rebase_abort__detached_head(void) cl_git_pass(git_signature_new(&signature, "Rebaser", "rebaser@example.com", 1404157834, -400)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL, NULL)); cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); test_abort(branch_head, onto_head); @@ -131,7 +131,7 @@ void test_rebase_abort__old_style_head_file(void) cl_git_pass(git_signature_new(&signature, "Rebaser", "rebaser@example.com", 1404157834, -400)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL, NULL)); cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); p_rename("rebase-merge/.git/rebase-merge/orig-head", diff --git a/tests/rebase/iterator.c b/tests/rebase/iterator.c index 23272d51c..d2f4278cc 100644 --- a/tests/rebase/iterator.c +++ b/tests/rebase/iterator.c @@ -64,7 +64,7 @@ void test_rebase_iterator__iterates(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); test_operations(rebase, GIT_REBASE_NO_OPERATION); git_rebase_free(rebase); diff --git a/tests/rebase/merge.c b/tests/rebase/merge.c index 02c39609e..ade6f5cf6 100644 --- a/tests/rebase/merge.c +++ b/tests/rebase/merge.c @@ -53,7 +53,7 @@ void test_rebase_merge__next(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); @@ -120,7 +120,7 @@ void test_rebase_merge__next_with_conflicts(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); @@ -167,7 +167,7 @@ void test_rebase_merge__next_stops_with_iterover(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, @@ -223,7 +223,7 @@ void test_rebase_merge__commit(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, @@ -316,7 +316,7 @@ void test_rebase_merge__commit_updates_rewritten(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, @@ -356,7 +356,7 @@ void test_rebase_merge__commit_drops_already_applied(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); cl_git_fail(error = git_rebase_commit(&commit_id, rebase, NULL, signature, @@ -399,7 +399,7 @@ void test_rebase_merge__finish(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, @@ -470,7 +470,7 @@ static void test_copy_note( git_commit_id(branch_commit), "This is a commit note.", 0)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, opts)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, opts, NULL)); cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, diff --git a/tests/rebase/setup.c b/tests/rebase/setup.c index 627d3b9de..61d886978 100644 --- a/tests/rebase/setup.c +++ b/tests/rebase/setup.c @@ -39,12 +39,12 @@ void test_rebase_setup__blocked_when_in_progress(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); git_rebase_free(rebase); cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); - cl_git_fail(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); + cl_git_fail(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); git_annotated_commit_free(branch_head); git_annotated_commit_free(upstream_head); @@ -70,7 +70,7 @@ void test_rebase_setup__merge(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); @@ -118,7 +118,7 @@ void test_rebase_setup__merge_root(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&onto_head, repo, onto_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL, NULL)); git_oid_fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00"); cl_git_pass(git_repository_head(&head, repo)); @@ -168,7 +168,7 @@ void test_rebase_setup__merge_onto_and_upstream(void) cl_git_pass(git_annotated_commit_from_ref(&branch2_head, repo, branch2_ref)); cl_git_pass(git_annotated_commit_from_ref(&onto_head, repo, onto_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch1_head, branch2_head, onto_head, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch1_head, branch2_head, onto_head, NULL, NULL)); git_oid_fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00"); cl_git_pass(git_repository_head(&head, repo)); @@ -215,7 +215,7 @@ void test_rebase_setup__branch_with_merges(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); @@ -263,7 +263,7 @@ void test_rebase_setup__orphan_branch(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); @@ -314,7 +314,7 @@ void test_rebase_setup__merge_null_branch_uses_HEAD(void) cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, NULL, upstream_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, NULL, upstream_head, NULL, NULL, NULL)); cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); @@ -358,7 +358,7 @@ static int rebase_is_blocked(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - error = git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL); + error = git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL); git_annotated_commit_free(branch_head); git_annotated_commit_free(upstream_head); From f3a199dd9952a885621848c82b7b68c78723a9ed Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 17 Mar 2015 15:53:04 -0400 Subject: [PATCH 6/9] rebase: init and open take a rebase_options `git_rebase_init` and `git_rebase_open` should take a `git_rebase_options` and use it for future rebase operations on that `rebase` object. --- CHANGELOG.md | 8 ++ include/git2/rebase.h | 54 +++++----- src/rebase.c | 232 ++++++++++++++++++++-------------------- tests/rebase/abort.c | 10 +- tests/rebase/iterator.c | 21 ++-- tests/rebase/merge.c | 76 +++++-------- tests/rebase/setup.c | 18 ++-- 7 files changed, 205 insertions(+), 214 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7d4aa497..b97360c9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -108,6 +108,14 @@ v0.22 + 1 if it is called immediately after creating a rebase session but before you have applied the first patch. +* `git_rebase_options` now contains an optional pointer to + `git_checkout_options` that will be used for functions that modify + the working directory, namely `git_checkout_init`, `git_checkout_next` + and `git_checkout_abort`. As a result, `git_rebase_open` now also + takes a `git_rebase_options` and only the `git_rebase_init` and + `git_rebase_open` functions take a `git_rebase_options`, where they + will persist the options to subsequent `git_rebase` calls. + v0.22 ------ diff --git a/include/git2/rebase.h b/include/git2/rebase.h index 8171682e4..370792f58 100644 --- a/include/git2/rebase.h +++ b/include/git2/rebase.h @@ -30,19 +30,32 @@ typedef struct { unsigned int version; /** - * Provide a quiet rebase experience; unused by libgit2 but provided for - * interoperability with other clients. + * Used by `git_rebase_init`, this will instruct other clients working + * on this rebase that you want a quiet rebase experience, which they + * may choose to provide in an application-specific manner. This has no + * effect upon libgit2 directly, but is provided for interoperability with + * other clients. */ int quiet; /** - * Canonical name of the notes reference used to rewrite notes for - * rebased commits when finishing the rebase; if NULL, the contents of - * the coniguration option `notes.rewriteRef` is examined, unless the - * configuration option `notes.rewrite.rebase` is set to false. If - * `notes.rewriteRef` is NULL, notes will not be rewritten. + * Used by `git_rebase_finish`, this is the canonical name of the notes + * reference used to rewrite notes for rebased commits when finishing the + * rebase; if NULL, the contents of the coniguration option + * `notes.rewriteRef` is examined, unless the configuration option + * `notes.rewrite.rebase` is set to false. If `notes.rewriteRef` is also + * NULL, notes will not be rewritten. */ const char *rewrite_notes_ref; + + /** + * Options to control how files are written during `git_rebase_init`, + * `git_checkout_next` and `git_checkout_abort`. Note that a minimum + * strategy of `GIT_CHECKOUT_SAFE` is defaulted in `init` and `next`, + * and a minimum strategy of `GIT_CHECKOUT_FORCE` is defaulted in + * `abort` to match git semantics. + */ + git_checkout_options *checkout_options; } git_rebase_options; /** @@ -142,9 +155,7 @@ GIT_EXTERN(int) git_rebase_init_options( * reachable commits * @param onto The branch to rebase onto, or NULL to rebase onto the given * upstream - * @param opts Options to specify how rebase is performed - * @param checkout_opts Options to specify how the checkout to the `onto` - * branch is performed + * @param opts Options to specify how rebase is performed, or NULL * @return Zero on success; -1 on failure. */ GIT_EXTERN(int) git_rebase_init( @@ -153,8 +164,7 @@ GIT_EXTERN(int) git_rebase_init( const git_annotated_commit *branch, const git_annotated_commit *upstream, const git_annotated_commit *onto, - const git_rebase_options *opts, - const git_checkout_options *checkout_opts); + const git_rebase_options *opts); /** * Opens an existing rebase that was previously started by either an @@ -162,9 +172,13 @@ GIT_EXTERN(int) git_rebase_init( * * @param out Pointer to store the rebase object * @param repo The repository that has a rebase in-progress + * @param opts Options to specify how rebase is performed * @return Zero on success; -1 on failure. */ -GIT_EXTERN(int) git_rebase_open(git_rebase **out, git_repository *repo); +GIT_EXTERN(int) git_rebase_open( + git_rebase **out, + git_repository *repo, + const git_rebase_options *opts); /** * Gets the count of rebase operations that are to be applied. @@ -205,13 +219,11 @@ GIT_EXTERN(git_rebase_operation *) git_rebase_operation_byindex( * * @param operation Pointer to store the rebase operation that is to be performed next * @param rebase The 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_rebase *rebase, - git_checkout_options *checkout_opts); + git_rebase *rebase); /** * Commits the current patch. You must have resolved any conflicts that @@ -248,14 +260,10 @@ GIT_EXTERN(int) git_rebase_commit( * and working directory to their state before rebase began. * * @param rebase The rebase that is in-progress - * @param checkout_opts The checkout options that will be used to influence a - * hard reset of the working directory. * @return Zero on success; GIT_ENOTFOUND if a rebase is not in progress, * -1 on other errors. */ -GIT_EXTERN(int) git_rebase_abort( - git_rebase *rebase, - const git_checkout_options *checkout_opts); +GIT_EXTERN(int) git_rebase_abort(git_rebase *rebase); /** * Finishes a rebase that is currently in progress once all patches have @@ -263,13 +271,11 @@ GIT_EXTERN(int) git_rebase_abort( * * @param rebase The rebase that is in-progress * @param signature The identity that is finishing the rebase (optional) - * @param opts Options to specify how rebase is finished * @return Zero on success; -1 on error */ GIT_EXTERN(int) git_rebase_finish( git_rebase *rebase, - const git_signature *signature, - const git_rebase_options *opts); + const git_signature *signature); /** * Frees the `git_rebase` object. diff --git a/src/rebase.c b/src/rebase.c index c51bf6094..5f1ba563a 100644 --- a/src/rebase.c +++ b/src/rebase.c @@ -57,6 +57,9 @@ typedef enum { struct git_rebase { git_repository *repo; + git_rebase_options options; + git_checkout_options checkout_options; + git_rebase_type_t type; char *state_path; @@ -249,7 +252,50 @@ done: return error; } -int git_rebase_open(git_rebase **out, git_repository *repo) +static git_rebase *rebase_alloc(const git_rebase_options *rebase_opts) +{ + git_rebase *rebase = git__calloc(1, sizeof(git_rebase)); + + if (!rebase) + return NULL; + + if (rebase_opts) + memcpy(&rebase->options, rebase_opts, sizeof(git_rebase_options)); + else + git_rebase_init_options(&rebase->options, GIT_REBASE_OPTIONS_VERSION); + + if (rebase_opts && rebase_opts->checkout_options) + memcpy(&rebase->checkout_options, rebase_opts->checkout_options, sizeof(git_checkout_options)); + else + git_checkout_init_options(&rebase->checkout_options, GIT_CHECKOUT_OPTIONS_VERSION); + + if (rebase_opts && rebase_opts->rewrite_notes_ref) { + if ((rebase->options.rewrite_notes_ref = git__strdup(rebase_opts->rewrite_notes_ref)) == NULL) + return NULL; + } + + rebase->options.checkout_options = NULL; + + if ((rebase->checkout_options.checkout_strategy & (GIT_CHECKOUT_SAFE | GIT_CHECKOUT_FORCE)) == 0) + rebase->checkout_options.checkout_strategy = GIT_CHECKOUT_SAFE; + + return rebase; +} + +static int rebase_check_versions(const git_rebase_options *given_opts) +{ + GITERR_CHECK_VERSION(given_opts, GIT_REBASE_OPTIONS_VERSION, "git_rebase_options"); + + if (given_opts) + GITERR_CHECK_VERSION(given_opts->checkout_options, GIT_CHECKOUT_OPTIONS_VERSION, "git_checkout_options"); + + return 0; +} + +int git_rebase_open( + git_rebase **out, + git_repository *repo, + const git_rebase_options *given_opts) { git_rebase *rebase; git_buf path = GIT_BUF_INIT, orig_head_name = GIT_BUF_INIT, @@ -258,7 +304,10 @@ int git_rebase_open(git_rebase **out, git_repository *repo) assert(repo); - rebase = git__calloc(1, sizeof(git_rebase)); + if ((error = rebase_check_versions(given_opts)) < 0) + return error; + + rebase = rebase_alloc(given_opts); GITERR_CHECK_ALLOC(rebase); rebase->repo = repo; @@ -446,48 +495,6 @@ int git_rebase_init_options(git_rebase_options *opts, unsigned int version) return 0; } -static int rebase_normalize_opts( - git_repository *repo, - git_rebase_options *opts, - const git_rebase_options *given_opts) -{ - git_rebase_options default_opts = GIT_REBASE_OPTIONS_INIT; - git_config *config; - - if (given_opts) - memcpy(opts, given_opts, sizeof(git_rebase_options)); - else - memcpy(opts, &default_opts, sizeof(git_rebase_options)); - - if (git_repository_config(&config, repo) < 0) - return -1; - - if (given_opts && given_opts->rewrite_notes_ref) { - opts->rewrite_notes_ref = git__strdup(given_opts->rewrite_notes_ref); - GITERR_CHECK_ALLOC(opts->rewrite_notes_ref); - } else if (git_config__get_bool_force(config, "notes.rewrite.rebase", 1)) { - char *rewrite_ref = git_config__get_string_force( - config, "notes.rewriteref", NOTES_DEFAULT_REF); - - if (rewrite_ref) { - opts->rewrite_notes_ref = rewrite_ref; - GITERR_CHECK_ALLOC(opts->rewrite_notes_ref); - } - } - - git_config_free(config); - - return 0; -} - -static void rebase_opts_free(git_rebase_options *opts) -{ - if (!opts) - return; - - git__free((char *)opts->rewrite_notes_ref); -} - static int rebase_ensure_not_in_progress(git_repository *repo) { int error; @@ -616,8 +623,7 @@ static int rebase_init( git_repository *repo, const git_annotated_commit *branch, const git_annotated_commit *upstream, - const git_annotated_commit *onto, - const git_rebase_options *opts) + const git_annotated_commit *onto) { git_reference *head_ref = NULL; git_annotated_commit *head_branch = NULL; @@ -639,7 +645,7 @@ static int rebase_init( rebase->type = GIT_REBASE_TYPE_MERGE; rebase->state_path = git_buf_detach(&state_path); rebase->orig_head_name = git__strdup(branch->ref_name ? branch->ref_name : ORIG_DETACHED_HEAD); - rebase->quiet = opts->quiet; + rebase->quiet = rebase->options.quiet; git_oid_cpy(&rebase->orig_head_id, git_annotated_commit_id(branch)); git_oid_cpy(&rebase->onto_id, git_annotated_commit_id(onto)); @@ -658,37 +664,17 @@ done: return error; } -static void normalize_checkout_opts( - git_checkout_options *checkout_opts, - const git_checkout_options *given_checkout_opts) -{ - if (given_checkout_opts != NULL) - memcpy(checkout_opts, given_checkout_opts, sizeof(git_checkout_options)); - else { - git_checkout_options default_checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; - default_checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; - - memcpy(checkout_opts, &default_checkout_opts, sizeof(git_checkout_options)); - } - - if (! (checkout_opts->checkout_strategy & (GIT_CHECKOUT_SAFE | GIT_CHECKOUT_FORCE))) - checkout_opts->checkout_strategy |= GIT_CHECKOUT_SAFE; -} - int git_rebase_init( git_rebase **out, git_repository *repo, const git_annotated_commit *branch, const git_annotated_commit *upstream, const git_annotated_commit *onto, - const git_rebase_options *given_opts, - const git_checkout_options *given_checkout_opts) + const git_rebase_options *given_opts) { git_rebase *rebase = NULL; - git_rebase_options opts; git_buf reflog = GIT_BUF_INIT; git_commit *onto_commit = NULL; - git_checkout_options checkout_opts; git_reference *head_ref = NULL; int error; @@ -696,15 +682,10 @@ int git_rebase_init( *out = NULL; - GITERR_CHECK_VERSION(given_opts, GIT_REBASE_OPTIONS_VERSION, "git_rebase_options"); - GITERR_CHECK_VERSION(given_checkout_opts, GIT_CHECKOUT_OPTIONS_VERSION, "git_checkout_options"); - if (!onto) onto = upstream; - normalize_checkout_opts(&checkout_opts, given_checkout_opts); - - if ((error = rebase_normalize_opts(repo, &opts, given_opts)) < 0 || + if ((error = rebase_check_versions(given_opts)) < 0 || (error = git_repository__ensure_not_bare(repo, "rebase")) < 0 || (error = rebase_ensure_not_in_progress(repo)) < 0 || (error = rebase_ensure_not_dirty(repo, true, true, GIT_ERROR)) < 0 || @@ -712,16 +693,15 @@ int git_rebase_init( &onto_commit, repo, git_annotated_commit_id(onto))) < 0) return error; - rebase = git__calloc(1, sizeof(git_rebase)); - GITERR_CHECK_ALLOC(rebase); + rebase = rebase_alloc(given_opts); if ((error = rebase_init( - rebase, repo, branch, upstream, onto, &opts)) < 0 || + rebase, repo, branch, upstream, onto)) < 0 || (error = rebase_setupfiles(rebase)) < 0 || (error = git_buf_printf(&reflog, "rebase: checkout %s", rebase_onto_name(onto))) < 0 || (error = git_checkout_tree( - repo, (git_object *)onto_commit, &checkout_opts)) < 0 || + repo, (git_object *)onto_commit, &rebase->checkout_options)) < 0 || (error = git_reference_create(&head_ref, repo, GIT_HEAD_FILE, git_annotated_commit_id(onto), 1, reflog.ptr)) < 0) goto done; @@ -737,18 +717,16 @@ done: git_commit_free(onto_commit); git_buf_free(&reflog); - rebase_opts_free(&opts); return error; } -static void normalize_checkout_opts_for_apply( - git_rebase *rebase, - git_commit *current_commit, +static void normalize_checkout_options_for_apply( git_checkout_options *checkout_opts, - const git_checkout_options *given_checkout_opts) + git_rebase *rebase, + git_commit *current_commit) { - normalize_checkout_opts(checkout_opts, given_checkout_opts); + memcpy(checkout_opts, &rebase->checkout_options, sizeof(git_checkout_options)); if (!checkout_opts->ancestor_label) checkout_opts->ancestor_label = "ancestor"; @@ -779,16 +757,15 @@ GIT_INLINE(int) rebase_movenext(git_rebase *rebase) static int rebase_next_merge( git_rebase_operation **out, - git_rebase *rebase, - git_checkout_options *given_checkout_opts) + git_rebase *rebase) { git_buf path = GIT_BUF_INIT; - git_checkout_options checkout_opts = {0}; git_commit *current_commit = NULL, *parent_commit = NULL; git_tree *current_tree = NULL, *head_tree = NULL, *parent_tree = NULL; git_index *index = NULL; git_indexwriter indexwriter = GIT_INDEXWRITER_INIT; git_rebase_operation *operation; + git_checkout_options checkout_opts; char current_idstr[GIT_OID_HEXSZ]; unsigned int parent_count; int error; @@ -817,7 +794,7 @@ static int rebase_next_merge( git_oid_fmt(current_idstr, &operation->id); - normalize_checkout_opts_for_apply(rebase, current_commit, &checkout_opts, given_checkout_opts); + normalize_checkout_options_for_apply(&checkout_opts, rebase, current_commit); if ((error = git_indexwriter_init_for_operation(&indexwriter, rebase->repo, &checkout_opts.checkout_strategy)) < 0 || (error = rebase_setupfile(rebase, MSGNUM_FILE, -1, "%d\n", rebase->current+1)) < 0 || @@ -845,8 +822,7 @@ done: int git_rebase_next( git_rebase_operation **out, - git_rebase *rebase, - git_checkout_options *checkout_opts) + git_rebase *rebase) { int error; @@ -854,7 +830,7 @@ int git_rebase_next( switch (rebase->type) { case GIT_REBASE_TYPE_MERGE: - error = rebase_next_merge(out, rebase, checkout_opts); + error = rebase_next_merge(out, rebase); break; default: abort(); @@ -972,9 +948,7 @@ int git_rebase_commit( return error; } -int git_rebase_abort( - git_rebase *rebase, - const git_checkout_options *checkout_opts) +int git_rebase_abort(git_rebase *rebase) { git_reference *orig_head_ref = NULL; git_commit *orig_head_commit = NULL; @@ -995,7 +969,7 @@ int git_rebase_abort( if ((error = git_commit_lookup( &orig_head_commit, rebase->repo, &rebase->orig_head_id)) < 0 || (error = git_reset(rebase->repo, (git_object *)orig_head_commit, - GIT_RESET_HARD, checkout_opts)) < 0) + GIT_RESET_HARD, &rebase->checkout_options)) < 0) goto done; error = rebase_cleanup(rebase); @@ -1007,19 +981,50 @@ done: return error; } +static int notes_ref_lookup(git_buf *out, git_rebase *rebase) +{ + git_config *config = NULL; + int do_rewrite, error; + + if (rebase->options.rewrite_notes_ref) { + git_buf_attach_notowned(out, + rebase->options.rewrite_notes_ref, + strlen(rebase->options.rewrite_notes_ref)); + return 0; + } + + if ((error = git_repository_config(&config, rebase->repo)) < 0 || + (error = git_config_get_bool(&do_rewrite, config, "notes.rewrite.rebase")) < 0) { + + if (error != GIT_ENOTFOUND) + goto done; + + giterr_clear(); + do_rewrite = 1; + } + + error = do_rewrite ? + git_config_get_string_buf(out, config, "notes.rewriteref") : + GIT_ENOTFOUND; + +done: + git_config_free(config); + return error; +} + static int rebase_copy_note( git_rebase *rebase, + const char *notes_ref, git_oid *from, git_oid *to, - const git_signature *committer, - const git_rebase_options *opts) + const git_signature *committer) { git_note *note = NULL; git_oid note_id; git_signature *who = NULL; int error; - if ((error = git_note_read(¬e, rebase->repo, opts->rewrite_notes_ref, from)) < 0) { + if ((error = git_note_read(¬e, rebase->repo, notes_ref, from)) < 0) { if (error == GIT_ENOTFOUND) { giterr_clear(); error = 0; @@ -1040,7 +1045,7 @@ static int rebase_copy_note( committer = who; } - error = git_note_create(¬e_id, rebase->repo, opts->rewrite_notes_ref, + error = git_note_create(¬e_id, rebase->repo, notes_ref, git_note_author(note), committer, to, git_note_message(note), 0); done: @@ -1052,17 +1057,22 @@ done: static int rebase_copy_notes( git_rebase *rebase, - const git_signature *committer, - const git_rebase_options *opts) + const git_signature *committer) { - git_buf path = GIT_BUF_INIT, rewritten = GIT_BUF_INIT; + git_buf path = GIT_BUF_INIT, rewritten = GIT_BUF_INIT, notes_ref = GIT_BUF_INIT; char *pair_list, *fromstr, *tostr, *end; git_oid from, to; unsigned int linenum = 1; int error = 0; - if (!opts->rewrite_notes_ref) + if ((error = notes_ref_lookup(¬es_ref, rebase)) < 0) { + if (error == GIT_ENOTFOUND) { + giterr_clear(); + error = 0; + } + goto done; + } if ((error = git_buf_joinpath(&path, rebase->state_path, REWRITTEN_FILE)) < 0 || (error = git_futils_readbuffer(&rewritten, path.ptr)) < 0) @@ -1091,7 +1101,7 @@ static int rebase_copy_notes( git_oid_fromstr(&to, tostr) < 0) goto on_error; - if ((error = rebase_copy_note(rebase, &from, &to, committer, opts)) < 0) + if ((error = rebase_copy_note(rebase, notes_ref.ptr, &from, &to, committer)) < 0) goto done; linenum++; @@ -1106,16 +1116,15 @@ on_error: done: git_buf_free(&rewritten); git_buf_free(&path); + git_buf_free(¬es_ref); return error; } int git_rebase_finish( git_rebase *rebase, - const git_signature *signature, - const git_rebase_options *given_opts) + const git_signature *signature) { - git_rebase_options opts; git_reference *terminal_ref = NULL, *branch_ref = NULL, *head_ref = NULL; git_commit *terminal_commit = NULL; git_buf branch_msg = GIT_BUF_INIT, head_msg = GIT_BUF_INIT; @@ -1124,11 +1133,6 @@ int git_rebase_finish( assert(rebase); - GITERR_CHECK_VERSION(given_opts, GIT_REBASE_OPTIONS_VERSION, "git_rebase_options"); - - if ((error = rebase_normalize_opts(rebase->repo, &opts, given_opts)) < 0) - goto done; - git_oid_fmt(onto, &rebase->onto_id); if ((error = git_buf_printf(&branch_msg, "rebase finished: %s onto %.*s", @@ -1144,7 +1148,7 @@ int git_rebase_finish( (error = git_reference_symbolic_create(&head_ref, rebase->repo, GIT_HEAD_FILE, rebase->orig_head_name, 1, head_msg.ptr)) < 0 || - (error = rebase_copy_notes(rebase, signature, &opts)) < 0) + (error = rebase_copy_notes(rebase, signature)) < 0) goto done; error = rebase_cleanup(rebase); @@ -1156,7 +1160,6 @@ done: git_reference_free(head_ref); git_reference_free(branch_ref); git_reference_free(terminal_ref); - rebase_opts_free(&opts); return error; } @@ -1191,5 +1194,6 @@ void git_rebase_free(git_rebase *rebase) git__free(rebase->orig_head_name); git__free(rebase->state_path); git_array_clear(rebase->operations); + git__free((char *)rebase->options.rewrite_notes_ref); git__free(rebase); } diff --git a/tests/rebase/abort.c b/tests/rebase/abort.c index a04a34b5c..c4b3890bc 100644 --- a/tests/rebase/abort.c +++ b/tests/rebase/abort.c @@ -27,8 +27,8 @@ static void test_abort(git_annotated_commit *branch, git_annotated_commit *onto) git_reflog *reflog; const git_reflog_entry *reflog_entry; - cl_git_pass(git_rebase_open(&rebase, repo)); - cl_git_pass(git_rebase_abort(rebase, NULL)); + cl_git_pass(git_rebase_open(&rebase, repo, NULL)); + cl_git_pass(git_rebase_abort(rebase)); cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo)); @@ -73,7 +73,7 @@ void test_rebase_abort__merge(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&onto_head, repo, onto_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL)); cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); test_abort(branch_head, onto_head); @@ -102,7 +102,7 @@ void test_rebase_abort__detached_head(void) cl_git_pass(git_signature_new(&signature, "Rebaser", "rebaser@example.com", 1404157834, -400)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL)); cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); test_abort(branch_head, onto_head); @@ -131,7 +131,7 @@ void test_rebase_abort__old_style_head_file(void) cl_git_pass(git_signature_new(&signature, "Rebaser", "rebaser@example.com", 1404157834, -400)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL)); cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); p_rename("rebase-merge/.git/rebase-merge/orig-head", diff --git a/tests/rebase/iterator.c b/tests/rebase/iterator.c index d2f4278cc..acf2a92db 100644 --- a/tests/rebase/iterator.c +++ b/tests/rebase/iterator.c @@ -52,52 +52,49 @@ void test_rebase_iterator__iterates(void) git_reference *branch_ref, *upstream_ref; git_annotated_commit *branch_head, *upstream_head; git_rebase_operation *rebase_operation; - git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; git_oid commit_id; int error; - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; - cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef")); cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); test_operations(rebase, GIT_REBASE_NO_OPERATION); git_rebase_free(rebase); - cl_git_pass(git_rebase_open(&rebase, repo)); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_open(&rebase, repo, NULL)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); test_operations(rebase, 0); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); test_operations(rebase, 1); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); test_operations(rebase, 2); git_rebase_free(rebase); - cl_git_pass(git_rebase_open(&rebase, repo)); + cl_git_pass(git_rebase_open(&rebase, repo, NULL)); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); test_operations(rebase, 3); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); test_operations(rebase, 4); - cl_git_fail(error = git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_fail(error = git_rebase_next(&rebase_operation, rebase)); cl_assert_equal_i(GIT_ITEROVER, error); test_operations(rebase, 4); diff --git a/tests/rebase/merge.c b/tests/rebase/merge.c index ade6f5cf6..7aea4f088 100644 --- a/tests/rebase/merge.c +++ b/tests/rebase/merge.c @@ -40,22 +40,19 @@ void test_rebase_merge__next(void) git_reference *branch_ref, *upstream_ref; git_annotated_commit *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, file1_id; - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; - cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef")); cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); git_oid_fromstr(&pick_id, "da9c51a23d02d931a486f45ad18cda05cf5d2b94"); @@ -87,7 +84,6 @@ void test_rebase_merge__next_with_conflicts(void) git_reference *branch_ref, *upstream_ref; git_annotated_commit *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, commit_id; @@ -112,17 +108,15 @@ void test_rebase_merge__next_with_conflicts(void) "asparagus which had been laid by, boil it until these last articles are\n" "sufficiently done, thicken with flour, butter and milk, and serve it up.\n"; - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; - cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/asparagus")); cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); git_oid_fromstr(&pick_id, "33f915f9e4dbd9f4b24430e48731a59b45b15500"); @@ -155,41 +149,38 @@ void test_rebase_merge__next_stops_with_iterover(void) git_reference *branch_ref, *upstream_ref; git_annotated_commit *branch_head, *upstream_head; git_rebase_operation *rebase_operation; - git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; git_oid commit_id; int error; - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; - cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef")); cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); - cl_git_fail(error = git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_fail(error = git_rebase_next(&rebase_operation, rebase)); cl_assert_equal_i(GIT_ITEROVER, error); cl_assert_equal_file("5\n", 2, "rebase/.git/rebase-merge/end"); @@ -208,24 +199,21 @@ void test_rebase_merge__commit(void) git_reference *branch_ref, *upstream_ref; git_annotated_commit *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; git_commit *commit; git_reflog *reflog; const git_reflog_entry *reflog_entry; - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; - cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef")); cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); @@ -305,24 +293,21 @@ void test_rebase_merge__commit_updates_rewritten(void) git_reference *branch_ref, *upstream_ref; git_annotated_commit *branch_head, *upstream_head; git_rebase_operation *rebase_operation; - git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; git_oid commit_id; - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; - cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef")); cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); @@ -344,27 +329,24 @@ void test_rebase_merge__commit_drops_already_applied(void) git_reference *branch_ref, *upstream_ref; git_annotated_commit *branch_head, *upstream_head; git_rebase_operation *rebase_operation; - git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; git_oid commit_id; int error; - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; - cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef")); cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/green_pea")); cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_fail(error = git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); cl_assert_equal_i(GIT_EAPPLIED, error); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); @@ -385,30 +367,27 @@ void test_rebase_merge__finish(void) git_reference *branch_ref, *upstream_ref, *head_ref; git_annotated_commit *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; const git_reflog_entry *reflog_entry; int error; - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; - cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/gravy")); cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/veal")); cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); - cl_git_fail(error = git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_fail(error = git_rebase_next(&rebase_operation, rebase)); cl_assert_equal_i(GIT_ITEROVER, error); - cl_git_pass(git_rebase_finish(rebase, signature, NULL)); + cl_git_pass(git_rebase_finish(rebase, signature)); cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo)); @@ -448,13 +427,10 @@ static void test_copy_note( git_annotated_commit *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; int error; - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; - cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/gravy")); cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/veal")); @@ -470,13 +446,13 @@ static void test_copy_note( git_commit_id(branch_commit), "This is a commit note.", 0)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, opts, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, opts)); - cl_git_pass(git_rebase_next(&rebase_operation, rebase, &checkout_opts)); + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); - cl_git_pass(git_rebase_finish(rebase, signature, opts)); + cl_git_pass(git_rebase_finish(rebase, signature)); cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo)); diff --git a/tests/rebase/setup.c b/tests/rebase/setup.c index 61d886978..627d3b9de 100644 --- a/tests/rebase/setup.c +++ b/tests/rebase/setup.c @@ -39,12 +39,12 @@ void test_rebase_setup__blocked_when_in_progress(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); git_rebase_free(rebase); cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); - cl_git_fail(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); + cl_git_fail(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); git_annotated_commit_free(branch_head); git_annotated_commit_free(upstream_head); @@ -70,7 +70,7 @@ void test_rebase_setup__merge(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); @@ -118,7 +118,7 @@ void test_rebase_setup__merge_root(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&onto_head, repo, onto_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, NULL, onto_head, NULL)); git_oid_fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00"); cl_git_pass(git_repository_head(&head, repo)); @@ -168,7 +168,7 @@ void test_rebase_setup__merge_onto_and_upstream(void) cl_git_pass(git_annotated_commit_from_ref(&branch2_head, repo, branch2_ref)); cl_git_pass(git_annotated_commit_from_ref(&onto_head, repo, onto_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch1_head, branch2_head, onto_head, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch1_head, branch2_head, onto_head, NULL)); git_oid_fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00"); cl_git_pass(git_repository_head(&head, repo)); @@ -215,7 +215,7 @@ void test_rebase_setup__branch_with_merges(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); @@ -263,7 +263,7 @@ void test_rebase_setup__orphan_branch(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL)); cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); @@ -314,7 +314,7 @@ void test_rebase_setup__merge_null_branch_uses_HEAD(void) cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - cl_git_pass(git_rebase_init(&rebase, repo, NULL, upstream_head, NULL, NULL, NULL)); + cl_git_pass(git_rebase_init(&rebase, repo, NULL, upstream_head, NULL, NULL)); cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo)); @@ -358,7 +358,7 @@ static int rebase_is_blocked(void) cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); - error = git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL, NULL); + error = git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, NULL); git_annotated_commit_free(branch_head); git_annotated_commit_free(upstream_head); From 7838235890b10e1e3c6ceb2c696c4721ad438246 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 17 Mar 2015 17:21:11 -0400 Subject: [PATCH 7/9] rebase: test checkout options for rebase --- tests/rebase/merge.c | 49 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/rebase/merge.c b/tests/rebase/merge.c index 7aea4f088..4371f1f1f 100644 --- a/tests/rebase/merge.c +++ b/tests/rebase/merge.c @@ -510,3 +510,52 @@ void test_rebase_merge__copy_notes_disabled_in_config(void) test_copy_note(NULL, 0); } +void rebase_checkout_progress_cb( + const char *path, + size_t completed_steps, + size_t total_steps, + void *payload) +{ + int *called = payload; + *called = 1; +} + +void test_rebase_merge__custom_checkout_options(void) +{ + git_rebase *rebase; + git_reference *branch_ref, *upstream_ref; + git_annotated_commit *branch_head, *upstream_head; + git_rebase_options rebase_options = GIT_REBASE_OPTIONS_INIT; + git_checkout_options checkout_options = GIT_CHECKOUT_OPTIONS_INIT; + git_rebase_operation *rebase_operation; + int called = 0; + + checkout_options.progress_cb = rebase_checkout_progress_cb; + checkout_options.progress_payload = &called; + + rebase_options.checkout_options = &checkout_options; + + cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef")); + cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); + + cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); + cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); + + called = 0; + cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, &rebase_options)); + cl_assert_equal_i(1, called); + + called = 0; + cl_git_pass(git_rebase_next(&rebase_operation, rebase)); + cl_assert_equal_i(1, called); + + called = 0; + cl_git_pass(git_rebase_abort(rebase)); + cl_assert_equal_i(1, called); + + git_annotated_commit_free(branch_head); + git_annotated_commit_free(upstream_head); + git_reference_free(branch_ref); + git_reference_free(upstream_ref); + git_rebase_free(rebase); +} From 94c988f6d6f4930ee4c120f6ce7932b5e49637be Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 20 Apr 2015 17:19:08 -0400 Subject: [PATCH 8/9] rebase: include checkout opts within rebase opts --- include/git2/rebase.h | 5 +++-- src/rebase.c | 20 ++++++-------------- tests/rebase/merge.c | 3 ++- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/include/git2/rebase.h b/include/git2/rebase.h index 370792f58..b85f7e2aa 100644 --- a/include/git2/rebase.h +++ b/include/git2/rebase.h @@ -55,7 +55,7 @@ typedef struct { * and a minimum strategy of `GIT_CHECKOUT_FORCE` is defaulted in * `abort` to match git semantics. */ - git_checkout_options *checkout_options; + git_checkout_options checkout_options; } git_rebase_options; /** @@ -100,7 +100,8 @@ typedef enum { } git_rebase_operation_t; #define GIT_REBASE_OPTIONS_VERSION 1 -#define GIT_REBASE_OPTIONS_INIT {GIT_REBASE_OPTIONS_VERSION} +#define GIT_REBASE_OPTIONS_INIT \ + {GIT_REBASE_OPTIONS_VERSION, 0, NULL, GIT_CHECKOUT_OPTIONS_INIT} /** Indicates that a rebase operation is not (yet) in progress. */ #define GIT_REBASE_NO_OPERATION SIZE_MAX diff --git a/src/rebase.c b/src/rebase.c index 5f1ba563a..b636e7951 100644 --- a/src/rebase.c +++ b/src/rebase.c @@ -58,7 +58,6 @@ struct git_rebase { git_repository *repo; git_rebase_options options; - git_checkout_options checkout_options; git_rebase_type_t type; char *state_path; @@ -264,20 +263,13 @@ static git_rebase *rebase_alloc(const git_rebase_options *rebase_opts) else git_rebase_init_options(&rebase->options, GIT_REBASE_OPTIONS_VERSION); - if (rebase_opts && rebase_opts->checkout_options) - memcpy(&rebase->checkout_options, rebase_opts->checkout_options, sizeof(git_checkout_options)); - else - git_checkout_init_options(&rebase->checkout_options, GIT_CHECKOUT_OPTIONS_VERSION); - if (rebase_opts && rebase_opts->rewrite_notes_ref) { if ((rebase->options.rewrite_notes_ref = git__strdup(rebase_opts->rewrite_notes_ref)) == NULL) return NULL; } - rebase->options.checkout_options = NULL; - - if ((rebase->checkout_options.checkout_strategy & (GIT_CHECKOUT_SAFE | GIT_CHECKOUT_FORCE)) == 0) - rebase->checkout_options.checkout_strategy = GIT_CHECKOUT_SAFE; + if ((rebase->options.checkout_options.checkout_strategy & (GIT_CHECKOUT_SAFE | GIT_CHECKOUT_FORCE)) == 0) + rebase->options.checkout_options.checkout_strategy = GIT_CHECKOUT_SAFE; return rebase; } @@ -287,7 +279,7 @@ static int rebase_check_versions(const git_rebase_options *given_opts) GITERR_CHECK_VERSION(given_opts, GIT_REBASE_OPTIONS_VERSION, "git_rebase_options"); if (given_opts) - GITERR_CHECK_VERSION(given_opts->checkout_options, GIT_CHECKOUT_OPTIONS_VERSION, "git_checkout_options"); + GITERR_CHECK_VERSION(&given_opts->checkout_options, GIT_CHECKOUT_OPTIONS_VERSION, "git_checkout_options"); return 0; } @@ -701,7 +693,7 @@ int git_rebase_init( (error = git_buf_printf(&reflog, "rebase: checkout %s", rebase_onto_name(onto))) < 0 || (error = git_checkout_tree( - repo, (git_object *)onto_commit, &rebase->checkout_options)) < 0 || + repo, (git_object *)onto_commit, &rebase->options.checkout_options)) < 0 || (error = git_reference_create(&head_ref, repo, GIT_HEAD_FILE, git_annotated_commit_id(onto), 1, reflog.ptr)) < 0) goto done; @@ -726,7 +718,7 @@ static void normalize_checkout_options_for_apply( git_rebase *rebase, git_commit *current_commit) { - memcpy(checkout_opts, &rebase->checkout_options, sizeof(git_checkout_options)); + memcpy(checkout_opts, &rebase->options.checkout_options, sizeof(git_checkout_options)); if (!checkout_opts->ancestor_label) checkout_opts->ancestor_label = "ancestor"; @@ -969,7 +961,7 @@ int git_rebase_abort(git_rebase *rebase) if ((error = git_commit_lookup( &orig_head_commit, rebase->repo, &rebase->orig_head_id)) < 0 || (error = git_reset(rebase->repo, (git_object *)orig_head_commit, - GIT_RESET_HARD, &rebase->checkout_options)) < 0) + GIT_RESET_HARD, &rebase->options.checkout_options)) < 0) goto done; error = rebase_cleanup(rebase); diff --git a/tests/rebase/merge.c b/tests/rebase/merge.c index 4371f1f1f..12f0de5a0 100644 --- a/tests/rebase/merge.c +++ b/tests/rebase/merge.c @@ -533,7 +533,8 @@ void test_rebase_merge__custom_checkout_options(void) checkout_options.progress_cb = rebase_checkout_progress_cb; checkout_options.progress_payload = &called; - rebase_options.checkout_options = &checkout_options; + memcpy(&rebase_options.checkout_options, &checkout_options, + sizeof(git_checkout_options)); cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef")); cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); From aa9bb425a951565663cf15e23e41b00ac46bf1a5 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 20 Apr 2015 17:22:39 -0400 Subject: [PATCH 9/9] rebase: correct documentation, CHANGELOG --- CHANGELOG.md | 2 +- include/git2/rebase.h | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b97360c9e..12c60532c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ v0.22 + 1 allow for specifying the expression from the user to be put into the reflog. -* `git_rebase_commit` now return `GIT_EUNMERGED` when you attempt to +* `git_rebase_commit` now returns `GIT_EUNMERGED` when you attempt to commit with unstaged changes. ### API additions diff --git a/include/git2/rebase.h b/include/git2/rebase.h index b85f7e2aa..d9aa175c7 100644 --- a/include/git2/rebase.h +++ b/include/git2/rebase.h @@ -33,18 +33,18 @@ typedef struct { * Used by `git_rebase_init`, this will instruct other clients working * on this rebase that you want a quiet rebase experience, which they * may choose to provide in an application-specific manner. This has no - * effect upon libgit2 directly, but is provided for interoperability with - * other clients. + * effect upon libgit2 directly, but is provided for interoperability + * between Git tools. */ int quiet; /** - * Used by `git_rebase_finish`, this is the canonical name of the notes - * reference used to rewrite notes for rebased commits when finishing the - * rebase; if NULL, the contents of the coniguration option - * `notes.rewriteRef` is examined, unless the configuration option - * `notes.rewrite.rebase` is set to false. If `notes.rewriteRef` is also - * NULL, notes will not be rewritten. + * Used by `git_rebase_finish`, this is the name of the notes reference + * used to rewrite notes for rebased commits when finishing the rebase; + * if NULL, the contents of the coniguration option `notes.rewriteRef` + * is examined, unless the configuration option `notes.rewrite.rebase` + * is set to false. If `notes.rewriteRef` is also NULL, notes will + * not be rewritten. */ const char *rewrite_notes_ref;