From 2a2ac926547bc4fa91fcd1cb741dd5691ba9b974 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 30 Apr 2008 13:23:55 -0400 Subject: [PATCH 1/3] add merge.renamelimit config option The point of rename limiting is to bound the amount of time we spend figuring out inexact renames. Currently we use a single value, diff.renamelimit, for all situations. However, it is probably the case that a user is willing to spend more time finding renames during a merge than they are while looking at git-log. This patch provides a way of setting those values separately (though for backwards compatibility, merge still falls back on the diff renamelimit). Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- Documentation/merge-config.txt | 5 +++ builtin-merge-recursive.c | 13 ++++-- t/t6032-merge-large-rename.sh | 73 ++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 3 deletions(-) create mode 100755 t/t6032-merge-large-rename.sh diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 9719311b42..48ce747cf4 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 910c0d20e7..1293e3d342 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,9 @@ 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 : + 100; opts.output_format = DIFF_FORMAT_NO_OUTPUT; if (diff_setup_done(&opts) < 0) die("diff setup failed"); @@ -1343,7 +1346,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/t/t6032-merge-large-rename.sh b/t/t6032-merge-large-rename.sh new file mode 100755 index 0000000000..eac5ebac24 --- /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 From 50705915eae89eae490dff30fa370ed02e4d6e72 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 30 Apr 2008 13:24:43 -0400 Subject: [PATCH 2/3] bump rename limit defaults The current rename limit default of 100 was arbitrarily chosen. Testing[1] has shown that on modern hardware, a limit of 200 adds about a second of computation time, and a limit of 500 adds about 5 seconds of computation time. This patch bumps the default limit to 200 for viewing diffs, and to 500 for performing a merge. The limit for generating git-status templates is set independently; we bump it up to 200 here, as well, to match the diff limit. [1]: See <20080211113516.GB6344@coredump.intra.peff.net> Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-merge-recursive.c | 2 +- diff.c | 2 +- wt-status.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index 1293e3d342..3902e91069 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -364,7 +364,7 @@ static struct path_list *get_renames(struct tree *tree, opts.detect_rename = DIFF_DETECT_RENAME; opts.rename_limit = merge_rename_limit >= 0 ? merge_rename_limit : diff_rename_limit >= 0 ? diff_rename_limit : - 100; + 500; opts.output_format = DIFF_FORMAT_NO_OUTPUT; if (diff_setup_done(&opts) < 0) die("diff setup failed"); diff --git a/diff.c b/diff.c index 3632b552b2..f7355191dd 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/wt-status.c b/wt-status.c index 532b4ea2c1..a44c543375 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); } From b8960bbe7bdfc0b232462f916ee8151c83afd16f Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 30 Apr 2008 13:25:53 -0400 Subject: [PATCH 3/3] diff: make "too many files" rename warning optional In many cases, the warning ends up as clutter, because the diff is being done "behind the scenes" from the user (e.g., when generating a commit diffstat), and whether we show renames or not is not particularly interesting to the user. However, in the case of a merge (which is what motivated the warning in the first place), it is a useful hint as to why a merge with renames might have failed. This patch makes the warning optional based on the code calling into diffcore. We default to not showing the warning, but turn it on for merges. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-merge-recursive.c | 1 + diff.h | 1 + diffcore-rename.c | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index 3902e91069..46e636fdcf 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -365,6 +365,7 @@ static struct path_list *get_renames(struct tree *tree, 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"); diff --git a/diff.h b/diff.h index f2c77391a9..8931116068 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 1369a5ec45..1b2ebb4001 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; }