mbox series

[v2,0/1] apply: support --ours, --theirs, and --union for three-way merges

Message ID 20240909141109.3102-1-alexhenrie24@gmail.com (mailing list archive)
Headers show
Series apply: support --ours, --theirs, and --union for three-way merges | expand

Message

Alex Henrie Sept. 9, 2024, 2:10 p.m. UTC
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;