summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/index.c12
-rw-r--r--tests-clar/index/addall.c20
2 files changed, 29 insertions, 3 deletions
diff --git a/src/index.c b/src/index.c
index e65dc052c..d5568528b 100644
--- a/src/index.c
+++ b/src/index.c
@@ -2176,6 +2176,7 @@ static int index_apply_to_all(
size_t i;
git_pathspec_context ps;
const char *match;
+ git_buf path = GIT_BUF_INIT;
assert(index);
@@ -2205,23 +2206,27 @@ static int index_apply_to_all(
}
}
+ /* index manipulation may alter entry, so don't depend on it */
+ if ((error = git_buf_sets(&path, entry->path)) < 0)
+ break;
+
switch (action) {
case INDEX_ACTION_NONE:
break;
case INDEX_ACTION_UPDATE:
- error = git_index_add_bypath(index, entry->path);
+ error = git_index_add_bypath(index, path.ptr);
if (error == GIT_ENOTFOUND) {
giterr_clear();
- error = git_index_remove_bypath(index, entry->path);
+ error = git_index_remove_bypath(index, path.ptr);
if (!error) /* back up foreach if we removed this */
i--;
}
break;
case INDEX_ACTION_REMOVE:
- if (!(error = git_index_remove_bypath(index, entry->path)))
+ if (!(error = git_index_remove_bypath(index, path.ptr)))
i--; /* back up foreach if we removed this */
break;
default:
@@ -2231,6 +2236,7 @@ static int index_apply_to_all(
}
}
+ git_buf_free(&path);
git_pathspec_context_free(&ps);
return error;
diff --git a/tests-clar/index/addall.c b/tests-clar/index/addall.c
index 33873cb7a..fca6e77fa 100644
--- a/tests-clar/index/addall.c
+++ b/tests-clar/index/addall.c
@@ -132,6 +132,7 @@ static void commit_index_to_head(
cl_git_pass(git_repository_index(&index, repo));
cl_git_pass(git_index_write_tree(&tree_id, index));
+ cl_git_pass(git_index_write(index)); /* not needed, but might as well */
git_index_free(index);
cl_git_pass(git_tree_lookup(&tree, repo, &tree_id));
@@ -250,5 +251,24 @@ void test_index_addall__repo_lifecycle(void)
cl_git_pass(git_index_update_all(index, NULL, NULL, NULL));
check_status(g_repo, 0, 1, 0, 3, 0, 0, 0);
+ strs[0] = "*";
+ cl_git_pass(git_index_add_all(index, &paths, 0, NULL, NULL));
+ check_status(g_repo, 3, 1, 0, 0, 0, 0, 0);
+
+ /* must be able to remove at any position while still updating other files */
+ cl_must_pass(p_unlink("addall/.gitignore"));
+ cl_git_rewritefile("addall/file.zzz", "reconstructed file");
+ cl_git_rewritefile("addall/more.zzz", "altered file reality");
+ check_status(g_repo, 3, 1, 0, 1, 1, 1, 0);
+
+ cl_git_pass(git_index_update_all(index, NULL, NULL, NULL));
+ check_status(g_repo, 2, 1, 0, 1, 0, 0, 0);
+ /* this behavior actually matches 'git add -u' where "file.zzz" has
+ * been removed from the index, so when you go to update, even though
+ * it exists in the HEAD, it is not re-added to the index, leaving it
+ * as a DELETE when comparing HEAD to index and as an ADD comparing
+ * index to worktree
+ */
+
git_index_free(index);
}