diff options
Diffstat (limited to 'diffcore-rename.c')
-rw-r--r-- | diffcore-rename.c | 105 |
1 files changed, 62 insertions, 43 deletions
diff --git a/diffcore-rename.c b/diffcore-rename.c index 168a95b541..d40e40a3ac 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -5,6 +5,7 @@ #include "diff.h" #include "diffcore.h" #include "hash.h" +#include "progress.h" /* Table of rename/copy destinations */ @@ -153,9 +154,9 @@ static int estimate_similarity(struct diff_filespec *src, * is a possible size - we really should have a flag to * say whether the size is valid or not!) */ - if (!src->cnt_data && diff_populate_filespec(src, 0)) + if (!src->cnt_data && diff_populate_filespec(src, 1)) return 0; - if (!dst->cnt_data && diff_populate_filespec(dst, 0)) + if (!dst->cnt_data && diff_populate_filespec(dst, 1)) return 0; max_size = ((src->size > dst->size) ? src->size : dst->size); @@ -170,7 +171,12 @@ static int estimate_similarity(struct diff_filespec *src, * and the final score computation below would not have a * divide-by-zero issue. */ - if (base_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE) + if (max_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE) + return 0; + + if (!src->cnt_data && diff_populate_filespec(src, 0)) + return 0; + if (!dst->cnt_data && diff_populate_filespec(dst, 0)) return 0; delta_limit = (unsigned long) @@ -242,7 +248,8 @@ struct file_similarity { }; static int find_identical_files(struct file_similarity *src, - struct file_similarity *dst) + struct file_similarity *dst, + struct diff_options *options) { int renames = 0; @@ -262,7 +269,7 @@ static int find_identical_files(struct file_similarity *src, int score; struct diff_filespec *source = p->filespec; - /* False hash collission? */ + /* False hash collision? */ if (hashcmp(source->sha1, target->sha1)) continue; /* Non-regular files? If so, the modes must match! */ @@ -272,6 +279,8 @@ static int find_identical_files(struct file_similarity *src, } /* Give higher scores to sources that haven't been used already */ score = !source->rename_used; + if (source->rename_used && options->detect_rename != DIFF_DETECT_COPY) + continue; score += basename_same(source, target); if (score > best_score) { best = p; @@ -301,11 +310,12 @@ static void free_similarity_list(struct file_similarity *p) } } -static int find_same_files(void *ptr) +static int find_same_files(void *ptr, void *data) { int ret; struct file_similarity *p = ptr; struct file_similarity *src = NULL, *dst = NULL; + struct diff_options *options = data; /* Split the hash list up into sources and destinations */ do { @@ -324,7 +334,7 @@ static int find_same_files(void *ptr) * If we have both sources *and* destinations, see if * we can match them up */ - ret = (src && dst) ? find_identical_files(src, dst) : 0; + ret = (src && dst) ? find_identical_files(src, dst, options) : 0; /* Free the hashes and return the number of renames found */ free_similarity_list(src); @@ -372,7 +382,7 @@ static void insert_file_table(struct hash_table *table, int src_dst, int index, * and then during the second round we try to match * cache-dirty entries as well. */ -static int find_exact_renames(void) +static int find_exact_renames(struct diff_options *options) { int i; struct hash_table file_table; @@ -385,7 +395,7 @@ static int find_exact_renames(void) insert_file_table(&file_table, 1, i, rename_dst[i].two); /* Find the renames */ - i = for_each_hash(&file_table, find_same_files); + i = for_each_hash(&file_table, find_same_files, options); /* .. and free the hash data structure */ free_hash(&file_table); @@ -409,6 +419,27 @@ static void record_if_better(struct diff_score m[], struct diff_score *o) m[worst] = *o; } +static int find_renames(struct diff_score *mx, int dst_cnt, int minimum_score, int copies) +{ + int count = 0, i; + + for (i = 0; i < dst_cnt * NUM_CANDIDATE_PER_DST; i++) { + struct diff_rename_dst *dst; + + if ((mx[i].dst < 0) || + (mx[i].score < minimum_score)) + break; /* there is no more usable pair. */ + dst = &rename_dst[mx[i].dst]; + if (dst->pair) + continue; /* already done, either exact or fuzzy. */ + if (!copies && rename_src[mx[i].src].one->rename_used) + continue; + record_rename_pair(mx[i].dst, mx[i].src, mx[i].score); + count++; + } + return count; +} + void diffcore_rename(struct diff_options *options) { int detect_rename = options->detect_rename; @@ -419,6 +450,7 @@ void diffcore_rename(struct diff_options *options) struct diff_score *mx; int i, j, rename_count; int num_create, num_src, dst_cnt; + struct progress *progress = NULL; if (!minimum_score) minimum_score = DEFAULT_RENAME_SCORE; @@ -462,7 +494,7 @@ void diffcore_rename(struct diff_options *options) * We really want to cull the candidates list early * with cheap tests in order to avoid doing deltas. */ - rename_count = find_exact_renames(); + rename_count = find_exact_renames(options); /* Did we only want exact renames? */ if (minimum_score == MAX_SCORE) @@ -488,15 +520,22 @@ void diffcore_rename(struct diff_options *options) * but handles the potential overflow case specially (and we * assume at least 32-bit integers) */ + options->needed_rename_limit = 0; if (rename_limit <= 0 || rename_limit > 32767) rename_limit = 32767; if ((num_create > rename_limit && num_src > rename_limit) || (num_create * num_src > rename_limit * rename_limit)) { - if (options->warn_on_too_large_rename) - warning("too many files (created: %d deleted: %d), skipping inexact rename detection", num_create, num_src); + options->needed_rename_limit = + num_src > num_create ? num_src : num_create; goto cleanup; } + if (options->show_rename_progress) { + progress = start_progress_delay( + "Performing inexact rename detection", + rename_dst_nr * rename_src_nr, 50, 1); + } + mx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx)); for (dst_cnt = i = 0; i < rename_dst_nr; i++) { struct diff_filespec *two = rename_dst[i].two; @@ -518,51 +557,31 @@ void diffcore_rename(struct diff_options *options) this_src.dst = i; this_src.src = j; record_if_better(m, &this_src); + /* + * Once we run estimate_similarity, + * We do not need the text anymore. + */ diff_free_filespec_blob(one); + diff_free_filespec_blob(two); } - /* We do not need the text anymore */ - diff_free_filespec_blob(two); dst_cnt++; + display_progress(progress, (i+1)*rename_src_nr); } + stop_progress(&progress); /* cost matrix sorted by most to least similar pair */ qsort(mx, dst_cnt * NUM_CANDIDATE_PER_DST, sizeof(*mx), score_compare); - for (i = 0; i < dst_cnt * NUM_CANDIDATE_PER_DST; i++) { - struct diff_rename_dst *dst; - - if ((mx[i].dst < 0) || - (mx[i].score < minimum_score)) - break; /* there is no more usable pair. */ - dst = &rename_dst[mx[i].dst]; - if (dst->pair) - continue; /* already done, either exact or fuzzy. */ - if (rename_src[mx[i].src].one->rename_used) - continue; - record_rename_pair(mx[i].dst, mx[i].src, mx[i].score); - rename_count++; - } - - for (i = 0; i < dst_cnt * NUM_CANDIDATE_PER_DST; i++) { - struct diff_rename_dst *dst; - - if ((mx[i].dst < 0) || - (mx[i].score < minimum_score)) - break; /* there is no more usable pair. */ - dst = &rename_dst[mx[i].dst]; - if (dst->pair) - continue; /* already done, either exact or fuzzy. */ - record_rename_pair(mx[i].dst, mx[i].src, mx[i].score); - rename_count++; - } + rename_count += find_renames(mx, dst_cnt, minimum_score, 0); + if (detect_rename == DIFF_DETECT_COPY) + rename_count += find_renames(mx, dst_cnt, minimum_score, 1); free(mx); cleanup: /* At this point, we have found some renames and copies and they * are recorded in rename_dst. The original list is still in *q. */ - outq.queue = NULL; - outq.nr = outq.alloc = 0; + DIFF_QUEUE_CLEAR(&outq); for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; struct diff_filepair *pair_to_free = NULL; |