Skip to content

Commit

Permalink
Merge branch 'pw/checkout-conflict-errorfix' into seen
Browse files Browse the repository at this point in the history
"git checkout --conflict=bad" reported a bad conflictStyle as if it
were given to a configuration variable; it has been corrected to
report that the command line option is bad.

* pw/checkout-conflict-errorfix:
  checkout: cleanup --conflict=<style> parsing
  merge options: add a conflict style member
  merge-ll: introduce LL_MERGE_OPTIONS_INIT
  xdiff-interface: refactor parsing of merge.conflictstyle
  • Loading branch information
gitster committed Mar 9, 2024
2 parents 3675857 + f310b49 commit 15c0c65
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 34 deletions.
40 changes: 21 additions & 19 deletions builtin/checkout.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ struct checkout_opts {
int new_branch_log;
enum branch_track track;
struct diff_options diff_options;
char *conflict_style;
char *conflict_style_name;
int conflict_style;

int branch_exists;
const char *prefix;
Expand All @@ -100,6 +101,8 @@ struct checkout_opts {
struct tree *source_tree;
};

#define CHECKOUT_OPTS_INIT { .conflict_style = -1 }

struct branch_info {
char *name; /* The short name used */
char *path; /* The full name of a real branch */
Expand Down Expand Up @@ -251,7 +254,8 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
}

static int checkout_merged(int pos, const struct checkout *state,
int *nr_checkouts, struct mem_pool *ce_mem_pool)
int *nr_checkouts, struct mem_pool *ce_mem_pool,
int conflict_style)
{
struct cache_entry *ce = the_index.cache[pos];
const char *path = ce->name;
Expand All @@ -262,7 +266,7 @@ static int checkout_merged(int pos, const struct checkout *state,
mmbuffer_t result_buf;
struct object_id threeway[3];
unsigned mode = 0;
struct ll_merge_options ll_opts;
struct ll_merge_options ll_opts = LL_MERGE_OPTIONS_INIT;
int renormalize = 0;

memset(threeway, 0, sizeof(threeway));
Expand All @@ -284,9 +288,9 @@ static int checkout_merged(int pos, const struct checkout *state,
read_mmblob(&ours, &threeway[1]);
read_mmblob(&theirs, &threeway[2]);

memset(&ll_opts, 0, sizeof(ll_opts));
git_config_get_bool("merge.renormalize", &renormalize);
ll_opts.renormalize = renormalize;
ll_opts.conflict_style = conflict_style;
merge_status = ll_merge(&result_buf, path, &ancestor, "base",
&ours, "ours", &theirs, "theirs",
state->istate, &ll_opts);
Expand Down Expand Up @@ -417,7 +421,8 @@ static int checkout_worktree(const struct checkout_opts *opts,
else if (opts->merge)
errs |= checkout_merged(pos, &state,
&nr_unmerged,
&ce_mem_pool);
&ce_mem_pool,
opts->conflict_style);
pos = skip_same_name(ce, pos) - 1;
}
}
Expand Down Expand Up @@ -897,6 +902,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
}
o.branch1 = new_branch_info->name;
o.branch2 = "local";
o.conflict_style = opts->conflict_style;
ret = merge_trees(&o,
new_tree,
work,
Expand Down Expand Up @@ -1644,7 +1650,7 @@ static struct option *add_common_options(struct checkout_opts *opts,
PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater),
OPT_BOOL(0, "progress", &opts->show_progress, N_("force progress reporting")),
OPT_BOOL('m', "merge", &opts->merge, N_("perform a 3-way merge with the new branch")),
OPT_STRING(0, "conflict", &opts->conflict_style, N_("style"),
OPT_STRING(0, "conflict", &opts->conflict_style_name, N_("style"),
N_("conflict style (merge, diff3, or zdiff3)")),
OPT_END()
};
Expand Down Expand Up @@ -1736,14 +1742,13 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
opts->show_progress = isatty(2);
}

