git_index_add: allow case changing renames On case insensitive platforms, allow `git_index_add` to provide a new path for an existing index entry. Previously, we would maintain the case in an index entry without the ability to change it (except by removing an entry and re-adding it.) Higher-level functions (like `git_index_add_bypath` and `git_index_add_frombuffers`) continue to keep the old path for easier usage.
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 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1f3c3ed..6ade3e3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -31,6 +31,11 @@ v0.23 + 1
with which to implement the transactional/atomic semantics for the
configuration backend.
+* `git_index_add` will now use the case as provided by the caller on
+ case insensitive systems. Previous versions would keep the case as
+ it existed in the index. This does not affect the higher-level
+ `git_index_add_bypath` or `git_index_add_frombuffer` functions.
+
v0.23
------
diff --git a/src/index.c b/src/index.c
index be86f16..3a7a3d8 100644
--- a/src/index.c
+++ b/src/index.c
@@ -977,16 +977,27 @@ static int index_entry_reuc_init(git_index_reuc_entry **reuc_out,
return 0;
}
-static void index_entry_cpy(git_index_entry *tgt, const git_index_entry *src)
+static void index_entry_cpy(
+ git_index_entry *tgt,
+ git_index *index,
+ const git_index_entry *src,
+ bool update_path)
{
const char *tgt_path = tgt->path;
memcpy(tgt, src, sizeof(*tgt));
- tgt->path = tgt_path; /* reset to existing path data */
+
+ /* keep the existing path buffer, but update the path to the one
+ * given by the caller, if we trust it.
+ */
+ tgt->path = tgt_path;
+
+ if (index->ignore_case && update_path)
+ memcpy((char *)tgt->path, src->path, strlen(tgt->path));
}
static int index_entry_dup(
git_index_entry **out,
- git_repository *repo,
+ git_index *index,
const git_index_entry *src)
{
git_index_entry *entry;
@@ -996,10 +1007,10 @@ static int index_entry_dup(
return 0;
}
- if (index_entry_create(&entry, repo, src->path) < 0)
+ if (index_entry_create(&entry, INDEX_OWNER(index), src->path) < 0)
return -1;
- index_entry_cpy(entry, src);
+ index_entry_cpy(entry, index, src, false);
*out = entry;
return 0;
}
@@ -1247,7 +1258,7 @@ static int index_insert(
*/
else if (existing) {
if (replace)
- index_entry_cpy(existing, entry);
+ index_entry_cpy(existing, index, entry, trust_path);
index_entry_free(entry);
*entry_ptr = entry = existing;
}
@@ -1327,7 +1338,7 @@ int git_index_add_frombuffer(
return -1;
}
- if (index_entry_dup(&entry, INDEX_OWNER(index), source_entry) < 0)
+ if (index_entry_dup(&entry, index, source_entry) < 0)
return -1;
error = git_blob_create_frombuffer(&id, INDEX_OWNER(index), buffer, len);
@@ -1474,7 +1485,7 @@ int git_index_add(git_index *index, const git_index_entry *source_entry)
return -1;
}
- if ((ret = index_entry_dup(&entry, INDEX_OWNER(index), source_entry)) < 0 ||
+ if ((ret = index_entry_dup(&entry, index, source_entry)) < 0 ||
(ret = index_insert(index, &entry, 1, true, true)) < 0)
return ret;
@@ -1600,9 +1611,9 @@ int git_index_conflict_add(git_index *index,
assert (index);
- if ((ret = index_entry_dup(&entries[0], INDEX_OWNER(index), ancestor_entry)) < 0 ||
- (ret = index_entry_dup(&entries[1], INDEX_OWNER(index), our_entry)) < 0 ||
- (ret = index_entry_dup(&entries[2], INDEX_OWNER(index), their_entry)) < 0)
+ if ((ret = index_entry_dup(&entries[0], index, ancestor_entry)) < 0 ||
+ (ret = index_entry_dup(&entries[1], index, our_entry)) < 0 ||
+ (ret = index_entry_dup(&entries[2], index, their_entry)) < 0)
goto on_error;
/* Validate entries */
@@ -2210,7 +2221,7 @@ static size_t read_entry(
entry.path = (char *)path_ptr;
- if (index_entry_dup(out, INDEX_OWNER(index), &entry) < 0)
+ if (index_entry_dup(out, index, &entry) < 0)
return 0;
return entry_size;
@@ -2727,7 +2738,7 @@ static int read_tree_cb(
entry->mode == old_entry->mode &&
git_oid_equal(&entry->id, &old_entry->id))
{
- index_entry_cpy(entry, old_entry);
+ index_entry_cpy(entry, data->index, old_entry, false);
entry->flags_extended = 0;
}
@@ -2859,7 +2870,7 @@ int git_index_read_index(
if (diff < 0) {
git_vector_insert(&remove_entries, (git_index_entry *)old_entry);
} else if (diff > 0) {
- if ((error = index_entry_dup(&entry, git_index_owner(index), new_entry)) < 0)
+ if ((error = index_entry_dup(&entry, index, new_entry)) < 0)
goto done;
git_vector_insert(&new_entries, entry);
@@ -2870,7 +2881,7 @@ int git_index_read_index(
if (git_oid_equal(&old_entry->id, &new_entry->id)) {
git_vector_insert(&new_entries, (git_index_entry *)old_entry);
} else {
- if ((error = index_entry_dup(&entry, git_index_owner(index), new_entry)) < 0)
+ if ((error = index_entry_dup(&entry, index, new_entry)) < 0)
goto done;
git_vector_insert(&new_entries, entry);
diff --git a/tests/index/bypath.c b/tests/index/bypath.c
index 17bba6a..b152b09 100644
--- a/tests/index/bypath.c
+++ b/tests/index/bypath.c
@@ -73,6 +73,26 @@ void test_index_bypath__add_hidden(void)
#endif
}
+void test_index_bypath__add_keeps_existing_case(void)
+{
+ const git_index_entry *entry;
+
+ if (!cl_repo_get_bool(g_repo, "core.ignorecase"))
+ clar__skip();
+
+ cl_git_mkfile("submod2/just_a_dir/file1.txt", "This is a file");
+ cl_git_pass(git_index_add_bypath(g_idx, "just_a_dir/file1.txt"));
+
+ cl_assert(entry = git_index_get_bypath(g_idx, "just_a_dir/file1.txt", 0));
+ cl_assert_equal_s("just_a_dir/file1.txt", entry->path);
+
+ cl_git_rewritefile("submod2/just_a_dir/file1.txt", "Updated!");
+ cl_git_pass(git_index_add_bypath(g_idx, "just_a_dir/FILE1.txt"));
+
+ cl_assert(entry = git_index_get_bypath(g_idx, "just_a_dir/FILE1.txt", 0));
+ cl_assert_equal_s("just_a_dir/file1.txt", entry->path);
+}
+
void test_index_bypath__add_honors_existing_case(void)
{
const git_index_entry *entry;
diff --git a/tests/index/rename.c b/tests/index/rename.c
index dd3cfa7..ebaa9b7 100644
--- a/tests/index/rename.c
+++ b/tests/index/rename.c
@@ -48,3 +48,34 @@ void test_index_rename__single_file(void)
cl_fixture_cleanup("rename");
}
+
+void test_index_rename__casechanging(void)
+{
+ git_repository *repo;
+ git_index *index;
+ const git_index_entry *entry;
+ git_index_entry new = {{0}};
+
+ p_mkdir("rename", 0700);
+
+ cl_git_pass(git_repository_init(&repo, "./rename", 0));
+ cl_git_pass(git_repository_index(&index, repo));
+
+ cl_git_mkfile("./rename/lame.name.txt", "new_file\n");
+
+ cl_git_pass(git_index_add_bypath(index, "lame.name.txt"));
+ cl_assert_equal_i(1, git_index_entrycount(index));
+ cl_assert((entry = git_index_get_bypath(index, "lame.name.txt", 0)));
+
+ memcpy(&new, entry, sizeof(git_index_entry));
+ new.path = "LAME.name.TXT";
+
+ cl_git_pass(git_index_add(index, &new));
+ cl_assert((entry = git_index_get_bypath(index, "LAME.name.TXT", 0)));
+
+ if (cl_repo_get_bool(repo, "core.ignorecase"))
+ cl_assert_equal_i(1, git_index_entrycount(index));
+ else
+ cl_assert_equal_i(2, git_index_entrycount(index));
+}
+