Commit 813f0802 by Edward Thomson

apply: validate workdir contents match index for BOTH

When applying to both the index and the working directory, ensure that
the index contents match the working directory.  This mirrors the
requirement in `git apply --index`.

This also means that - along with the prior commit that uses the working
directory contents as the checkout baseline - we no longer expect
conflicts during checkout.  So remove the special-case error handling
for checkout conflicts.  (Any checkout conflict now would be because the
file was actually modified between the start of patch application and
the checkout.)
parent 0f4b2f02
......@@ -406,15 +406,19 @@ static int apply_one(
delta = git_patch_get_delta(patch);
if (delta->status != GIT_DELTA_ADDED) {
if ((error = git_reader_read(&pre_contents, &pre_id,
preimage_reader, delta->old_file.path)) < 0) {
error = git_reader_read(&pre_contents, &pre_id,
preimage_reader, delta->old_file.path);
/* ENOTFOUND is really an application error */
if (error == GIT_ENOTFOUND)
error = GIT_EAPPLYFAIL;
/* ENOTFOUND means the preimage was not found; apply failed. */
if (error == GIT_ENOTFOUND)
error = GIT_EAPPLYFAIL;
/* When applying to BOTH, the index did not match the workdir. */
if (error == GIT_READER_MISMATCH)
error = apply_err("%s: does not match index", delta->old_file.path);
if (error < 0)
goto done;
}
/*
* We need to populate the preimage data structure with the
......@@ -563,13 +567,6 @@ static int git_apply__to_workdir(
error = git_checkout_index(repo, postimage, &checkout_opts);
/*
* When there's a checkout conflict, the file in the working directory
* has been modified. Upgrade this error to an application error.
*/
if (error == GIT_ECONFLICT)
error = GIT_EAPPLYFAIL;
done:
git_vector_free(&paths);
return error;
......@@ -645,7 +642,7 @@ int git_apply(
git_reader *pre_reader = NULL;
git_apply_options opts = GIT_APPLY_OPTIONS_INIT;
size_t i;
int error;
int error = GIT_EINVALID;
assert(repo && diff);
......@@ -660,10 +657,19 @@ int git_apply(
* in `--cached` or `--index` mode, we apply to the contents already
* in the index.
*/
if (opts.location == GIT_APPLY_LOCATION_WORKDIR)
error = git_reader_for_workdir(&pre_reader, repo, false);
else
switch (opts.location) {
case GIT_APPLY_LOCATION_BOTH:
error = git_reader_for_workdir(&pre_reader, repo, true);
break;
case GIT_APPLY_LOCATION_INDEX:
error = git_reader_for_index(&pre_reader, repo, NULL);
break;
case GIT_APPLY_LOCATION_WORKDIR:
error = git_reader_for_workdir(&pre_reader, repo, false);
break;
default:
assert(false);
}
if (error < 0)
goto done;
......
......@@ -185,6 +185,43 @@ void test_apply_both__application_failure_leaves_index_unmodified(void)
git_diff_free(diff);
}
void test_apply_both__index_must_match_workdir(void)
{
git_diff *diff;
git_index *index;
git_index_entry idx_entry;
git_apply_options opts = GIT_APPLY_OPTIONS_INIT;
const char *diff_file = DIFF_MODIFY_TWO_FILES;
/*
* Append a line to the end of the file in both the index and the
* working directory. Although the appended line would allow for
* patch application in each, the line appended is different in
* each, so the application should not be allowed.
*/
cl_git_append2file("merge-recursive/asparagus.txt",
"This is a modification.\n");
cl_git_pass(git_repository_index(&index, repo));
memset(&idx_entry, 0, sizeof(git_index_entry));
idx_entry.mode = 0100644;
idx_entry.path = "asparagus.txt";
cl_git_pass(git_oid_fromstr(&idx_entry.id, "06d3fefb8726ab1099acc76e02dfb85e034b2538"));
cl_git_pass(git_index_add(index, &idx_entry));
cl_git_pass(git_index_write(index));
git_index_free(index);
cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file)));
opts.location = GIT_APPLY_LOCATION_BOTH;
cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, &opts));
git_diff_free(diff);
}
void test_apply_both__application_failure_leaves_workdir_unmodified(void)
{
git_diff *diff;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment