Skip to content

Commit

Permalink
Merge branch 'ad/merge-with-diff-algorithm' into next
Browse files Browse the repository at this point in the history
Many Porcelain commands that internally use the merge machinery
were taught to consistently honor the diff.algorithm configuration.

* ad/merge-with-diff-algorithm:
  merge-recursive: honor diff.algorithm
  • Loading branch information
gitster committed Jul 16, 2024
2 parents 3e860b3 + 9c93ba4 commit 90fe5af
Show file tree
Hide file tree
Showing 15 changed files with 150 additions and 15 deletions.
2 changes: 1 addition & 1 deletion builtin/am.c
Original file line number Diff line number Diff line change
Expand Up @@ -1630,7 +1630,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
* changes.
*/

init_merge_options(&o, the_repository);
init_ui_merge_options(&o, the_repository);

o.branch1 = "HEAD";
their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg);
Expand Down
2 changes: 1 addition & 1 deletion builtin/checkout.c
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,7 @@ static int merge_working_tree(const struct checkout_opts *opts,

add_files_to_cache(the_repository, NULL, NULL, NULL, 0,
0);
init_merge_options(&o, the_repository);
init_ui_merge_options(&o, the_repository);
o.verbosity = 0;
work = write_in_core_index_as_tree(the_repository);

Expand Down
2 changes: 1 addition & 1 deletion builtin/merge-recursive.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix UNUSED)
char *better1, *better2;
struct commit *result;

init_merge_options(&o, the_repository);
init_basic_merge_options(&o, the_repository);
if (argv[0] && ends_with(argv[0], "-subtree"))
o.subtree_shift = "";

Expand Down
2 changes: 1 addition & 1 deletion builtin/merge-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
};

/* Init merge options */
init_merge_options(&o.merge_options, the_repository);
init_ui_merge_options(&o.merge_options, the_repository);

/* Parse arguments */
original_argc = argc - 1; /* ignoring argv[0] */
Expand Down
2 changes: 1 addition & 1 deletion builtin/merge.c
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
return 2;
}

init_merge_options(&o, the_repository);
init_ui_merge_options(&o, the_repository);
if (!strcmp(strategy, "subtree"))
o.subtree_shift = "";

Expand Down
2 changes: 1 addition & 1 deletion builtin/replay.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ int cmd_replay(int argc, const char **argv, const char *prefix)
goto cleanup;
}

init_merge_options(&merge_opt, the_repository);
init_basic_merge_options(&merge_opt, the_repository);
memset(&result, 0, sizeof(result));
merge_opt.show_rename_progress = 0;
last_commit = onto;
Expand Down
2 changes: 1 addition & 1 deletion builtin/stash.c
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
}
}

init_merge_options(&o, the_repository);
init_ui_merge_options(&o, the_repository);

o.branch1 = "Updated upstream";
o.branch2 = "Stashed changes";
Expand Down
2 changes: 1 addition & 1 deletion log-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -1025,7 +1025,7 @@ static int do_remerge_diff(struct rev_info *opt,
struct strbuf parent2_desc = STRBUF_INIT;

/* Setup merge options */
init_merge_options(&o, the_repository);
init_ui_merge_options(&o, the_repository);
o.show_rename_progress = 0;
o.record_conflict_msgs_as_headers = 1;
o.msg_header_prefix = "remerge";
Expand Down
29 changes: 25 additions & 4 deletions merge-recursive.c
Original file line number Diff line number Diff line change
Expand Up @@ -3921,7 +3921,7 @@ int merge_recursive_generic(struct merge_options *opt,
return clean ? 0 : 1;
}

static void merge_recursive_config(struct merge_options *opt)
static void merge_recursive_config(struct merge_options *opt, int ui)
{
char *value = NULL;
int renormalize = 0;
Expand Down Expand Up @@ -3950,11 +3950,20 @@ static void merge_recursive_config(struct merge_options *opt)
} /* avoid erroring on values from future versions of git */
free(value);
}
if (ui) {
if (!git_config_get_string("diff.algorithm", &value)) {
long diff_algorithm = parse_algorithm_value(value);
if (diff_algorithm < 0)
die(_("unknown value for config '%s': %s"), "diff.algorithm", value);
opt->xdl_opts = (opt->xdl_opts & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;
free(value);
}
}
git_config(git_xmerge_config, NULL);
}

