diffcore-rename.c 17.4 KB
Newer Older
1 2 3 4 5 6
/*
 * Copyright (C) 2005 Junio C Hamano
 */
#include "cache.h"
#include "diff.h"
#include "diffcore.h"
7
#include "hash.h"
8
#include "progress.h"
9

10 11 12 13 14 15 16
/* Table of rename/copy destinations */

static struct diff_rename_dst {
	struct diff_filespec *two;
	struct diff_filepair *pair;
} *rename_dst;
static int rename_dst_nr, rename_dst_alloc;
17

18 19
static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
						 int insert_ok)
20
{
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
	int first, last;

	first = 0;
	last = rename_dst_nr;
	while (last > first) {
		int next = (last + first) >> 1;
		struct diff_rename_dst *dst = &(rename_dst[next]);
		int cmp = strcmp(two->path, dst->two->path);
		if (!cmp)
			return dst;
		if (cmp < 0) {
			last = next;
			continue;
		}
		first = next+1;
	}
	/* not found */
	if (!insert_ok)
		return NULL;
	/* insert to make it at "first" */
	if (rename_dst_alloc <= rename_dst_nr) {
		rename_dst_alloc = alloc_nr(rename_dst_alloc);
		rename_dst = xrealloc(rename_dst,
				      rename_dst_alloc * sizeof(*rename_dst));
	}
	rename_dst_nr++;
	if (first < rename_dst_nr)
		memmove(rename_dst + first + 1, rename_dst + first,
			(rename_dst_nr - first - 1) * sizeof(*rename_dst));
J
Junio C Hamano 已提交
50 51
	rename_dst[first].two = alloc_filespec(two->path);
	fill_filespec(rename_dst[first].two, two->sha1, two->mode);
52 53
	rename_dst[first].pair = NULL;
	return &(rename_dst[first]);
54 55
}

56
/* Table of rename/copy src files */
57 58
static struct diff_rename_src {
	struct diff_filespec *one;
59
	unsigned short score; /* to remember the break score */
60 61
} *rename_src;
static int rename_src_nr, rename_src_alloc;
62

63
static struct diff_rename_src *register_rename_src(struct diff_filespec *one,
64
						   unsigned short score)
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
{
	int first, last;

	first = 0;
	last = rename_src_nr;
	while (last > first) {
		int next = (last + first) >> 1;
		struct diff_rename_src *src = &(rename_src[next]);
		int cmp = strcmp(one->path, src->one->path);
		if (!cmp)
			return src;
		if (cmp < 0) {
			last = next;
			continue;
		}
		first = next+1;
	}
82

83 84 85 86 87
	/* insert to make it at "first" */
	if (rename_src_alloc <= rename_src_nr) {
		rename_src_alloc = alloc_nr(rename_src_alloc);
		rename_src = xrealloc(rename_src,
				      rename_src_alloc * sizeof(*rename_src));
88
	}
89 90 91 92 93
	rename_src_nr++;
	if (first < rename_src_nr)
		memmove(rename_src + first + 1, rename_src + first,
			(rename_src_nr - first - 1) * sizeof(*rename_src));
	rename_src[first].one = one;
94
	rename_src[first].score = score;
95
	return &(rename_src[first]);
96 97
}

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
static int basename_same(struct diff_filespec *src, struct diff_filespec *dst)
{
	int src_len = strlen(src->path), dst_len = strlen(dst->path);
	while (src_len && dst_len) {
		char c1 = src->path[--src_len];
		char c2 = dst->path[--dst_len];
		if (c1 != c2)
			return 0;
		if (c1 == '/')
			return 1;
	}
	return (!src_len || src->path[src_len - 1] == '/') &&
		(!dst_len || dst->path[dst_len - 1] == '/');
}

113
struct diff_score {
114 115
	int src; /* index in rename_src */
	int dst; /* index in rename_dst */
116 117
	unsigned short score;
	short name_score;
118 119 120 121 122 123 124 125 126 127 128 129 130
};

