Add index API to remove all files in a directory This adds the git_index_remove_directory API plus tests.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
diff --git a/include/git2/index.h b/include/git2/index.h
index fa9a197..1d21403 100644
--- a/include/git2/index.h
+++ b/include/git2/index.h
@@ -313,6 +313,17 @@ GIT_EXTERN(const git_index_entry *) git_index_get_bypath(
GIT_EXTERN(int) git_index_remove(git_index *index, const char *path, int stage);
/**
+ * Remove all entries from the index under a given directory
+ *
+ * @param index an existing index object
+ * @param dir container directory path
+ * @param stage stage to search
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_index_remove_directory(
+ git_index *index, const char *dir, int stage);
+
+/**
* Add or update an index entry from an in-memory struct
*
* If a previous index entry exists that has the same path and stage
diff --git a/src/index.c b/src/index.c
index 9f2012b..ce902c5 100644
--- a/src/index.c
+++ b/src/index.c
@@ -794,6 +794,44 @@ int git_index_remove(git_index *index, const char *path, int stage)
return error;
}
+int git_index_remove_directory(git_index *index, const char *dir, int stage)
+{
+ git_buf pfx = GIT_BUF_INIT;
+ int error = 0;
+ size_t pos;
+ git_index_entry *entry;
+
+ if (git_buf_sets(&pfx, dir) < 0 || git_path_to_dir(&pfx) < 0)
+ return -1;
+
+ git_vector_sort(&index->entries);
+
+ pos = git_index__prefix_position(index, pfx.ptr);
+
+ while (1) {
+ entry = git_vector_get(&index->entries, pos);
+ if (!entry || git__prefixcmp(entry->path, pfx.ptr) != 0)
+ break;
+
+ if (index_entry_stage(entry) != stage) {
+ ++pos;
+ continue;
+ }
+
+ git_tree_cache_invalidate_path(index->tree, entry->path);
+
+ if ((error = git_vector_remove(&index->entries, pos)) < 0)
+ break;
+ index_entry_free(entry);
+
+ /* removed entry at 'pos' so we don't need to increment it */
+ }
+
+ git_buf_free(&pfx);
+
+ return error;
+}
+
static int index_find(git_index *index, const char *path, int stage)
{
struct entry_srch_key srch_key;
diff --git a/tests-clar/index/tests.c b/tests-clar/index/tests.c
index 989734c..5c3d4cf 100644
--- a/tests-clar/index/tests.c
+++ b/tests-clar/index/tests.c
@@ -290,3 +290,86 @@ void test_index_tests__write_invalid_filename(void)
cl_fixture_cleanup("read_tree");
}
+
+void test_index_tests__remove_entry(void)
+{
+ git_repository *repo;
+ git_index *index;
+
+ p_mkdir("index_test", 0770);
+
+ cl_git_pass(git_repository_init(&repo, "index_test", 0));
+ cl_git_pass(git_repository_index(&index, repo));
+ cl_assert(git_index_entrycount(index) == 0);
+
+ cl_git_mkfile("index_test/hello", NULL);
+ cl_git_pass(git_index_add_from_workdir(index, "hello"));
+ cl_git_pass(git_index_write(index));
+
+ cl_git_pass(git_index_read(index)); /* reload */
+ cl_assert(git_index_entrycount(index) == 1);
+ cl_assert(git_index_get_bypath(index, "hello", 0) != NULL);
+
+ cl_git_pass(git_index_remove(index, "hello", 0));
+ cl_git_pass(git_index_write(index));
+
+ cl_git_pass(git_index_read(index)); /* reload */
+ cl_assert(git_index_entrycount(index) == 0);
+ cl_assert(git_index_get_bypath(index, "hello", 0) == NULL);
+
+ git_index_free(index);
+ git_repository_free(repo);
+ cl_fixture_cleanup("index_test");
+}
+
+void test_index_tests__remove_directory(void)
+{
+ git_repository *repo;
+ git_index *index;
+
+ p_mkdir("index_test", 0770);
+
+ cl_git_pass(git_repository_init(&repo, "index_test", 0));
+ cl_git_pass(git_repository_index(&index, repo));
+ cl_assert_equal_i(0, (int)git_index_entrycount(index));
+
+ p_mkdir("index_test/a", 0770);
+ cl_git_mkfile("index_test/a/1.txt", NULL);
+ cl_git_mkfile("index_test/a/2.txt", NULL);
+ cl_git_mkfile("index_test/a/3.txt", NULL);
+ cl_git_mkfile("index_test/b.txt", NULL);
+
+ cl_git_pass(git_index_add_from_workdir(index, "a/1.txt"));
+ cl_git_pass(git_index_add_from_workdir(index, "a/2.txt"));
+ cl_git_pass(git_index_add_from_workdir(index, "a/3.txt"));
+ cl_git_pass(git_index_add_from_workdir(index, "b.txt"));
+ cl_git_pass(git_index_write(index));
+
+ cl_git_pass(git_index_read(index)); /* reload */
+ cl_assert_equal_i(4, (int)git_index_entrycount(index));
+ cl_assert(git_index_get_bypath(index, "a/1.txt", 0) != NULL);
+ cl_assert(git_index_get_bypath(index, "a/2.txt", 0) != NULL);
+ cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL);
+
+ cl_git_pass(git_index_remove(index, "a/1.txt", 0));
+ cl_git_pass(git_index_write(index));
+
+ cl_git_pass(git_index_read(index)); /* reload */
+ cl_assert_equal_i(3, (int)git_index_entrycount(index));
+ cl_assert(git_index_get_bypath(index, "a/1.txt", 0) == NULL);
+ cl_assert(git_index_get_bypath(index, "a/2.txt", 0) != NULL);
+ cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL);
+
+ cl_git_pass(git_index_remove_directory(index, "a", 0));
+ cl_git_pass(git_index_write(index));
+
+ cl_git_pass(git_index_read(index)); /* reload */
+ cl_assert_equal_i(1, (int)git_index_entrycount(index));
+ cl_assert(git_index_get_bypath(index, "a/1.txt", 0) == NULL);
+ cl_assert(git_index_get_bypath(index, "a/2.txt", 0) == NULL);
+ cl_assert(git_index_get_bypath(index, "b.txt", 0) != NULL);
+
+ git_index_free(index);
+ git_repository_free(repo);
+ cl_fixture_cleanup("index_test");
+}