apply: test re-adding a file after removing it Ensure that we can add a file back after it's been removed. Update the renamed/deleted validation in application to not apply to deltas that are adding files to support this.
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
diff --git a/src/apply.c b/src/apply.c
index c337982..614baf7 100644
--- a/src/apply.c
+++ b/src/apply.c
@@ -458,23 +458,26 @@ static int apply_one(
}
/*
- * We may be applying a second delta to an already seen file. If so,
- * use the already modified data in the postimage instead of the
- * content from the index or working directory. (Don't do this in
- * the case of a rename, which must be specified before additional
- * deltas since we apply deltas to the target filename.)
- *
- * Additionally, make sure that the file has not been deleted or renamed
- * out of the way; again, except in the rename case, since we support
- * renaming a single file into two target files.
+ * Ensure that the file has not been deleted or renamed if we're
+ * applying a modification delta.
*/
- if (delta->status != GIT_DELTA_RENAMED) {
+ if (delta->status != GIT_DELTA_RENAMED &&
+ delta->status != GIT_DELTA_ADDED) {
pos = git_strmap_lookup_index(removed_paths, delta->old_file.path);
if (git_strmap_valid_index(removed_paths, pos)) {
error = apply_err("path '%s' has been renamed or deleted", delta->old_file.path);
goto done;
}
+ }
+ /*
+ * We may be applying a second delta to an already seen file. If so,
+ * use the already modified data in the postimage instead of the
+ * content from the index or working directory. (Don't do this in
+ * the case of a rename, which must be specified before additional
+ * deltas since we apply deltas to the target filename.)
+ */
+ if (delta->status != GIT_DELTA_RENAMED) {
if ((error = git_reader_read(&pre_contents, &pre_id, &pre_filemode,
postimage_reader, delta->old_file.path)) == 0) {
skip_preimage = true;
diff --git a/tests/apply/apply_helpers.h b/tests/apply/apply_helpers.h
index a2f4dab..9cc9e44 100644
--- a/tests/apply/apply_helpers.h
+++ b/tests/apply/apply_helpers.h
@@ -394,6 +394,31 @@
" Put into a pot three quarts of water, three onions cut small, one\n" \
" spoonful of black pepper pounded, and two of salt, with two or three\n"
+#define DIFF_DELETE_AND_READD_FILE \
+ "diff --git a/asparagus.txt b/asparagus.txt\n" \
+ "deleted file mode 100644\n" \
+ "index f516580..0000000\n" \
+ "--- a/asparagus.txt\n" \
+ "+++ /dev/null\n" \
+ "@@ -1,10 +0,0 @@\n" \
+ "-ASPARAGUS SOUP!\n" \
+ "-\n" \
+ "-Take four large bunches of asparagus, scrape it nicely, cut off one inch\n" \
+ "-of the tops, and lay them in water, chop the stalks and put them on the\n" \
+ "-fire with a piece of bacon, a large onion cut up, and pepper and salt;\n" \
+ "-add two quarts of water, boil them till the stalks are quite soft, then\n" \
+ "-pulp them through a sieve, and strain the water to it, which must be put\n" \
+ "-back in the pot; put into it a chicken cut up, with the tops of\n" \
+ "-asparagus which had been laid by, boil it until these last articles are\n" \
+ "-sufficiently done, thicken with flour, butter and milk, and serve it up.\n" \
+ "diff --git a/asparagus.txt b/asparagus.txt\n" \
+ "new file mode 100644\n" \
+ "index 0000000..2dc7f8b\n" \
+ "--- /dev/null\n" \
+ "+++ b/asparagus.txt\n" \
+ "@@ -0,0 +1 @@\n" \
+ "+New file.\n" \
+
struct iterator_compare_data {
struct merge_index_entry *expected;
size_t cnt;
diff --git a/tests/apply/both.c b/tests/apply/both.c
index f5bb3e4..cac5acb 100644
--- a/tests/apply/both.c
+++ b/tests/apply/both.c
@@ -698,3 +698,28 @@ void test_apply_both__cant_modify_source_path_after_rename(void)
git_diff_free(diff);
}
+
+void test_apply_both__readd_deleted_file(void)
+{
+ git_diff *diff;
+
+ struct merge_index_entry both_expected[] = {
+ { 0100644, "2dc7f8b24ba27f3888368bd180df03ff4c6c6fab", 0, "asparagus.txt" },
+ { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
+ { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
+ { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
+ { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
+ { 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }
+ };
+ size_t both_expected_cnt = sizeof(both_expected) /
+ sizeof(struct merge_index_entry);
+
+ cl_git_pass(git_diff_from_buffer(&diff, DIFF_DELETE_AND_READD_FILE,
+ strlen(DIFF_DELETE_AND_READD_FILE)));
+ cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
+
+ validate_apply_index(repo, both_expected, both_expected_cnt);
+ validate_apply_workdir(repo, both_expected, both_expected_cnt);
+
+ git_diff_free(diff);
+}