Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f28bae0

Browse files
author
Edward Thomson
committed
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.
1 parent 5a296ad commit f28bae0

File tree

4 files changed

+62
-24
lines changed

4 files changed

+62
-24
lines changed

include/git2/rebase.h

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,6 @@ typedef struct {
142142
* be populated for operations of type `GIT_REBASE_OPERATION_EXEC`.
143143
*/
144144
const char *exec;
145-
146-
/**
147-
* The index that is the result of an operation.
148-
* This is set only for in-memory rebases.
149-
*/
150-
git_index *index;
151145
} git_rebase_operation;
152146

153147
/**
@@ -247,6 +241,21 @@ GIT_EXTERN(int) git_rebase_next(
247241
git_rebase_operation **operation,
248242
git_rebase *rebase);
249243

244+
/**
245+
* Gets the index produced by the last operation, which is the result
246+
* of `git_rebase_next` and which will be committed by the next
247+
* invocation of `git_rebase_commit`. This is useful for resolving
248+
* conflicts in an in-memory rebase before committing them. You must
249+
* call `git_index_free` when you are finished with this.
250+
*
251+
* This is only applicable for in-memory rebases; for rebases within
252+
* a working directory, the changes were applied to the repository's
253+
* index.
254+
*/
255+
GIT_EXTERN(int) git_rebase_inmemory_index(
256+
git_index **index,
257+
git_rebase *rebase);
258+
250259
/**
251260
* Commits the current patch. You must have resolved any conflicts that
252261
* were introduced during the patch application from the `git_rebase_next`

src/rebase.c

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ struct git_rebase {
7171
size_t current;
7272

7373
/* Used by in-memory rebase */
74+
git_index *index;
7475
git_commit *last_commit;
75-
git_index *last_index;
7676

7777
/* Used by regular (not in-memory) merge-style rebase */
7878
git_oid orig_head_id;
@@ -856,10 +856,13 @@ static int rebase_next_inmemory(
856856
(error = git_merge_trees(&index, rebase->repo, parent_tree, head_tree, current_tree, &rebase->options.merge_options)) < 0)
857857
goto done;
858858

859-
git_index_free(rebase->last_index);
860-
rebase->last_index = index;
861-
operation->index = index;
862-
index = NULL;
859+
if (!rebase->index) {
860+
rebase->index = index;
861+
index = NULL;
862+
} else {
863+
if ((error = git_index_read_index(rebase->index, index)) < 0)
864+
goto done;
865+
}
863866

864867
*out = operation;
865868

@@ -895,6 +898,18 @@ int git_rebase_next(
895898
return error;
896899
}
897900

