diffcore-rename.c 16.8 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

9 10 11 12 13 14 15
/* 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;
16

17 18
static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
						 int insert_ok)
19
{
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
	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 已提交
49 50
	rename_dst[first].two = alloc_filespec(two->path);
	fill_filespec(rename_dst[first].two, two->sha1, two->mode);
51 52
	rename_dst[first].pair = NULL;
	return &(rename_dst[first]);
53 54
}

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

62
static struct diff_rename_src *register_rename_src(struct diff_filespec *one,
63
						   unsigned short score)
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
{
	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;
	}
81

82 83 84 85 86
	/* 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));
87
	}
88 89 90 91 92
	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;
93
	rename_src[first].score = score;
94
	return &(rename_src[first]);
95 96
}

97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
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] == '/');
}

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

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
130 131 132 133 134
	 * 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.
135
	 */
L
Linus Torvalds 已提交
136
	unsigned long max_size, delta_size, base_size, src_copied, literal_added;
137
	unsigned long delta_limit;
138 139
	int score;

140 141 142 143 144 145 146
	/* 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;

147 148 149 150 151 152 153 154 155
	/*
	 * 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!)
	 */
156
	if (!src->cnt_data && diff_populate_filespec(src, 1))
157
		return 0;
158
	if (!dst->cnt_data && diff_populate_filespec(dst, 1))
159 160
		return 0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
struct file_similarity {
	int src_dst, index;
	struct diff_filespec *filespec;
	struct file_similarity *next;
};

static int find_identical_files(struct file_similarity *src,
				struct file_similarity *dst)
{
	int renames = 0;

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

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

M
Mike Ralphson 已提交
270
			/* False hash collision? */
271
			if (hashcmp(source->sha1, target->sha1))
272 273
				continue;
			/* Non-regular files? If so, the modes must match! */
274 275
			if (!S_ISREG(source->mode) || !S_ISREG(target->mode)) {
				if (source->mode != target->mode)
276 277
					continue;
			}
278 279 280 281 282 283 284 285 286
			/* Give higher scores to sources that haven't been used already */
			score = !source->rename_used;
			score += basename_same(source, target);
			if (score > best_score) {
				best = p;
				best_score = score;
				if (score == 2)
					break;
			}
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 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

			/* 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);
	}
}

static int find_same_files(void *ptr)
{
	int ret;
	struct file_similarity *p = ptr;
	struct file_similarity *src = NULL, *dst = NULL;

	/* 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
	 */
	ret = (src && dst) ? find_identical_files(src, dst) : 0;

	/* 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;
	}
}

373 374 375 376 377 378 379 380 381
/*
 * 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.
 */
static int find_exact_renames(void)
{
382 383
	int i;
	struct hash_table file_table;
384

385 386 387 388 389 390 391 392 393 394 395 396 397 398
	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 */
	i = for_each_hash(&file_table, find_same_files);

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

	return i;
399 400
}

401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
#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;
}