void init_merge_options(struct merge_options *opt,
struct repository *repo)
static void init_merge_options(struct merge_options *opt,
struct repository *repo, int ui)
{
const char *merge_verbosity;
memset(opt, 0, sizeof(struct merge_options));
Expand All @@ -3973,14 +3982,26 @@ void init_merge_options(struct merge_options *opt,

opt->conflict_style = -1;

merge_recursive_config(opt);
merge_recursive_config(opt, ui);
merge_verbosity = getenv("GIT_MERGE_VERBOSITY");
if (merge_verbosity)
opt->verbosity = strtol(merge_verbosity, NULL, 10);
if (opt->verbosity >= 5)
opt->buffer_output = 0;
}

void init_ui_merge_options(struct merge_options *opt,
struct repository *repo)
{
init_merge_options(opt, repo, 1);
}

void init_basic_merge_options(struct merge_options *opt,
struct repository *repo)
{
init_merge_options(opt, repo, 0);
}

/*
* For now, members of merge_options do not need deep copying, but
* it may change in the future, in which case we would need to update
Expand Down
5 changes: 4 additions & 1 deletion merge-recursive.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ struct merge_options {
struct merge_options_internal *priv;
};

void init_merge_options(struct merge_options *opt, struct repository *repo);
/* for use by porcelain commands */
void init_ui_merge_options(struct merge_options *opt, struct repository *repo);
/* for use by plumbing commands */
void init_basic_merge_options(struct merge_options *opt, struct repository *repo);

void copy_merge_options(struct merge_options *dst, struct merge_options *src);
void clear_merge_options(struct merge_options *opt);
Expand Down
4 changes: 2 additions & 2 deletions sequencer.c
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ static int do_recursive_merge(struct repository *r,

repo_read_index(r);

init_merge_options(&o, r);
init_ui_merge_options(&o, r);
o.ancestor = base ? base_label : "(empty tree)";
o.branch1 = "HEAD";
o.branch2 = next ? next_label : "(empty tree)";
Expand Down Expand Up @@ -4309,7 +4309,7 @@ static int do_merge(struct repository *r,
bases = reverse_commit_list(bases);

repo_read_index(r);
init_merge_options(&o, r);
init_ui_merge_options(&o, r);
o.branch1 = "HEAD";
o.branch2 = ref_name.buf;
o.buffer_output = 2;
Expand Down
60 changes: 60 additions & 0 deletions t/t7615-diff-algo-with-mergy-operations.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/bin/sh

test_description='git merge and other operations that rely on merge
Testing the influence of the diff algorithm on the merge output.'

TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh

test_expect_success 'setup' '
cp "$TEST_DIRECTORY"/t7615/base.c file.c &&
git add file.c &&
git commit -m c0 &&
git tag c0 &&
cp "$TEST_DIRECTORY"/t7615/ours.c file.c &&
git add file.c &&
git commit -m c1 &&
git tag c1 &&
git reset --hard c0 &&
cp "$TEST_DIRECTORY"/t7615/theirs.c file.c &&
git add file.c &&
git commit -m c2 &&
git tag c2
'

GIT_TEST_MERGE_ALGORITHM=recursive

test_expect_success 'merge c2 to c1 with recursive merge strategy fails with the current default myers diff algorithm' '
git reset --hard c1 &&
test_must_fail git merge -s recursive c2
'

test_expect_success 'merge c2 to c1 with recursive merge strategy succeeds with -Xdiff-algorithm=histogram' '
git reset --hard c1 &&
git merge --strategy recursive -Xdiff-algorithm=histogram c2
'

test_expect_success 'merge c2 to c1 with recursive merge strategy succeeds with diff.algorithm = histogram' '
git reset --hard c1 &&
git config diff.algorithm histogram &&
git merge --strategy recursive c2
'

test_expect_success 'cherry-pick c2 to c1 with recursive merge strategy fails with the current default myers diff algorithm' '
git reset --hard c1 &&
test_must_fail git cherry-pick -s recursive c2
'

test_expect_success 'cherry-pick c2 to c1 with recursive merge strategy succeeds with -Xdiff-algorithm=histogram' '
git reset --hard c1 &&
git cherry-pick --strategy recursive -Xdiff-algorithm=histogram c2
'

test_expect_success 'cherry-pick c2 to c1 with recursive merge strategy succeeds with diff.algorithm = histogram' '
git reset --hard c1 &&
git config diff.algorithm histogram &&
git cherry-pick --strategy recursive c2
'

test_done
17 changes: 17 additions & 0 deletions t/t7615/base.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
int f(int x, int y)
{
if (x == 0)
{
return y;
}
return x;
}

int g(size_t u)
{
while (u < 30)
{
u++;
}
return u;
}
17 changes: 17 additions & 0 deletions t/t7615/ours.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
int g(size_t u)
{
while (u < 30)
{
u++;
}
return u;
}

int h(int x, int y, int z)
{
if (z == 0)
{
return x;
}
return y;
}
17 changes: 17 additions & 0 deletions t/t7615/theirs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
int f(int x, int y)
{
if (x == 0)
{
return y;
}
return x;
}

int g(size_t u)
{
while (u > 34)
{
u--;
}
return u;
}

0 comments on commit 90fe5af

Please sign in to comment.