Changes from v1: - Use OPT_SET_INT_F instead of OPT_CALLBACK_F - Remove the special message and instead always say that the patch applied cleanly when these options are used Thanks to Junio for your feedback. Alex Henrie (1): apply: support --ours, --theirs, and --union for three-way merges Documentation/git-apply.txt | 9 ++++++++- apply.c | 20 +++++++++++++++++-- apply.h | 1 + t/t4108-apply-threeway.sh | 40 +++++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 3 deletions(-) Range-diff against v1: 1: e0e4000d47 ! 1: 9307dc5a1b apply: support --ours, --theirs, and --union for three-way merges @@ Documentation/git-apply.txt: OPTIONS for each blob to help identify the original version that ## apply.c ## -@@ apply.c: int init_apply_state(struct apply_state *state, - state->prefix = prefix; - state->repo = repo; - state->apply = 1; -+ state->merge_opts.conflict_style = -1; - state->line_termination = '\n'; - state->p_value = 1; - state->p_context = UINT_MAX; @@ apply.c: static int three_way_merge(struct apply_state *state, + const struct object_id *theirs) + { + mmfile_t base_file, our_file, their_file; ++ struct ll_merge_options merge_opts = LL_MERGE_OPTIONS_INIT; + mmbuffer_t result = { NULL }; + enum ll_merge_result status; + +@@ apply.c: static int three_way_merge(struct apply_state *state, + read_mmblob(&base_file, base); + read_mmblob(&our_file, ours); + read_mmblob(&their_file, theirs); ++ merge_opts.variant = state->merge_variant; + status = ll_merge(&result, path, + &base_file, "base", &our_file, "ours", &their_file, "theirs", state->repo->index, - NULL); -+ &state->merge_opts); ++ &merge_opts); if (status == LL_MERGE_BINARY_CONFLICT) warning("Cannot merge binary files: %s (%s vs. %s)", path, "ours", "theirs"); -@@ apply.c: static int try_threeway(struct apply_state *state, - return status; - } - -- if (status) { -+ if (state->merge_opts.variant) { -+ /* -+ * XDL_MERGE_FAVOR_(OURS|THEIRS|UNION) automatically resolves -+ * conflicts, but the ll_merge function is not yet smart enough -+ * to report whether or not there were conflicts, so just print -+ * a generic message. -+ */ -+ fprintf(stderr, _("Applied patch to '%s'.\n"), patch->new_name); -+ } else if (status) { - patch->conflicted_threeway = 1; - if (patch->is_new) - oidclr(&patch->threeway_stage[0], the_repository->hash_algo); -@@ apply.c: static int apply_option_parse_space_change(const struct option *opt, - return 0; - } - -+static int apply_option_parse_favorite(const struct option *opt, -+ const char *arg, int unset) -+{ -+ struct apply_state *state = opt->value; -+ -+ BUG_ON_OPT_ARG(arg); -+ BUG_ON_OPT_NEG(unset); -+ -+ if (!strcmp(opt->long_name, "ours")) -+ state->merge_opts.variant = XDL_MERGE_FAVOR_OURS; -+ else if (!strcmp(opt->long_name, "theirs")) -+ state->merge_opts.variant = XDL_MERGE_FAVOR_THEIRS; -+ else -+ state->merge_opts.variant = XDL_MERGE_FAVOR_UNION; -+ return 0; -+} -+ - static int apply_option_parse_whitespace(const struct option *opt, - const char *arg, int unset) - { @@ apply.c: int apply_parse_options(int argc, const char **argv, N_("also apply the patch (use with --stat/--summary/--check)")), OPT_BOOL('3', "3way", &state->threeway, N_( "attempt three-way merge, fall back on normal patch if that fails")), -+ OPT_CALLBACK_F(0, "ours", state, NULL, ++ OPT_SET_INT_F(0, "ours", &state->merge_variant, + N_("for conflicts, use our version"), -+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, -+ apply_option_parse_favorite), -+ OPT_CALLBACK_F(0, "theirs", state, NULL, ++ XDL_MERGE_FAVOR_OURS, PARSE_OPT_NONEG), ++ OPT_SET_INT_F(0, "theirs", &state->merge_variant, + N_("for conflicts, use their version"), -+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, -+ apply_option_parse_favorite), -+ OPT_CALLBACK_F(0, "union", state, NULL, ++ XDL_MERGE_FAVOR_THEIRS, PARSE_OPT_NONEG), ++ OPT_SET_INT_F(0, "union", &state->merge_variant, + N_("for conflicts, use a union version"), -+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, -+ apply_option_parse_favorite), ++ XDL_MERGE_FAVOR_UNION, PARSE_OPT_NONEG), OPT_FILENAME(0, "build-fake-ancestor", &state->fake_ancestor, N_("build a temporary index based on embedded index information")), /* Think twice before adding "--nul" synonym to this */ @@ apply.c: int apply_parse_options(int argc, const char **argv, - return parse_options(argc, argv, state->prefix, builtin_apply_options, apply_usage, 0); + argc = parse_options(argc, argv, state->prefix, builtin_apply_options, apply_usage, 0); + -+ if (state->merge_opts.variant && !state->threeway) ++ if (state->merge_variant && !state->threeway) + die(_("--ours, --theirs, and --union require --3way")); + + return argc; } ## apply.h ## -@@ - - #include "hash.h" - #include "lockfile.h" -+#include "merge-ll.h" - #include "string-list.h" - #include "strmap.h" - @@ apply.h: struct apply_state { struct repository *repo; const char *index_file; enum apply_verbosity apply_verbosity; -+ struct ll_merge_options merge_opts; ++ int merge_variant; char *fake_ancestor; const char *patch_input_file; int line_termination; -- 2.46.0