417
void diffcore_rename(struct diff_options *options)
418
{
419 420 421
	int detect_rename = options->detect_rename;
	int minimum_score = options->rename_score;
	int rename_limit = options->rename_limit;
422
	struct diff_queue_struct *q = &diff_queued_diff;
J
Junio C Hamano 已提交
423
	struct diff_queue_struct outq;
424
	struct diff_score *mx;
425
	int i, j, rename_count;
426
	int num_create, num_src, dst_cnt;
427

428
	if (!minimum_score)
429
		minimum_score = DEFAULT_RENAME_SCORE;
430 431

	for (i = 0; i < q->nr; i++) {
432
		struct diff_filepair *p = q->queue[i];
433
		if (!DIFF_FILE_VALID(p->one)) {
434
			if (!DIFF_FILE_VALID(p->two))
435
				continue; /* unmerged */
436 437 438
			else if (options->single_follow &&
				 strcmp(options->single_follow, p->two->path))
				continue; /* not interested */
439
			else
440
				locate_rename_dst(p->two, 1);
441
		}
442
		else if (!DIFF_FILE_VALID(p->two)) {
443 444
			/*
			 * If the source is a broken "delete", and
445 446
			 * they did not really want to get broken,
			 * that means the source actually stays.
447 448 449 450 451 452 453 454 455 456 457
			 * 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.
458
			 */
459 460
			p->one->rename_used++;
			register_rename_src(p->one, p->score);
461
		}
462
	}
463
	if (rename_dst_nr == 0 || rename_src_nr == 0)
464 465
		goto cleanup; /* nothing to do */

466 467 468 469 470 471
	/*
	 * We really want to cull the candidates list early
	 * with cheap tests in order to avoid doing deltas.
	 */
	rename_count = find_exact_renames();

472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
	/* 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;

487 488 489 490
	/*
	 * This basically does a test for the rename matrix not
	 * growing larger than a "rename_limit" square matrix, ie:
	 *
491
	 *    num_create * num_src > rename_limit * rename_limit
492 493 494 495 496 497
	 *
	 * 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;
498 499
	if ((num_create > rename_limit && num_src > rename_limit) ||
	    (num_create * num_src > rename_limit * rename_limit)) {
500
		if (options->warn_on_too_large_rename)
501
			warning("too many files (created: %d deleted: %d), skipping inexact rename detection", num_create, num_src);
502
		goto cleanup;
503
	}
504

505
	mx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx));
506 507
	for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
		struct diff_filespec *two = rename_dst[i].two;
508 509
		struct diff_score *m;

510
		if (rename_dst[i].pair)
511
			continue; /* dealt with exact match already. */
512 513 514 515 516

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

517 518
		for (j = 0; j < rename_src_nr; j++) {
			struct diff_filespec *one = rename_src[j].one;
519 520 521 522 523 524 525
			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);
526
			diff_free_filespec_blob(one);
527
		}
528
		/* We do not need the text anymore */
529
		diff_free_filespec_blob(two);
530 531
		dst_cnt++;
	}
532

533
	/* cost matrix sorted by most to least similar pair */
534 535 536 537 538 539 540 541 542
	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];
543 544
		if (dst->pair)
			continue; /* already done, either exact or fuzzy. */
545
		if (rename_src[mx[i].src].one->rename_used)
546 547 548 549
			continue;
		record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
		rename_count++;
	}
550 551 552 553 554 555 556 557

	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];
558 559
		if (dst->pair)
			continue; /* already done, either exact or fuzzy. */
J
Junio C Hamano 已提交
560 561
		record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
		rename_count++;
562 563 564
	}
	free(mx);

565
 cleanup:
566
	/* At this point, we have found some renames and copies and they
J
Junio C Hamano 已提交
567
	 * are recorded in rename_dst.  The original list is still in *q.
568
	 */
569 570
	outq.queue = NULL;
	outq.nr = outq.alloc = 0;
571
	for (i = 0; i < q->nr; i++) {
572 573 574
		struct diff_filepair *p = q->queue[i];
		struct diff_filepair *pair_to_free = NULL;

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

			if (pair_to_free)
				;
			else
				diff_q(&outq, p);
		}
630
		else if (!diff_unmodified_pair(p))
631
			/* all the usual ones need to be kept */
632
			diff_q(&outq, p);
633 634 635 636
		else
			/* no need to keep unmodified pairs */
			pair_to_free = p;

637 638
		if (pair_to_free)
			diff_free_filepair(pair_to_free);
639
	}
640
	diff_debug_queue("done copying original", &outq);
641

642 643 644
	free(q->queue);
	*q = outq;
	diff_debug_queue("done collapsing", q);
645

646 647
	for (i = 0; i < rename_dst_nr; i++)
		free_filespec(rename_dst[i].two);
J
Junio C Hamano 已提交
648

649 650 651 652 653 654
	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;
655 656
	return;
}