static int estimate_similarity(struct diff_filespec *src,
			       struct diff_filespec *dst,
			       int minimum_score)
{
	/* src points at a file that existed in the original tree (or
	 * optionally a file in the destination tree) and dst points
	 * at a newly created file.  They may be quite similar, in which
	 * case we want to say src is renamed to dst or src is copied into
	 * dst, and then some edit has been applied to dst.
	 *
	 * Compare them and return how similar they are, representing
131 132 133 134 135
	 * the score as an integer between 0 and MAX_SCORE.
	 *
	 * When there is an exact match, it is considered a better
	 * match than anything else; the destination does not even
	 * call into this function in that case.
136
	 */
L
Linus Torvalds 已提交
137
	unsigned long max_size, delta_size, base_size, src_copied, literal_added;
138
	unsigned long delta_limit;
139 140
	int score;

141 142 143 144 145 146 147
	/* We deal only with regular files.  Symlink renames are handled
	 * only when they are exact matches --- in other words, no edits
	 * after renaming.
	 */
	if (!S_ISREG(src->mode) || !S_ISREG(dst->mode))
		return 0;

148 149 150 151 152 153 154 155 156
	/*
	 * Need to check that source and destination sizes are
	 * filled in before comparing them.
	 *
	 * If we already have "cnt_data" filled in, we know it's
	 * all good (avoid checking the size for zero, as that
	 * is a possible size - we really should have a flag to
	 * say whether the size is valid or not!)
	 */
157
	if (!src->cnt_data && diff_populate_filespec(src, 1))
158
		return 0;
159
	if (!dst->cnt_data && diff_populate_filespec(dst, 1))
160 161
		return 0;

L
Linus Torvalds 已提交
162
	max_size = ((src->size > dst->size) ? src->size : dst->size);
163
	base_size = ((src->size < dst->size) ? src->size : dst->size);
L
Linus Torvalds 已提交
164
	delta_size = max_size - base_size;
165

166 167
	/* We would not consider edits that change the file size so
	 * drastically.  delta_size must be smaller than
168
	 * (MAX_SCORE-minimum_score)/MAX_SCORE * min(src->size, dst->size).
169
	 *
170 171 172
	 * Note that base_size == 0 case is handled here already
	 * and the final score computation below would not have a
	 * divide-by-zero issue.
173
	 */
174
	if (max_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE)
175 176
		return 0;

177 178 179 180 181
	if (!src->cnt_data && diff_populate_filespec(src, 0))
		return 0;
	if (!dst->cnt_data && diff_populate_filespec(dst, 0))
		return 0;

182 183
	delta_limit = (unsigned long)
		(base_size * (MAX_SCORE-minimum_score) / MAX_SCORE);
184
	if (diffcore_count_changes(src, dst,
185
				   &src->cnt_data, &dst->cnt_data,
186 187
				   delta_limit,
				   &src_copied, &literal_added))
188
		return 0;
189

190 191
	/* How similar are they?
	 * what percentage of material in dst are from source?
192
	 */
L
Linus Torvalds 已提交
193
	if (!dst->size)
194
		score = 0; /* should not happen */
195
	else
196
		score = (int)(src_copied * MAX_SCORE / max_size);
197 198 199
	return score;
}

J
Junio C Hamano 已提交
200
static void record_rename_pair(int dst_index, int src_index, int score)
201
{
202
	struct diff_filespec *src, *dst;
203
	struct diff_filepair *dp;
204

205 206
	if (rename_dst[dst_index].pair)
		die("internal error: dst already matched.");
207

208
	src = rename_src[src_index].one;
209
	src->rename_used++;
210
	src->count++;
211

212
	dst = rename_dst[dst_index].two;
213
	dst->count++;
214

215
	dp = diff_queue(NULL, src, dst);
216
	dp->renamed_pair = 1;
217 218 219 220
	if (!strcmp(src->path, dst->path))
		dp->score = rename_src[src_index].score;
	else
		dp->score = score;
221
	rename_dst[dst_index].pair = dp;
222 223 224 225
}

/*
 * We sort the rename similarity matrix with the score, in descending
226
 * order (the most similar first).
227 228 229 230
 */
static int score_compare(const void *a_, const void *b_)
{
	const struct diff_score *a = a_, *b = b_;
231

232 233 234 235 236 237
	/* sink the unused ones to the bottom */
	if (a->dst < 0)
		return (0 <= b->dst);
	else if (b->dst < 0)
		return -1;

238 239 240
	if (a->score == b->score)
		return b->name_score - a->name_score;

241 242 243
	return b->score - a->score;
}

244 245 246 247 248 249 250
struct file_similarity {
	int src_dst, index;
	struct diff_filespec *filespec;
	struct file_similarity *next;
};