901+
int git_rebase_inmemory_index(
902+
git_index **out,
903+
git_rebase *rebase)
904+
{
905+
assert(out && rebase && rebase->index);
906+
907+
GIT_REFCOUNT_INC(rebase->index);
908+
*out = rebase->index;
909+
910+
return 0;
911+
}
912+
898913
static int rebase_commit__create(
899914
git_commit **out,
900915
git_rebase *rebase,
@@ -1018,17 +1033,13 @@ static int rebase_commit_inmemory(
10181033
operation = git_array_get(rebase->operations, rebase->current);
10191034

10201035
assert(operation);
1021-
assert(operation->index);
1036+
assert(rebase->index);
10221037
assert(rebase->last_commit);
10231038

1024-
if ((error = rebase_commit__create(&commit, rebase, operation->index,
1039+
if ((error = rebase_commit__create(&commit, rebase, rebase->index,
10251040
rebase->last_commit, author, committer, message_encoding, message)) < 0)
10261041
goto done;
10271042

1028-
git_index_free(rebase->last_index);
1029-
operation->index = NULL;
1030-
rebase->last_index = NULL;
1031-
10321043
git_commit_free(rebase->last_commit);
10331044
rebase->last_commit = commit;
10341045

@@ -1313,7 +1324,7 @@ void git_rebase_free(git_rebase *rebase)
13131324
if (rebase == NULL)
13141325
return;
13151326

1316-
git_index_free(rebase->last_index);
1327+
git_index_free(rebase->index);
13171328
git_commit_free(rebase->last_commit);
13181329
git__free(rebase->onto_name);
13191330
git__free(rebase->orig_head_name);

tests/rebase/inmemory.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ void test_rebase_inmemory__can_resolve_conflicts(void)
5454
git_status_list *status_list;
5555
git_oid pick_id, commit_id, expected_commit_id;
5656
git_signature *signature;
57-
git_index *repo_index;
57+
git_index *rebase_index, *repo_index;
5858
git_index_entry resolution = {{0}};
5959
git_rebase_options opts = GIT_REBASE_OPTIONS_INIT;
6060

@@ -86,16 +86,17 @@ void test_rebase_inmemory__can_resolve_conflicts(void)
8686
cl_assert_equal_i(0, git_status_list_entrycount(status_list));
8787

8888
/* but that the index returned from rebase does have conflicts */
89-
cl_assert(git_index_has_conflicts(rebase_operation->index));
89+
cl_git_pass(git_rebase_inmemory_index(&rebase_index, rebase));
90+
cl_assert(git_index_has_conflicts(rebase_index));
9091

9192
cl_git_fail_with(GIT_EUNMERGED, git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL));
9293

9394
/* ensure that we can work with the in-memory index to resolve the conflict */
9495
resolution.path = "asparagus.txt";
9596
resolution.mode = GIT_FILEMODE_BLOB;
9697
git_oid_fromstr(&resolution.id, "414dfc71ead79c07acd4ea47fecf91f289afc4b9");
97-
cl_git_pass(git_index_conflict_remove(rebase_operation->index, "asparagus.txt"));
98-
cl_git_pass(git_index_add(rebase_operation->index, &resolution));
98+
cl_git_pass(git_index_conflict_remove(rebase_index, "asparagus.txt"));
99+
cl_git_pass(git_index_add(rebase_index, &resolution));
99100

100101
/* and finally create a commit for the resolved rebase operation */
101102
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)
110111
git_reference_free(branch_ref);
111112
git_reference_free(upstream_ref);
112113
git_index_free(repo_index);
114+
git_index_free(rebase_index);
113115
git_rebase_free(rebase);
114116
}

tests/rebase/iterator.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ void test_rebase_iterator__initialize(void)
1313
{
1414
repo = cl_git_sandbox_init("rebase");
1515
cl_git_pass(git_repository_index(&_index, repo));
16-
cl_git_pass(git_signature_now(&signature, "Rebaser", "[email protected]"));
16+
cl_git_pass(git_signature_new(&signature, "Rebaser",
17+
"[email protected]", 1405694510, 0));
1718
}
1819

1920
void test_rebase_iterator__cleanup(void)
@@ -53,7 +54,7 @@ void test_iterator(bool inmemory)
5354
git_reference *branch_ref, *upstream_ref;
5455
git_annotated_commit *branch_head, *upstream_head;
5556
git_rebase_operation *rebase_operation;
56-
git_oid commit_id;
57+
git_oid commit_id, expected_id;
5758
int error;
5859

5960
opts.inmemory = inmemory;
@@ -77,16 +78,25 @@ void test_iterator(bool inmemory)
7778
NULL, NULL));
7879
test_operations(rebase, 0);
7980

81+
git_oid_fromstr(&expected_id, "776e4c48922799f903f03f5f6e51da8b01e4cce0");
82+
cl_assert_equal_oid(&expected_id, &commit_id);
83+
8084
cl_git_pass(git_rebase_next(&rebase_operation, rebase));
8185
cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature,
8286
NULL, NULL));
8387
test_operations(rebase, 1);
8488

89+
git_oid_fromstr(&expected_id, "ba1f9b4fd5cf8151f7818be2111cc0869f1eb95a");
90+
cl_assert_equal_oid(&expected_id, &commit_id);
91+
8592
cl_git_pass(git_rebase_next(&rebase_operation, rebase));
8693
cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature,
8794
NULL, NULL));
8895
test_operations(rebase, 2);
8996

97+
git_oid_fromstr(&expected_id, "948b12fe18b84f756223a61bece4c307787cd5d4");
98+
cl_assert_equal_oid(&expected_id, &commit_id);
99+
90100
if (!inmemory) {
91101
git_rebase_free(rebase);
92102
cl_git_pass(git_rebase_open(&rebase, repo, NULL));
@@ -97,11 +107,17 @@ void test_iterator(bool inmemory)
97107
NULL, NULL));
98108
test_operations(rebase, 3);
99109

110+
git_oid_fromstr(&expected_id, "d9d5d59d72c9968687f9462578d79878cd80e781");
111+
cl_assert_equal_oid(&expected_id, &commit_id);
112+
100113
cl_git_pass(git_rebase_next(&rebase_operation, rebase));
101114
cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature,
102115
NULL, NULL));
103116
test_operations(rebase, 4);
104117

118+
git_oid_fromstr(&expected_id, "9cf383c0a125d89e742c5dec58ed277dd07588b3");
119+
cl_assert_equal_oid(&expected_id, &commit_id);
120+
105121
cl_git_fail(error = git_rebase_next(&rebase_operation, rebase));
106122
cl_assert_equal_i(GIT_ITEROVER, error);
107123
test_operations(rebase, 4);

0 commit comments

Comments
 (0)