From 5baa20b86e23ace3817c4ed38f9de7ea57dcf4a3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 1 Jun 2016 14:52:25 -0500 Subject: [PATCH 1/7] round-trip trees through index_read_index Read a tree into an index using `git_index_read_index` (by reading a tree into a new index, then reading that index into the current index), then write the index back out, ensuring that our new index is treesame to the tree that we read. --- tests/index/read_index.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/index/read_index.c b/tests/index/read_index.c index 82a771d54..30adc0388 100644 --- a/tests/index/read_index.c +++ b/tests/index/read_index.c @@ -71,3 +71,35 @@ void test_index_read_index__maintains_stat_cache(void) } } } + +static bool roundtrip_with_read_index(const char *tree_idstr) +{ + git_oid tree_id, new_tree_id; + git_tree *tree; + git_index *tree_index; + + cl_git_pass(git_oid_fromstr(&tree_id, tree_idstr)); + cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id)); + cl_git_pass(git_index_new(&tree_index)); + cl_git_pass(git_index_read_tree(tree_index, tree)); + cl_git_pass(git_index_read_index(_index, tree_index)); + cl_git_pass(git_index_write_tree(&new_tree_id, _index)); + + git_tree_free(tree); + git_index_free(tree_index); + + return git_oid_equal(&tree_id, &new_tree_id); +} + +void test_index_read_index__produces_treesame_indexes(void) +{ + roundtrip_with_read_index("53fc32d17276939fc79ed05badaef2db09990016"); + roundtrip_with_read_index("944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"); + roundtrip_with_read_index("1810dff58d8a660512d4832e740f692884338ccd"); + roundtrip_with_read_index("d52a8fe84ceedf260afe4f0287bbfca04a117e83"); + roundtrip_with_read_index("c36d8ea75da8cb510fcb0c408c1d7e53f9a99dbe"); + roundtrip_with_read_index("7b2417a23b63e1fdde88c80e14b33247c6e5785a"); + roundtrip_with_read_index("f82a8eb4cb20e88d1030fd10d89286215a715396"); + roundtrip_with_read_index("fd093bff70906175335656e6ce6ae05783708765"); + roundtrip_with_read_index("ae90f12eea699729ed24555e40b9fd669da12a12"); +} From 93de20b8d282e3747f4d28a6daaa792ce7128cc6 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 1 Jun 2016 14:56:27 -0500 Subject: [PATCH 2/7] index_read_index: reset error correctly Clear any error state upon each iteration. If one of the iterations ends (with an error of `GIT_ITEROVER`) we need to reset that error to 0, lest we stop the whole process prematurely. --- src/index.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/index.c b/src/index.c index 31cb27d6c..135bf9ff5 100644 --- a/src/index.c +++ b/src/index.c @@ -2968,6 +2968,8 @@ int git_index_read_index( *remove_entry = NULL; int diff; + error = 0; + if (old_entry && new_entry) diff = git_index_entry_cmp(old_entry, new_entry); else if (!old_entry && new_entry) From 046ec3c9d68d4a79ed7efb044d275c62e8a49873 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 2 Jun 2016 00:47:51 -0500 Subject: [PATCH 3/7] index_read_index: differentiate on mode Treat index entries with different modes as different, which they are, at least for the purposes of up-to-date calculations. --- src/index.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/index.c b/src/index.c index 135bf9ff5..b1ee65ffe 100644 --- a/src/index.c +++ b/src/index.c @@ -2987,7 +2987,8 @@ int git_index_read_index( /* Path and stage are equal, if the OID is equal, keep it to * keep the stat cache data. */ - if (git_oid_equal(&old_entry->id, &new_entry->id)) { + if (git_oid_equal(&old_entry->id, &new_entry->id) && + old_entry->mode == new_entry->mode) { add_entry = (git_index_entry *)old_entry; } else { dup_entry = (git_index_entry *)new_entry; From 9167c1450e45f713448ed4c0c6cb13344f69d40a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 2 Jun 2016 01:04:58 -0500 Subject: [PATCH 4/7] index_read_index: set flags for path_len correctly Update the flags to reset the path_len (to emulate `index_insert`) --- src/index.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/index.c b/src/index.c index b1ee65ffe..430a34f8e 100644 --- a/src/index.c +++ b/src/index.c @@ -2999,6 +2999,9 @@ int git_index_read_index( if (dup_entry) { if ((error = index_entry_dup_nocache(&add_entry, index, dup_entry)) < 0) goto done; + + index_entry_adjust_namemask(add_entry, + ((struct entry_internal *)add_entry)->pathlen); } if (add_entry) { From 91fbf9d867877d77ec0546bd45fb649721d194f8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 1 Jun 2016 22:31:16 -0500 Subject: [PATCH 5/7] test: ensure we can round-trip a written tree Read a tree into an index, write the index, then re-open the index and ensure that we are treesame to the original. --- tests/index/read_index.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/index/read_index.c b/tests/index/read_index.c index 30adc0388..6d14bc9fd 100644 --- a/tests/index/read_index.c +++ b/tests/index/read_index.c @@ -103,3 +103,26 @@ void test_index_read_index__produces_treesame_indexes(void) roundtrip_with_read_index("fd093bff70906175335656e6ce6ae05783708765"); roundtrip_with_read_index("ae90f12eea699729ed24555e40b9fd669da12a12"); } + +void test_index_read_index__read_and_writes(void) +{ + git_oid tree_id, new_tree_id; + git_tree *tree; + git_index *tree_index, *new_index; + + cl_git_pass(git_oid_fromstr(&tree_id, "ae90f12eea699729ed24555e40b9fd669da12a12")); + cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id)); + cl_git_pass(git_index_new(&tree_index)); + cl_git_pass(git_index_read_tree(tree_index, tree)); + cl_git_pass(git_index_read_index(_index, tree_index)); + cl_git_pass(git_index_write(_index)); + + cl_git_pass(git_index_open(&new_index, git_index_path(_index))); + cl_git_pass(git_index_write_tree_to(&new_tree_id, new_index, _repo)); + + cl_assert_equal_oid(&tree_id, &new_tree_id); + + git_tree_free(tree); + git_index_free(tree_index); + git_index_free(new_index); +} From 5acf18ac6304fc216f1adecba64d61c895a883c8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 2 Jun 2016 01:58:25 -0500 Subject: [PATCH 6/7] rebase: test rebasing a new commit with subfolder Test a rebase (both a merge rebase and an inmemory rebase) with a new commit that adds files underneath a new subfolder. --- tests/rebase/inmemory.c | 43 ++++++++++++++++++ tests/rebase/merge.c | 39 ++++++++++++++++ .../1d/83f106355e4309a293e42ad2a2c4b8bdbe77ae | Bin 0 -> 31 bytes .../5a/72bf3bf964fdb176ffa4587312e69e2039695a | Bin 0 -> 49 bytes .../77/0f14546ee2563a26c52afa5cc4139a96e5d360 | Bin 0 -> 238 bytes .../91/4f3c604d1098847b7fe275f659ee329878153f | Bin 0 -> 48 bytes .../d9/c5185186d95d233dc007c1927cb3bdd6cde35b | Bin 0 -> 165 bytes .../rebase/.gitted/refs/heads/deep_gravy | Bin 0 -> 41 bytes 8 files changed, 82 insertions(+) create mode 100644 tests/resources/rebase/.gitted/objects/1d/83f106355e4309a293e42ad2a2c4b8bdbe77ae create mode 100644 tests/resources/rebase/.gitted/objects/5a/72bf3bf964fdb176ffa4587312e69e2039695a create mode 100644 tests/resources/rebase/.gitted/objects/77/0f14546ee2563a26c52afa5cc4139a96e5d360 create mode 100644 tests/resources/rebase/.gitted/objects/91/4f3c604d1098847b7fe275f659ee329878153f create mode 100644 tests/resources/rebase/.gitted/objects/d9/c5185186d95d233dc007c1927cb3bdd6cde35b create mode 100644 tests/resources/rebase/.gitted/refs/heads/deep_gravy diff --git a/tests/rebase/inmemory.c b/tests/rebase/inmemory.c index 7ce865b2f..367d6b3ac 100644 --- a/tests/rebase/inmemory.c +++ b/tests/rebase/inmemory.c @@ -165,3 +165,46 @@ void test_rebase_inmemory__no_common_ancestor(void) git_reference_free(upstream_ref); git_rebase_free(rebase); } + +void test_rebase_inmemory__with_directories(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, tree_id; + git_commit *commit; + git_rebase_options opts = GIT_REBASE_OPTIONS_INIT; + + opts.inmemory = true; + + git_oid_fromstr(&tree_id, "a4d6d9c3d57308fd8e320cf2525bae8f1adafa57"); + + cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/deep_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, &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)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + cl_git_fail_with(GIT_ITEROVER, git_rebase_next(&rebase_operation, rebase)); + + cl_git_pass(git_commit_lookup(&commit, repo, &commit_id)); + cl_assert_equal_oid(&tree_id, git_commit_tree_id(commit)); + + git_commit_free(commit); + 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); +} diff --git a/tests/rebase/merge.c b/tests/rebase/merge.c index 74507e258..0f06ed153 100644 --- a/tests/rebase/merge.c +++ b/tests/rebase/merge.c @@ -750,3 +750,42 @@ void test_rebase_merge__custom_merge_options(void) git_rebase_free(rebase); } +void test_rebase_merge__with_directories(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, tree_id; + git_commit *commit; + + git_oid_fromstr(&tree_id, "a4d6d9c3d57308fd8e320cf2525bae8f1adafa57"); + + cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/deep_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)); + + 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)); + cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, + NULL, NULL)); + + cl_git_fail_with(GIT_ITEROVER, git_rebase_next(&rebase_operation, rebase)); + + cl_git_pass(git_commit_lookup(&commit, repo, &commit_id)); + cl_assert_equal_oid(&tree_id, git_commit_tree_id(commit)); + + git_commit_free(commit); + 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); +} diff --git a/tests/resources/rebase/.gitted/objects/1d/83f106355e4309a293e42ad2a2c4b8bdbe77ae b/tests/resources/rebase/.gitted/objects/1d/83f106355e4309a293e42ad2a2c4b8bdbe77ae new file mode 100644 index 0000000000000000000000000000000000000000..6230fdf3572a956500c2620856e6128382dc67a0 GIT binary patch literal 31 ncmb+Z{2VYrjL_8fA$Lc?8T5bhvOUo)zb~! literal 0 HcmV?d00001 diff --git a/tests/resources/rebase/.gitted/objects/5a/72bf3bf964fdb176ffa4587312e69e2039695a b/tests/resources/rebase/.gitted/objects/5a/72bf3bf964fdb176ffa4587312e69e2039695a new file mode 100644 index 0000000000000000000000000000000000000000..80eb921d64873e3ef7ead63046661ce9ebea7fe7 GIT binary patch literal 49 zcmV-10M7q-0V^p=O;s>9VlXr?Ff%bxNXyJgWsq(D$YvVn%(-at6Rk^&j_laGuY4T< H{4Eb|&W05t literal 0 HcmV?d00001 diff --git a/tests/resources/rebase/.gitted/objects/77/0f14546ee2563a26c52afa5cc4139a96e5d360 b/tests/resources/rebase/.gitted/objects/77/0f14546ee2563a26c52afa5cc4139a96e5d360 new file mode 100644 index 0000000000000000000000000000000000000000..6091d54a09c8f3da365d2524517602ee4f204418 GIT binary patch literal 238 zcmV5wO}wbFfcPQQAjK9W-u`T0)@QP;*!)9hNzJ*^> literal 0 HcmV?d00001 diff --git a/tests/resources/rebase/.gitted/objects/d9/c5185186d95d233dc007c1927cb3bdd6cde35b b/tests/resources/rebase/.gitted/objects/d9/c5185186d95d233dc007c1927cb3bdd6cde35b new file mode 100644 index 0000000000000000000000000000000000000000..3c340db849e62b13d782c6740053ac56142a69cd GIT binary patch literal 165 zcmV;W09yZe0iBLpYQr!P0Q0R=>;+O*k6l?1Lh{iY^a3ksRU2X}I10Uf-7EBO7#Nt+ z*L4}-ygiLw6=K9@0|i!f#9ka1a?*rK3Dze`tW-UtdCIQafXbF@ia0sVF=tl`H#?!k zQX~aT$>%7<&B%MqeTUEbBYTCfxv#Ij!9@@IN4M`~%7}=CH@* T(Es-4UMmQ+<)P*mi)Bej+>lRj literal 0 HcmV?d00001 diff --git a/tests/resources/rebase/.gitted/refs/heads/deep_gravy b/tests/resources/rebase/.gitted/refs/heads/deep_gravy new file mode 100644 index 0000000000000000000000000000000000000000..efbe5f0a07ff51a436bd873fbd03f44ac8aadbd3 GIT binary patch literal 41 tcmWN Date: Thu, 2 Jun 2016 02:34:03 -0500 Subject: [PATCH 7/7] index_read_index: invalidate new paths in tree cache When adding a new entry to an existing index via `git_index_read_index`, be sure to remove the tree cache entry for that new path. This will mark all parent trees as dirty. --- src/index.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/index.c b/src/index.c index 430a34f8e..20ab6a19d 100644 --- a/src/index.c +++ b/src/index.c @@ -3004,6 +3004,12 @@ int git_index_read_index( ((struct entry_internal *)add_entry)->pathlen); } + /* invalidate this path in the tree cache if this is new (to + * invalidate the parent trees) + */ + if (dup_entry && !remove_entry && index->tree) + git_tree_cache_invalidate_path(index->tree, dup_entry->path); + if (add_entry) { if ((error = git_vector_insert(&new_entries, add_entry)) == 0) INSERT_IN_MAP_EX(index, new_entries_map, add_entry, error);