summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@github.com>2016-02-15 17:16:00 +0000
committerEdward Thomson <ethomson@github.com>2016-02-15 19:27:06 +0000
commitf28bae0c380467409515ffd25247f3204dcc4019 (patch)
tree437cafaa9d8afc0b59c6b63bd5d5cf068fc52fe7
parent5a296ad07ea5536a0ac2f17921f2839612d838d3 (diff)
downloadlibgit2-f28bae0c380467409515ffd25247f3204dcc4019.tar.gz
rebase: persist a single in-memory index
When performing an in-memory rebase, keep a single index for the duration, so that callers have the expected index lifecycle and do not hold on to an index that is free'd out from under them.
-rw-r--r--include/git2/rebase.h21
-rw-r--r--src/rebase.c35
-rw-r--r--tests/rebase/inmemory.c10
-rw-r--r--tests/rebase/iterator.c20
4 files changed, 62 insertions, 24 deletions
diff --git a/include/git2/rebase.h b/include/git2/rebase.h
index 4fda1fd2f..ece8b3664 100644
--- a/include/git2/rebase.h
+++ b/include/git2/rebase.h
@@ -142,12 +142,6 @@ typedef struct {
* be populated for operations of type `GIT_REBASE_OPERATION_EXEC`.
*/
const char *exec;
-
- /**
- * The index that is the result of an operation.
- * This is set only for in-memory rebases.
- */
- git_index *index;
} git_rebase_operation;
/**
@@ -248,6 +242,21 @@ GIT_EXTERN(int) git_rebase_next(
git_rebase *rebase);
/**
+ * Gets the index produced by the last operation, which is the result
+ * of `git_rebase_next` and which will be committed by the next
+ * invocation of `git_rebase_commit`. This is useful for resolving
+ * conflicts in an in-memory rebase before committing them. You must
+ * call `git_index_free` when you are finished with this.
+ *
+ * This is only applicable for in-memory rebases; for rebases within
+ * a working directory, the changes were applied to the repository's
+ * index.
+ */
+GIT_EXTERN(int) git_rebase_inmemory_index(
+ git_index **index,
+ git_rebase *rebase);
+
+/**
* Commits the current patch. You must have resolved any conflicts that
* were introduced during the patch application from the `git_rebase_next`
* invocation.
diff --git a/src/rebase.c b/src/rebase.c
index 52a6df032..b9d1d4fc5 100644
--- a/src/rebase.c
+++ b/src/rebase.c
@@ -71,8 +71,8 @@ struct git_rebase {
size_t current;
/* Used by in-memory rebase */
+ git_index *index;
git_commit *last_commit;
- git_index *last_index;
/* Used by regular (not in-memory) merge-style rebase */
git_oid orig_head_id;
@@ -856,10 +856,13 @@ static int rebase_next_inmemory(
(error = git_merge_trees(&index, rebase->repo, parent_tree, head_tree, current_tree, &rebase->options.merge_options)) < 0)
goto done;
- git_index_free(rebase->last_index);
- rebase->last_index = index;
- operation->index = index;
- index = NULL;
+ if (!rebase->index) {
+ rebase->index = index;
+ index = NULL;
+ } else {
+ if ((error = git_index_read_index(rebase->index, index)) < 0)
+ goto done;
+ }
*out = operation;
@@ -895,6 +898,18 @@ int git_rebase_next(
return error;
}
+int git_rebase_inmemory_index(
+ git_index **out,
+ git_rebase *rebase)
+{
+ assert(out && rebase && rebase->index);
+
+ GIT_REFCOUNT_INC(rebase->index);
+ *out = rebase->index;
+
+ return 0;
+}
+
static int rebase_commit__create(
git_commit **out,
git_rebase *rebase,
@@ -1018,17 +1033,13 @@ static int rebase_commit_inmemory(
operation = git_array_get(rebase->operations, rebase->current);
assert(operation);
- assert(operation->index);
+ assert(rebase->index);
assert(rebase->last_commit);
- if ((error = rebase_commit__create(&commit, rebase, operation->index,
+ if ((error = rebase_commit__create(&commit, rebase, rebase->index,
rebase->last_commit, author, committer, message_encoding, message)) < 0)
goto done;
- git_index_free(rebase->last_index);
- operation->index = NULL;
- rebase->last_index = NULL;
-
git_commit_free(rebase->last_commit);
rebase->last_commit = commit;
@@ -1313,7 +1324,7 @@ void git_rebase_free(git_rebase *rebase)
if (rebase == NULL)
return;
- git_index_free(rebase->last_index);
+ git_index_free(rebase->index);
git_commit_free(rebase->last_commit);
git__free(rebase->onto_name);
git__free(rebase->orig_head_name);
diff --git a/tests/rebase/inmemory.c b/tests/rebase/inmemory.c
index c7942d6af..d5d89c719 100644
--- a/tests/rebase/inmemory.c
+++ b/tests/rebase/inmemory.c
@@ -54,7 +54,7 @@ void test_rebase_inmemory__can_resolve_conflicts(void)
git_status_list *status_list;
git_oid pick_id, commit_id, expected_commit_id;
git_signature *signature;
- git_index *repo_index;
+ git_index *rebase_index, *repo_index;
git_index_entry resolution = {{0}};
git_rebase_options opts = GIT_REBASE_OPTIONS_INIT;
@@ -86,7 +86,8 @@ void test_rebase_inmemory__can_resolve_conflicts(void)
cl_assert_equal_i(0, git_status_list_entrycount(status_list));
/* but that the index returned from rebase does have conflicts */
- cl_assert(git_index_has_conflicts(rebase_operation->index));
+ cl_git_pass(git_rebase_inmemory_index(&rebase_index, rebase));
+ cl_assert(git_index_has_conflicts(rebase_index));
cl_git_fail_with(GIT_EUNMERGED, git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL));
@@ -94,8 +95,8 @@ void test_rebase_inmemory__can_resolve_conflicts(void)
resolution.path = "asparagus.txt";
resolution.mode = GIT_FILEMODE_BLOB;
git_oid_fromstr(&resolution.id, "414dfc71ead79c07acd4ea47fecf91f289afc4b9");
- cl_git_pass(git_index_conflict_remove(rebase_operation->index, "asparagus.txt"));
- cl_git_pass(git_index_add(rebase_operation->index, &resolution));
+ cl_git_pass(git_index_conflict_remove(rebase_index, "asparagus.txt"));
+ cl_git_pass(git_index_add(rebase_index, &resolution));
/* and finally create a commit for the resolved rebase operation */
cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL));
@@ -110,5 +111,6 @@ void test_rebase_inmemory__can_resolve_conflicts(void)
git_reference_free(branch_ref);
git_reference_free(upstream_ref);
git_index_free(repo_index);
+ git_index_free(rebase_index);
git_rebase_free(rebase);
}
diff --git a/tests/rebase/iterator.c b/tests/rebase/iterator.c
index e761d39d3..db57b0a83 100644
--- a/tests/rebase/iterator.c
+++ b/tests/rebase/iterator.c
@@ -13,7 +13,8 @@ void test_rebase_iterator__initialize(void)
{
repo = cl_git_sandbox_init("rebase");
cl_git_pass(git_repository_index(&_index, repo));
- cl_git_pass(git_signature_now(&signature, "Rebaser", "rebaser@rebaser.rb"));
+ cl_git_pass(git_signature_new(&signature, "Rebaser",
+ "rebaser@rebaser.rb", 1405694510, 0));
}
void test_rebase_iterator__cleanup(void)
@@ -53,7 +54,7 @@ void test_iterator(bool inmemory)
git_reference *branch_ref, *upstream_ref;
git_annotated_commit *branch_head, *upstream_head;
git_rebase_operation *rebase_operation;
- git_oid commit_id;
+ git_oid commit_id, expected_id;
int error;
opts.inmemory = inmemory;
@@ -77,16 +78,25 @@ void test_iterator(bool inmemory)
NULL, NULL));
test_operations(rebase, 0);
+ git_oid_fromstr(&expected_id, "776e4c48922799f903f03f5f6e51da8b01e4cce0");
+ cl_assert_equal_oid(&expected_id, &commit_id);
+
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);
+ git_oid_fromstr(&expected_id, "ba1f9b4fd5cf8151f7818be2111cc0869f1eb95a");
+ cl_assert_equal_oid(&expected_id, &commit_id);
+
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_oid_fromstr(&expected_id, "948b12fe18b84f756223a61bece4c307787cd5d4");
+ cl_assert_equal_oid(&expected_id, &commit_id);
+
if (!inmemory) {
git_rebase_free(rebase);
cl_git_pass(git_rebase_open(&rebase, repo, NULL));
@@ -97,11 +107,17 @@ void test_iterator(bool inmemory)
NULL, NULL));
test_operations(rebase, 3);
+ git_oid_fromstr(&expected_id, "d9d5d59d72c9968687f9462578d79878cd80e781");
+ cl_assert_equal_oid(&expected_id, &commit_id);
+
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);
+ git_oid_fromstr(&expected_id, "9cf383c0a125d89e742c5dec58ed277dd07588b3");
+ cl_assert_equal_oid(&expected_id, &commit_id);
+
cl_git_fail(error = git_rebase_next(&rebase_operation, rebase));
cl_assert_equal_i(GIT_ITEROVER, error);
test_operations(rebase, 4);