diffcore-rename.c 17.0 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
struct file_similarity {
	int src_dst, index;
	struct diff_filespec *filespec;
	struct file_similarity *next;
};

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

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

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

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

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

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

	/* 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
	 */
336
	ret = (src && dst) ? find_identical_files(src, dst, options) : 0;
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 373 374 375 376

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

377 378 379 380 381 382 383
/*
 * 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.
 */
384
static int find_exact_renames(struct diff_options *options)
385
{
386 387
	int i;
	struct hash_table file_table;
388

389 390 391 392 393 394 395 396
	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 */
397
	i = for_each_hash(&file_table, find_same_files, options);
398 399 400 401 402

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

	return i;
403 404
}

405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
#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;
}

421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
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;
}

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

453
	if (!minimum_score)
454
		minimum_score = DEFAULT_RENAME_SCORE;
455 456

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

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

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

512 513 514 515
	/*
	 * This basically does a test for the rename matrix not
	 * growing larger than a "rename_limit" square matrix, ie:
	 *
516
	 *    num_create * num_src > rename_limit * rename_limit
517 518 519 520 521 522
	 *
	 * 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;
523 524
	if ((num_create > rename_limit && num_src > rename_limit) ||
	    (num_create * num_src > rename_limit * rename_limit)) {
525
		if (options->warn_on_too_large_rename)
526
			warning("too many files (created: %d deleted: %d), skipping inexact rename detection", num_create, num_src);
527
		goto cleanup;
528
	}
529

530
	mx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx));
531 532
	for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
		struct diff_filespec *two = rename_dst[i].two;
533 534
		struct diff_score *m;

535
		if (rename_dst[i].pair)
536
			continue; /* dealt with exact match already. */
537 538 539 540 541

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

542 543
		for (j = 0; j < rename_src_nr; j++) {
			struct diff_filespec *one = rename_src[j].one;
544 545 546 547 548 549 550
			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);
551 552 553 554
			/*
			 * Once we run estimate_similarity,
			 * We do not need the text anymore.
			 */
555
			diff_free_filespec_blob(one);
556
			diff_free_filespec_blob(two);
557 558 559
		}
		dst_cnt++;
	}
560

561
	/* cost matrix sorted by most to least similar pair */
562 563
	qsort(mx, dst_cnt * NUM_CANDIDATE_PER_DST, sizeof(*mx), score_compare);

564 565 566
	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);
567 568
	free(mx);

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

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

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

640 641
		if (pair_to_free)
			diff_free_filepair(pair_to_free);
642
	}
643
	diff_debug_queue("done copying original", &outq);
644

645 646 647
	free(q->queue);
	*q = outq;
	diff_debug_queue("done collapsing", q);
648

649 650
	for (i = 0; i < rename_dst_nr; i++)
		free_filespec(rename_dst[i].two);
J
Junio C Hamano 已提交
651

652 653 654 655 656 657
	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;
658 659
	return;
}