diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 9719311b42f1beadeca752888dbd12a05ce511f8..48ce747cf4dad592d642735856eb156e93d6cf30 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -6,6 +6,11 @@ merge.log:: Whether to include summaries of merged commits in newly created merge commit messages. False by default. +merge.renameLimit:: + The number of files to consider when performing rename detection + during a merge; if not specified, defaults to the value of + diff.renameLimit. + merge.tool:: Controls which merge resolution program is used by linkgit:git-mergetool[1]. Valid built-in values are: "kdiff3", diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index 910c0d20e7ba1128c705a49bfd9966212c5420b2..46e636fdcf1cb854a486e425df05a2485d18d5d7 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -92,7 +92,8 @@ static struct path_list current_directory_set = {NULL, 0, 0, 1}; static int call_depth = 0; static int verbosity = 2; -static int rename_limit = -1; +static int diff_rename_limit = -1; +static int merge_rename_limit = -1; static int buffer_output = 1; static struct strbuf obuf = STRBUF_INIT; @@ -361,7 +362,10 @@ static struct path_list *get_renames(struct tree *tree, diff_setup(&opts); DIFF_OPT_SET(&opts, RECURSIVE); opts.detect_rename = DIFF_DETECT_RENAME; - opts.rename_limit = rename_limit; + opts.rename_limit = merge_rename_limit >= 0 ? merge_rename_limit : + diff_rename_limit >= 0 ? diff_rename_limit : + 500; + opts.warn_on_too_large_rename = 1; opts.output_format = DIFF_FORMAT_NO_OUTPUT; if (diff_setup_done(&opts) < 0) die("diff setup failed"); @@ -1343,7 +1347,11 @@ static int merge_config(const char *var, const char *value) return 0; } if (!strcasecmp(var, "diff.renamelimit")) { - rename_limit = git_config_int(var, value); + diff_rename_limit = git_config_int(var, value); + return 0; + } + if (!strcasecmp(var, "merge.renamelimit")) { + merge_rename_limit = git_config_int(var, value); return 0; } return git_default_config(var, value); diff --git a/diff.c b/diff.c index e35384b4442fbaedbf460ddf61c32b85dde2a4d7..439d4746cae343f08b298473d35d9792048abfa0 100644 --- a/diff.c +++ b/diff.c @@ -19,7 +19,7 @@ #endif static int diff_detect_rename_default; -static int diff_rename_limit_default = 100; +static int diff_rename_limit_default = 200; int diff_use_color_default = -1; static const char *external_diff_cmd_cfg; int diff_auto_refresh_index = 1; diff --git a/diff.h b/diff.h index 1bd94a4807c741e7cb2e4d8eb9f6476eba691388..3a02d38d12d94c39ff9ef3ab744ea7d157fb52b4 100644 --- a/diff.h +++ b/diff.h @@ -83,6 +83,7 @@ struct diff_options { int pickaxe_opts; int rename_score; int rename_limit; + int warn_on_too_large_rename; int dirstat_percent; int setup; int abbrev; diff --git a/diffcore-rename.c b/diffcore-rename.c index 1369a5ec45349c1ef04e4df2d7d7d4dd28cd3596..1b2ebb40014d820fe4fb679509ab694d453be7b4 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -492,7 +492,8 @@ void diffcore_rename(struct diff_options *options) rename_limit = 32767; if ((num_create > rename_limit && num_src > rename_limit) || (num_create * num_src > rename_limit * rename_limit)) { - warning("too many files, skipping inexact rename detection"); + if (options->warn_on_too_large_rename) + warning("too many files, skipping inexact rename detection"); goto cleanup; } diff --git a/t/t6032-merge-large-rename.sh b/t/t6032-merge-large-rename.sh new file mode 100755 index 0000000000000000000000000000000000000000..eac5ebac24a0174fa20625a19835861573147a26 --- /dev/null +++ b/t/t6032-merge-large-rename.sh @@ -0,0 +1,73 @@ +#!/bin/sh + +test_description='merging with large rename matrix' +. ./test-lib.sh + +count() { + i=1 + while test $i -le $1; do + echo $i + i=$(($i + 1)) + done +} + +test_expect_success 'setup (initial)' ' + touch file && + git add . && + git commit -m initial && + git tag initial +' + +make_text() { + echo $1: $2 + for i in `count 20`; do + echo $1: $i + done + echo $1: $3 +} + +test_rename() { + test_expect_success "rename ($1, $2)" ' + n='$1' + expect='$2' + git checkout -f master && + git branch -D test$n || true && + git reset --hard initial && + for i in $(count $n); do + make_text $i initial initial >$i + done && + git add . && + git commit -m add=$n && + for i in $(count $n); do + make_text $i changed initial >$i + done && + git commit -a -m change=$n && + git checkout -b test$n HEAD^ && + for i in $(count $n); do + git rm $i + make_text $i initial changed >$i.moved + done && + git add . && + git commit -m change+rename=$n && + case "$expect" in + ok) git merge master ;; + *) test_must_fail git merge master ;; + esac + ' +} + +test_rename 5 ok + +test_expect_success 'set diff.renamelimit to 4' ' + git config diff.renamelimit 4 +' +test_rename 4 ok +test_rename 5 fail + +test_expect_success 'set merge.renamelimit to 5' ' + git config merge.renamelimit 5 +' +test_rename 5 ok +test_rename 6 fail + +test_done diff --git a/wt-status.c b/wt-status.c index 532b4ea2c1960f18e41a5167a60f6de1b481606b..a44c5433754eb89cb84a64c7c7c6d2181bcf7641 100644 --- a/wt-status.c +++ b/wt-status.c @@ -206,7 +206,7 @@ static void wt_status_print_updated(struct wt_status *s) rev.diffopt.format_callback = wt_status_print_updated_cb; rev.diffopt.format_callback_data = s; rev.diffopt.detect_rename = 1; - rev.diffopt.rename_limit = 100; + rev.diffopt.rename_limit = 200; rev.diffopt.break_opt = 0; run_diff_index(&rev, 1); }