static int find_identical_files(struct file_similarity *src,
251 252
				struct file_similarity *dst,
				struct diff_options *options)
253 254 255 256 257 258 259
{
	int renames = 0;

	/*
	 * Walk over all the destinations ...
	 */
	do {
260
		struct diff_filespec *target = dst->filespec;
261
		struct file_similarity *p, *best;
262
		int i = 100, best_score = -1;
263 264 265 266 267 268

		/*
		 * .. to find the best source match
		 */
		best = NULL;
		for (p = src; p; p = p->next) {
269 270
			int score;
			struct diff_filespec *source = p->filespec;
271

M
Mike Ralphson 已提交
272
			/* False hash collision? */
273
			if (hashcmp(source->sha1, target->sha1))
274 275
				continue;
			/* Non-regular files? If so, the modes must match! */
276 277
			if (!S_ISREG(source->mode) || !S_ISREG(target->mode)) {
				if (source->mode != target->mode)
278 279
					continue;
			}
280 281
			/* Give higher scores to sources that haven't been used already */
			score = !source->rename_used;
282 283
			if (source->rename_used && options->detect_rename != DIFF_DETECT_COPY)
				continue;
284 285 286 287 288 289 290
			score += basename_same(source, target);
			if (score > best_score) {
				best = p;
				best_score = score;
				if (score == 2)
					break;
			}
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312

			/* Too many identical alternatives? Pick one */
			if (!--i)
				break;
		}
		if (best) {
			record_rename_pair(dst->index, best->index, MAX_SCORE);
			renames++;
		}
	} while ((dst = dst->next) != NULL);
	return renames;
}

static void free_similarity_list(struct file_similarity *p)
{
	while (p) {
		struct file_similarity *entry = p;
		p = p->next;
		free(entry);
	}
}

313
static int find_same_files(void *ptr, void *data)
314 315 316 317
{
	int ret;
	struct file_similarity *p = ptr;
	struct file_similarity *src = NULL, *dst = NULL;
318
	struct diff_options *options = data;
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336

	/* Split the hash list up into sources and destinations */
	do {
		struct file_similarity *entry = p;
		p = p->next;
		if (entry->src_dst < 0) {
			entry->next = src;
			src = entry;
		} else {
			entry->next = dst;
			dst = entry;
		}
	} while (p);

	/*
	 * If we have both sources *and* destinations, see if
	 * we can match them up
	 */
337
	ret = (src && dst) ? find_identical_files(src, dst, options) : 0;
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377

	/* Free the hashes and return the number of renames found */
	free_similarity_list(src);
	free_similarity_list(dst);
	return ret;
}

static unsigned int hash_filespec(struct diff_filespec *filespec)
{
	unsigned int hash;
	if (!filespec->sha1_valid) {
		if (diff_populate_filespec(filespec, 0))
			return 0;
		hash_sha1_file(filespec->data, filespec->size, "blob", filespec->sha1);
	}
	memcpy(&hash, filespec->sha1, sizeof(hash));
	return hash;
}

static void insert_file_table(struct hash_table *table, int src_dst, int index, struct diff_filespec *filespec)
{
	void **pos;
	unsigned int hash;
	struct file_similarity *entry = xmalloc(sizeof(*entry));

	entry->src_dst = src_dst;
	entry->index = index;
	entry->filespec = filespec;
	entry->next = NULL;

	hash = hash_filespec(filespec);
	pos = insert_hash(hash, entry, table);

	/* We already had an entry there? */
	if (pos) {
		entry->next = *pos;
		*pos = entry;
	}
}

378 379 380 381 382 383 384
/*
 * Find exact renames first.
 *
 * The first round matches up the up-to-date entries,
 * and then during the second round we try to match
 * cache-dirty entries as well.
 */
385
static int find_exact_renames(struct diff_options *options)
386
{
387 388
	int i;
	struct hash_table file_table;
389

390 391 392 393 394 395 396 397
	init_hash(&file_table);
	for (i = 0; i < rename_src_nr; i++)
		insert_file_table(&file_table, -1, i, rename_src[i].one);

	for (i = 0; i < rename_dst_nr; i++)
		insert_file_table(&file_table, 1, i, rename_dst[i].two);

	/* Find the renames */
398
	i = for_each_hash(&file_table, find_same_files, options);
399 400 401 402 403

	/* .. and free the hash data structure */
	free_hash(&file_table);

	return i;
404 405
}

