diffcore-rename: fall back to -C when -C -C busts the rename limit

When there are too many paths in the project, the number of rename source
candidates "git diff -C -C" finds will exceed the rename detection limit,
and no inexact rename detection is performed.  We however could fall back
to "git diff -C" if the number of modified paths is sufficiently small.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Junio C Hamano
2011-01-06 13:50:06 -08:00
parent e88d6bc6f9
commit f31027c99c
7 changed files with 112 additions and 10 deletions

View File

@ -420,11 +420,18 @@ static void record_if_better(struct diff_score m[], struct diff_score *o)
m[worst] = *o;
}
/*
* Returns:
* 0 if we are under the limit;
* 1 if we need to disable inexact rename detection;
* 2 if we would be under the limit if we were given -C instead of -C -C.
*/
static int too_many_rename_candidates(int num_create,
struct diff_options *options)
{
int rename_limit = options->rename_limit;
int num_src = rename_src_nr;
int i;
options->needed_rename_limit = 0;
@ -445,6 +452,20 @@ static int too_many_rename_candidates(int num_create,
options->needed_rename_limit =
num_src > num_create ? num_src : num_create;
/* Are we running under -C -C? */
if (!DIFF_OPT_TST(options, FIND_COPIES_HARDER))
return 1;
/* Would we bust the limit if we were running under -C? */
for (num_src = i = 0; i < rename_src_nr; i++) {
if (diff_unmodified_pair(rename_src[i].p))
continue;
num_src++;
}
if ((num_create <= rename_limit || num_src <= rename_limit) &&
(num_create * num_src <= rename_limit * rename_limit))
return 2;
return 1;
}
@ -476,7 +497,7 @@ void diffcore_rename(struct diff_options *options)
struct diff_queue_struct *q = &diff_queued_diff;
struct diff_queue_struct outq;
struct diff_score *mx;
int i, j, rename_count;
int i, j, rename_count, skip_unmodified = 0;
int num_create, num_src, dst_cnt;
struct progress *progress = NULL;
@ -539,8 +560,16 @@ void diffcore_rename(struct diff_options *options)
if (!num_create)
goto cleanup;
if (too_many_rename_candidates(num_create, options))
switch (too_many_rename_candidates(num_create, options)) {
case 1:
goto cleanup;
case 2:
options->degraded_cc_to_c = 1;
skip_unmodified = 1;
break;
default:
break;
}
if (options->show_rename_progress) {
progress = start_progress_delay(
@ -563,6 +592,11 @@ void diffcore_rename(struct diff_options *options)
for (j = 0; j < rename_src_nr; j++) {
struct diff_filespec *one = rename_src[j].p->one;
struct diff_score this_src;
if (skip_unmodified &&
diff_unmodified_pair(rename_src[j].p))
continue;
this_src.score = estimate_similarity(one, two,
minimum_score);
this_src.name_score = basename_same(one, two);