Merge branch 'jz/apply-run-3way-first'

"git apply --3way" has always been "to fall back to 3-way merge
only when straight application fails". Swap the order of falling
back so that 3-way is always attempted first (only when the option
is given, of course) and then straight patch application is used as
a fallback when it fails.

* jz/apply-run-3way-first:
  git-apply: try threeway first when "--3way" is used
This commit is contained in:
Junio C Hamano 2021-04-15 13:36:00 -07:00
commit 771c758e8a
3 changed files with 28 additions and 10 deletions

View File

@ -84,9 +84,8 @@ OPTIONS
-3:: -3::
--3way:: --3way::
When the patch does not apply cleanly, fall back on 3-way merge if Attempt 3-way merge if the patch records the identity of blobs it is supposed
the patch records the identity of blobs it is supposed to apply to, to apply to and we have those blobs available locally, possibly leaving the
and we have those blobs available locally, possibly leaving the
conflict markers in the files in the working tree for the user to conflict markers in the files in the working tree for the user to
resolve. This option implies the `--index` option, and is incompatible resolve. This option implies the `--index` option, and is incompatible
with the `--reject` and the `--cached` options. with the `--reject` and the `--cached` options.

13
apply.c
View File

@ -3570,10 +3570,10 @@ static int try_threeway(struct apply_state *state,
write_object_file("", 0, blob_type, &pre_oid); write_object_file("", 0, blob_type, &pre_oid);
else if (get_oid(patch->old_oid_prefix, &pre_oid) || else if (get_oid(patch->old_oid_prefix, &pre_oid) ||
read_blob_object(&buf, &pre_oid, patch->old_mode)) read_blob_object(&buf, &pre_oid, patch->old_mode))
return error(_("repository lacks the necessary blob to fall back on 3-way merge.")); return error(_("repository lacks the necessary blob to perform 3-way merge."));
if (state->apply_verbosity > verbosity_silent) if (state->apply_verbosity > verbosity_silent)
fprintf(stderr, _("Falling back to three-way merge...\n")); fprintf(stderr, _("Performing three-way merge...\n"));
img = strbuf_detach(&buf, &len); img = strbuf_detach(&buf, &len);
prepare_image(&tmp_image, img, len, 1); prepare_image(&tmp_image, img, len, 1);
@ -3605,7 +3605,7 @@ static int try_threeway(struct apply_state *state,
if (status < 0) { if (status < 0) {
if (state->apply_verbosity > verbosity_silent) if (state->apply_verbosity > verbosity_silent)
fprintf(stderr, fprintf(stderr,
_("Failed to fall back on three-way merge...\n")); _("Failed to perform three-way merge...\n"));
return status; return status;
} }
@ -3638,10 +3638,9 @@ static int apply_data(struct apply_state *state, struct patch *patch,
if (load_preimage(state, &image, patch, st, ce) < 0) if (load_preimage(state, &image, patch, st, ce) < 0)
return -1; return -1;
if (patch->direct_to_threeway || if (!state->threeway || try_threeway(state, &image, patch, st, ce) < 0) {
apply_fragments(state, &image, patch) < 0) {
/* Note: with --reject, apply_fragments() returns 0 */ /* Note: with --reject, apply_fragments() returns 0 */
if (!state->threeway || try_threeway(state, &image, patch, st, ce) < 0) if (patch->direct_to_threeway || apply_fragments(state, &image, patch) < 0)
return -1; return -1;
} }
patch->result = image.buf; patch->result = image.buf;
@ -5018,7 +5017,7 @@ int apply_parse_options(int argc, const char **argv,
OPT_BOOL(0, "apply", force_apply, OPT_BOOL(0, "apply", force_apply,
N_("also apply the patch (use with --stat/--summary/--check)")), N_("also apply the patch (use with --stat/--summary/--check)")),
OPT_BOOL('3', "3way", &state->threeway, OPT_BOOL('3', "3way", &state->threeway,
N_( "attempt three-way merge if a patch does not apply")), N_( "attempt three-way merge, fall back on normal patch if that fails")),
OPT_FILENAME(0, "build-fake-ancestor", &state->fake_ancestor, OPT_FILENAME(0, "build-fake-ancestor", &state->fake_ancestor,
N_("build a temporary index based on embedded index information")), N_("build a temporary index based on embedded index information")),
/* Think twice before adding "--nul" synonym to this */ /* Think twice before adding "--nul" synonym to this */

View File

@ -160,4 +160,24 @@ test_expect_success 'apply -3 with add/add conflict (dirty working tree)' '
test_cmp three.save three test_cmp three.save three
' '
test_expect_success 'apply -3 with ambiguous repeating file' '
git reset --hard &&
test_write_lines 1 2 1 2 1 2 1 2 1 2 1 >one_two_repeat &&
git add one_two_repeat &&
git commit -m "init one" &&
test_write_lines 1 2 1 2 1 2 1 2 one 2 1 >one_two_repeat &&
git commit -a -m "change one" &&
git diff HEAD~ >Repeat.diff &&
git reset --hard HEAD~ &&
test_write_lines 1 2 1 2 1 2 one 2 1 2 one >one_two_repeat &&
git commit -a -m "change surrounding one" &&
git apply --index --3way Repeat.diff &&
test_write_lines 1 2 1 2 1 2 one 2 one 2 one >expect &&
test_cmp expect one_two_repeat
'
test_done test_done