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;