diffcore-rename.c 17.2 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
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;
}

443
void diffcore_rename(struct diff_options *options)
444
{
445 446 447
	int detect_rename = options->detect_rename;
	int minimum_score = options->rename_score;
	int rename_limit = options->rename_limit;
448
	struct diff_queue_struct *q = &diff_queued_diff;
J
Junio C Hamano 已提交
449
	struct diff_queue_struct outq;
450
	struct diff_score *mx;
451
	int i, j, rename_count;
452
	int num_create, num_src, dst_cnt;
453
	struct progress *progress = NULL;
454

455
	if (!minimum_score)
456
		minimum_score = DEFAULT_RENAME_SCORE;
457 458

	for (i = 0; i < q->nr; i++) {
459
		struct diff_filepair *p = q->queue[i];
460
		if (!DIFF_FILE_VALID(p->one)) {
461
			if (!DIFF_FILE_VALID(p->two))
462
				continue; /* unmerged */
463 464 465
			else if (options->single_follow &&
				 strcmp(options->single_follow, p->two->path))
				continue; /* not interested */
466
			else
467
				locate_rename_dst(p->two, 1);
468
		}
469
		else if (!DIFF_FILE_VALID(p->two)) {
470 471
			/*
			 * If the source is a broken "delete", and
472 473
			 * they did not really want to get broken,
			 * that means the source actually stays.
474 475 476 477 478 479 480 481 482 483 484
			 * 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.
485
			 */
486 487
			p->one->rename_used++;
			register_rename_src(p->one, p->score);
488
		}
489
	}
490
	if (rename_dst_nr == 0 || rename_src_nr == 0)
491 492
		goto cleanup; /* nothing to do */

493 494 495 496
	/*
	 * We really want to cull the candidates list early
	 * with cheap tests in order to avoid doing deltas.
	 */
497
	rename_count = find_exact_renames(options);
498

499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
	/* 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;

514 515 516 517
	/*
	 * This basically does a test for the rename matrix not
	 * growing larger than a "rename_limit" square matrix, ie:
	 *
518
	 *    num_create * num_src > rename_limit * rename_limit
519 520 521 522
	 *
	 * but handles the potential overflow case specially (and we
	 * assume at least 32-bit integers)
	 */
523
	options->needed_rename_limit = 0;
524 525
	if (rename_limit <= 0 || rename_limit > 32767)
		rename_limit = 32767;
526 527
	if ((num_create > rename_limit && num_src > rename_limit) ||
	    (num_create * num_src > rename_limit * rename_limit)) {
528 529
		options->needed_rename_limit =
			num_src > num_create ? num_src : num_create;
530
		goto cleanup;
531
	}
532

533 534 535 536 537 538
	if (options->show_rename_progress) {
		progress = start_progress_delay(
				"Performing inexact rename detection",
				rename_dst_nr * rename_src_nr, 50, 1);
	}

539
	mx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx));
540 541
	for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
		struct diff_filespec *two = rename_dst[i].two;
542 543
		struct diff_score *m;

544
		if (rename_dst[i].pair)
545
			continue; /* dealt with exact match already. */
546 547 548 549 550

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

551 552
		for (j = 0; j < rename_src_nr; j++) {
			struct diff_filespec *one = rename_src[j].one;
553 554 555 556 557 558 559
			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);
560 561 562 563
			/*
			 * Once we run estimate_similarity,
			 * We do not need the text anymore.
			 */
564
			diff_free_filespec_blob(one);
565
			diff_free_filespec_blob(two);
566 567
		}
		dst_cnt++;
568
		display_progress(progress, (i+1)*rename_src_nr);
569
	}
570
	stop_progress(&progress);
571

572
	/* cost matrix sorted by most to least similar pair */
573 574
	qsort(mx, dst_cnt * NUM_CANDIDATE_PER_DST, sizeof(*mx), score_compare);

575 576 577
	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);
578 579
	free(mx);

580
 cleanup:
581
	/* At this point, we have found some renames and copies and they
J
Junio C Hamano 已提交
582
	 * are recorded in rename_dst.  The original list is still in *q.
583
	 */
B
Bo Yang 已提交
584
	DIFF_QUEUE_CLEAR(&outq);
585
	for (i = 0; i < q->nr; i++) {
586 587 588
		struct diff_filepair *p = q->queue[i];
		struct diff_filepair *pair_to_free = NULL;

589 590 591 592 593 594 595 596 597 598
		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) {
599 600 601 602
				diff_q(&outq, dst->pair);
				pair_to_free = p;
			}
			else
603 604
				/* no matching rename/copy source, so
				 * record this as a creation.
605 606
				 */
				diff_q(&outq, p);
607
		}
608 609 610 611
		else if (DIFF_FILE_VALID(p->one) && !DIFF_FILE_VALID(p->two)) {
			/*
			 * Deletion
			 *
612 613 614 615
			 * 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 已提交
616 617 618
			 * (2) this is not a broken delete, and rename_dst
			 *     does not have a rename/copy to move p->one->path
			 *     out of existence.
619 620 621 622 623
			 *
			 * Otherwise, the counterpart broken create
			 * has been turned into a rename-edit; or
			 * delete did not have a matching create to
			 * begin with.
624
			 */
625 626 627 628 629 630 631 632 633
			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 {
634
				if (p->one->rename_used)
635 636 637
					/* this path remains */
					pair_to_free = p;
			}
638 639 640 641 642 643

			if (pair_to_free)
				;
			else
				diff_q(&outq, p);
		}
644
		else if (!diff_unmodified_pair(p))
645
			/* all the usual ones need to be kept */
646
			diff_q(&outq, p);
647 648 649 650
		else
			/* no need to keep unmodified pairs */
			pair_to_free = p;

651 652
		if (pair_to_free)
			diff_free_filepair(pair_to_free);
653
	}
654
	diff_debug_queue("done copying original", &outq);
655

656 657 658
	free(q->queue);
	*q = outq;
	diff_debug_queue("done collapsing", q);
659

660 661
	for (i = 0; i < rename_dst_nr; i++)
		free_filespec(rename_dst[i].two);
J
Junio C Hamano 已提交
662

663 664 665 666 667 668
	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;
669 670
	return;
}