406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
#define NUM_CANDIDATE_PER_DST 4
static void record_if_better(struct diff_score m[], struct diff_score *o)
{
	int i, worst;

	/* find the worst one */
	worst = 0;
	for (i = 1; i < NUM_CANDIDATE_PER_DST; i++)
		if (score_compare(&m[i], &m[worst]) > 0)
			worst = i;

	/* is it better than the worst one? */
	if (score_compare(&m[worst], o) > 0)
		m[worst] = *o;
}

422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
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;

	options->needed_rename_limit = 0;

	/*
	 * This basically does a test for the rename matrix not
	 * growing larger than a "rename_limit" square matrix, ie:
	 *
	 *    num_create * num_src > rename_limit * rename_limit
	 *
	 * but handles the potential overflow case specially (and we
	 * assume at least 32-bit integers)
	 */
	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))
		return 0;

	options->needed_rename_limit =
		num_src > num_create ? num_src : num_create;
	return 1;
}

450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
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;
}

471
void diffcore_rename(struct diff_options *options)
472
{
473 474
	int detect_rename = options->detect_rename;
	int minimum_score = options->rename_score;
475
	struct diff_queue_struct *q = &diff_queued_diff;
J
Junio C Hamano 已提交
476
	struct diff_queue_struct outq;
477
	struct diff_score *mx;
478
	int i, j, rename_count;
479
	int num_create, num_src, dst_cnt;
480
	struct progress *progress = NULL;
481

482
	if (!minimum_score)
483
		minimum_score = DEFAULT_RENAME_SCORE;
484 485

	for (i = 0; i < q->nr; i++) {
486
		struct diff_filepair *p = q->queue[i];
487
		if (!DIFF_FILE_VALID(p->one)) {
488
			if (!DIFF_FILE_VALID(p->two))
489
				continue; /* unmerged */
490 491 492
			else if (options->single_follow &&
				 strcmp(options->single_follow, p->two->path))
				continue; /* not interested */
493
			else
494
				locate_rename_dst(p->two, 1);
495
		}
496
		else if (!DIFF_FILE_VALID(p->two)) {
497 498
			/*
			 * If the source is a broken "delete", and
499 500
			 * they did not really want to get broken,
			 * that means the source actually stays.
501 502 503 504 505 506 507 508 509 510 511
			 * So we increment the "rename_used" score
			 * by one, to indicate ourselves as a user
			 */
			if (p->broken_pair && !p->score)
				p->one->rename_used++;
			register_rename_src(p->one, p->score);
		}
		else if (detect_rename == DIFF_DETECT_COPY) {
			/*
			 * Increment the "rename_used" score by
			 * one, to indicate ourselves as a user.
512
			 */
513 514
			p->one->rename_used++;
			register_rename_src(p->one, p->score);
515
		}
516
	}
517
	if (rename_dst_nr == 0 || rename_src_nr == 0)
518 519
		goto cleanup; /* nothing to do */

520 521 522 523
	/*
	 * We really want to cull the candidates list early
	 * with cheap tests in order to avoid doing deltas.
	 */
524
	rename_count = find_exact_renames(options);
525

526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
	/* Did we only want exact renames? */
	if (minimum_score == MAX_SCORE)
		goto cleanup;

	/*
	 * Calculate how many renames are left (but all the source
	 * files still remain as options for rename/copies!)
	 */
	num_create = (rename_dst_nr - rename_count);
	num_src = rename_src_nr;

	/* All done? */
	if (!num_create)
		goto cleanup;

541
	if (too_many_rename_candidates(num_create, options))
542 543
		goto cleanup;

544 545 546 547 548 549
	if (options->show_rename_progress) {
		progress = start_progress_delay(
				"Performing inexact rename detection",
				rename_dst_nr * rename_src_nr, 50, 1);
	}

550
	mx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx));
551 552
	for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
		struct diff_filespec *two = rename_dst[i].two;
553 554
		struct diff_score *m;

555
		if (rename_dst[i].pair)
556
			continue; /* dealt with exact match already. */
557 558 559 560 561

		m = &mx[dst_cnt * NUM_CANDIDATE_PER_DST];
		for (j = 0; j < NUM_CANDIDATE_PER_DST; j++)
			m[j].dst = -1;