if (opts->conflict_style) {
struct key_value_info kvi = KVI_INIT;
struct config_context ctx = {
.kvi = &kvi,
};
if (opts->conflict_style_name) {
opts->merge = 1; /* implied */
git_xmerge_config("merge.conflictstyle", opts->conflict_style,
&ctx, NULL);
opts->conflict_style =
parse_conflict_style(opts->conflict_style_name);
if (opts->conflict_style < 0)
die(_("unknown conflict style '%s'"),
opts->conflict_style_name);
}
if (opts->force) {
opts->discard_changes = 1;
Expand Down Expand Up @@ -1909,7 +1914,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,

int cmd_checkout(int argc, const char **argv, const char *prefix)
{
struct checkout_opts opts;
struct checkout_opts opts = CHECKOUT_OPTS_INIT;
struct option *options;
struct option checkout_options[] = {
OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
Expand All @@ -1925,7 +1930,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
int ret;
struct branch_info new_branch_info = { 0 };

memset(&opts, 0, sizeof(opts));
opts.dwim_new_local_branch = 1;
opts.switch_branch_doing_nothing_is_ok = 1;
opts.only_merge_on_switching_branches = 0;
Expand Down Expand Up @@ -1964,7 +1968,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)

int cmd_switch(int argc, const char **argv, const char *prefix)
{
struct checkout_opts opts;
struct checkout_opts opts = CHECKOUT_OPTS_INIT;
struct option *options = NULL;
struct option switch_options[] = {
OPT_STRING('c', "create", &opts.new_branch, N_("branch"),
Expand All @@ -1980,7 +1984,6 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
int ret;
struct branch_info new_branch_info = { 0 };

memset(&opts, 0, sizeof(opts));
opts.dwim_new_local_branch = 1;
opts.accept_ref = 1;
opts.accept_pathspec = 0;
Expand All @@ -2006,7 +2009,7 @@ int cmd_switch(int argc, const char **argv, const char *prefix)

int cmd_restore(int argc, const char **argv, const char *prefix)
{
struct checkout_opts opts;
struct checkout_opts opts = CHECKOUT_OPTS_INIT;
struct option *options;
struct option restore_options[] = {
OPT_STRING('s', "source", &opts.from_treeish, "<tree-ish>",
Expand All @@ -2023,7 +2026,6 @@ int cmd_restore(int argc, const char **argv, const char *prefix)
int ret;
struct branch_info new_branch_info = { 0 };

memset(&opts, 0, sizeof(opts));
opts.accept_ref = 0;
opts.accept_pathspec = 1;
opts.empty_pathspec_ok = 0;
Expand Down
6 changes: 4 additions & 2 deletions merge-ll.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@ static enum ll_merge_result ll_xdl_merge(const struct ll_merge_driver *drv_unuse
xmp.level = XDL_MERGE_ZEALOUS;
xmp.favor = opts->variant;
xmp.xpp.flags = opts->xdl_opts;
if (git_xmerge_style >= 0)
if (opts->conflict_style >= 0)
xmp.style = opts->conflict_style;
else if (git_xmerge_style >= 0)
xmp.style = git_xmerge_style;
if (marker_size > 0)
xmp.marker_size = marker_size;
Expand Down Expand Up @@ -401,7 +403,7 @@ enum ll_merge_result ll_merge(mmbuffer_t *result_buf,
const struct ll_merge_options *opts)
{
struct attr_check *check = load_merge_attributes();
static const struct ll_merge_options default_opts;
static const struct ll_merge_options default_opts = LL_MERGE_OPTIONS_INIT;
const char *ll_driver_name = NULL;
int marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
const struct ll_merge_driver *driver;
Expand Down
5 changes: 5 additions & 0 deletions merge-ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,15 @@ struct ll_merge_options {
*/
unsigned extra_marker_size;

/* Override the global conflict style. */
int conflict_style;

/* Extra xpparam_t flags as defined in xdiff/xdiff.h. */
long xdl_opts;
};

#define LL_MERGE_OPTIONS_INIT { .conflict_style = -1 }

enum ll_merge_result {
LL_MERGE_ERROR = -1,
LL_MERGE_OK = 0,
Expand Down
3 changes: 2 additions & 1 deletion merge-ort.c
Original file line number Diff line number Diff line change
Expand Up @@ -2025,7 +2025,7 @@ static int merge_3way(struct merge_options *opt,
mmbuffer_t *result_buf)
{
mmfile_t orig, src1, src2;
struct ll_merge_options ll_opts = {0};
struct ll_merge_options ll_opts = LL_MERGE_OPTIONS_INIT;
char *base, *name1, *name2;
enum ll_merge_result merge_status;

Expand All @@ -2035,6 +2035,7 @@ static int merge_3way(struct merge_options *opt,
ll_opts.renormalize = opt->renormalize;
ll_opts.extra_marker_size = extra_marker_size;
ll_opts.xdl_opts = opt->xdl_opts;
ll_opts.conflict_style = opt->conflict_style;

if (opt->priv->call_depth) {
ll_opts.virtual_ancestor = 1;
Expand Down
5 changes: 4 additions & 1 deletion merge-recursive.c
Original file line number Diff line number Diff line change
Expand Up @@ -1048,13 +1048,14 @@ static int merge_3way(struct merge_options *opt,
const int extra_marker_size)
{
mmfile_t orig, src1, src2;
struct ll_merge_options ll_opts = {0};
struct ll_merge_options ll_opts = LL_MERGE_OPTIONS_INIT;
char *base, *name1, *name2;
enum ll_merge_result merge_status;

ll_opts.renormalize = opt->renormalize;
ll_opts.extra_marker_size = extra_marker_size;
ll_opts.xdl_opts = opt->xdl_opts;
ll_opts.conflict_style = opt->conflict_style;

if (opt->priv->call_depth) {
ll_opts.virtual_ancestor = 1;
Expand Down Expand Up @@ -3947,6 +3948,8 @@ void init_merge_options(struct merge_options *opt,

opt->renormalize = 0;

opt->conflict_style = -1;

merge_recursive_config(opt);
merge_verbosity = getenv("GIT_MERGE_VERBOSITY");
if (merge_verbosity)
Expand Down
1 change: 1 addition & 0 deletions merge-recursive.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct merge_options {

/* xdiff-related options (patience, ignore whitespace, ours/theirs) */
long xdl_opts;
int conflict_style;
enum {
MERGE_VARIANT_NORMAL = 0,
MERGE_VARIANT_OURS,
Expand Down
6 changes: 6 additions & 0 deletions t/t7201-co.sh
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,12 @@ test_expect_success 'checkout --conflict=diff3' '
test_cmp merged file
'

test_expect_success 'checkout with invalid conflict style' '
test_must_fail git checkout --conflict=bad 2>actual -- file &&
echo "fatal: unknown conflict style ${SQ}bad${SQ}" >expect &&
test_cmp expect actual
'

test_expect_success 'failing checkout -b should not break working tree' '
git clean -fd && # Remove untracked files in the way
git reset --hard main &&
Expand Down
29 changes: 18 additions & 11 deletions xdiff-interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,22 @@ int xdiff_compare_lines(const char *l1, long s1,
return xdl_recmatch(l1, s1, l2, s2, flags);
}

int parse_conflict_style(const char *value)
{
if (!strcmp(value, "diff3"))
return XDL_MERGE_DIFF3;
else if (!strcmp(value, "zdiff3"))
return XDL_MERGE_ZEALOUS_DIFF3;
else if (!strcmp(value, "merge"))
return 0;
/*
* Please update _git_checkout() in git-completion.bash when
* you add new merge config
*/
else
return -1;
}

int git_xmerge_style = -1;

int git_xmerge_config(const char *var, const char *value,
Expand All @@ -313,17 +329,8 @@ int git_xmerge_config(const char *var, const char *value,
if (!strcmp(var, "merge.conflictstyle")) {
if (!value)
return config_error_nonbool(var);
if (!strcmp(value, "diff3"))
git_xmerge_style = XDL_MERGE_DIFF3;
else if (!strcmp(value, "zdiff3"))
git_xmerge_style = XDL_MERGE_ZEALOUS_DIFF3;
else if (!strcmp(value, "merge"))
git_xmerge_style = 0;
/*
* Please update _git_checkout() in
* git-completion.bash when you add new merge config
*/
else
git_xmerge_style = parse_conflict_style(value);
if (git_xmerge_style == -1)
return error(_("unknown style '%s' given for '%s'"),
value, var);
return 0;
Expand Down
1 change: 1 addition & 0 deletions xdiff-interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ int buffer_is_binary(const char *ptr, unsigned long size);
void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line, int cflags);
void xdiff_clear_find_func(xdemitconf_t *xecfg);
struct config_context;
int parse_conflict_style(const char *value);
int git_xmerge_config(const char *var, const char *value,
const struct config_context *ctx, void *cb);
extern int git_xmerge_style;
Expand Down

0 comments on commit 15c0c65

Please sign in to comment.