562 563
		for (j = 0; j < rename_src_nr; j++) {
			struct diff_filespec *one = rename_src[j].one;
564 565 566 567 568 569 570
			struct diff_score this_src;
			this_src.score = estimate_similarity(one, two,
							     minimum_score);
			this_src.name_score = basename_same(one, two);
			this_src.dst = i;
			this_src.src = j;
			record_if_better(m, &this_src);
571 572 573 574
			/*
			 * Once we run estimate_similarity,
			 * We do not need the text anymore.
			 */
575
			diff_free_filespec_blob(one);
576
			diff_free_filespec_blob(two);
577 578
		}
		dst_cnt++;
579
		display_progress(progress, (i+1)*rename_src_nr);
580
	}
581
	stop_progress(&progress);
582

583
	/* cost matrix sorted by most to least similar pair */
584 585
	qsort(mx, dst_cnt * NUM_CANDIDATE_PER_DST, sizeof(*mx), score_compare);

586 587 588
	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);
589 590
	free(mx);

591
 cleanup:
592
	/* At this point, we have found some renames and copies and they
J
Junio C Hamano 已提交
593
	 * are recorded in rename_dst.  The original list is still in *q.
594
	 */
B
Bo Yang 已提交
595
	DIFF_QUEUE_CLEAR(&outq);
596
	for (i = 0; i < q->nr; i++) {
597 598 599
		struct diff_filepair *p = q->queue[i];
		struct diff_filepair *pair_to_free = NULL;

600 601 602 603 604 605 606 607 608 609
		if (!DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) {
			/*
			 * Creation
			 *
			 * We would output this create record if it has
			 * not been turned into a rename/copy already.
			 */
			struct diff_rename_dst *dst =
				locate_rename_dst(p->two, 0);
			if (dst && dst->pair) {
610 611 612 613
				diff_q(&outq, dst->pair);
				pair_to_free = p;
			}
			else
614 615
				/* no matching rename/copy source, so
				 * record this as a creation.
616 617
				 */
				diff_q(&outq, p);
618
		}
619 620 621 622
		else if (DIFF_FILE_VALID(p->one) && !DIFF_FILE_VALID(p->two)) {
			/*
			 * Deletion
			 *
623 624 625 626
			 * We would output this delete record if:
			 *
			 * (1) this is a broken delete and the counterpart
			 *     broken create remains in the output; or
J
Junio C Hamano 已提交
627 628 629
			 * (2) this is not a broken delete, and rename_dst
			 *     does not have a rename/copy to move p->one->path
			 *     out of existence.
630 631 632 633 634
			 *
			 * Otherwise, the counterpart broken create
			 * has been turned into a rename-edit; or
			 * delete did not have a matching create to
			 * begin with.
635
			 */
636 637 638 639 640 641 642 643 644
			if (DIFF_PAIR_BROKEN(p)) {
				/* broken delete */
				struct diff_rename_dst *dst =
					locate_rename_dst(p->one, 0);
				if (dst && dst->pair)
					/* counterpart is now rename/copy */
					pair_to_free = p;
			}
			else {
645
				if (p->one->rename_used)
646 647 648
					/* this path remains */
					pair_to_free = p;
			}
649 650 651 652 653 654

			if (pair_to_free)
				;
			else
				diff_q(&outq, p);
		}
655
		else if (!diff_unmodified_pair(p))
656
			/* all the usual ones need to be kept */
657
			diff_q(&outq, p);
658 659 660 661
		else
			/* no need to keep unmodified pairs */
			pair_to_free = p;

662 663
		if (pair_to_free)
			diff_free_filepair(pair_to_free);
664
	}
665
	diff_debug_queue("done copying original", &outq);
666

667 668 669
	free(q->queue);
	*q = outq;
	diff_debug_queue("done collapsing", q);
670

671 672
	for (i = 0; i < rename_dst_nr; i++)
		free_filespec(rename_dst[i].two);
J
Junio C Hamano 已提交
673

674 675 676 677 678 679
	free(rename_dst);
	rename_dst = NULL;
	rename_dst_nr = rename_dst_alloc = 0;
	free(rename_src);
	rename_src = NULL;
	rename_src_nr = rename_src_alloc = 0;
680 681
	return;
}