diffcore-rename.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. /*
  2. *
  3. * Copyright (C) 2005 Junio C Hamano
  4. */
  5. #include "cache.h"
  6. #include "diff.h"
  7. #include "diffcore.h"
  8. #include "object-store.h"
  9. #include "hashmap.h"
  10. #include "progress.h"
  11. #include "promisor-remote.h"
  12. /* Table of rename/copy destinations */
  13. static struct diff_rename_dst {
  14. struct diff_filespec *two;
  15. struct diff_filepair *pair;
  16. } *rename_dst;
  17. static int rename_dst_nr, rename_dst_alloc;
  18. static int find_rename_dst(struct diff_filespec *two)
  19. {
  20. int first, last;
  21. first = 0;
  22. last = rename_dst_nr;
  23. while (last > first) {
  24. int next = first + ((last - first) >> 1);
  25. struct diff_rename_dst *dst = &(rename_dst[next]);
  26. int cmp = strcmp(two->path, dst->two->path);
  27. if (!cmp)
  28. return next;
  29. if (cmp < 0) {
  30. last = next;
  31. continue;
  32. }
  33. first = next+1;
  34. }
  35. return -first - 1;
  36. }
  37. static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two)
  38. {
  39. int ofs = find_rename_dst(two);
  40. return ofs < 0 ? NULL : &rename_dst[ofs];
  41. }
  42. /*
  43. * Returns 0 on success, -1 if we found a duplicate.
  44. */
  45. static int add_rename_dst(struct diff_filespec *two)
  46. {
  47. int first = find_rename_dst(two);
  48. if (first >= 0)
  49. return -1;
  50. first = -first - 1;
  51. /* insert to make it at "first" */
  52. ALLOC_GROW(rename_dst, rename_dst_nr + 1, rename_dst_alloc);
  53. rename_dst_nr++;
  54. if (first < rename_dst_nr)
  55. MOVE_ARRAY(rename_dst + first + 1, rename_dst + first,
  56. rename_dst_nr - first - 1);
  57. rename_dst[first].two = alloc_filespec(two->path);
  58. fill_filespec(rename_dst[first].two, &two->oid, two->oid_valid,
  59. two->mode);
  60. rename_dst[first].pair = NULL;
  61. return 0;
  62. }
  63. /* Table of rename/copy src files */
  64. static struct diff_rename_src {
  65. struct diff_filepair *p;
  66. unsigned short score; /* to remember the break score */
  67. } *rename_src;
  68. static int rename_src_nr, rename_src_alloc;
  69. static struct diff_rename_src *register_rename_src(struct diff_filepair *p)
  70. {
  71. int first, last;
  72. struct diff_filespec *one = p->one;
  73. unsigned short score = p->score;
  74. first = 0;
  75. last = rename_src_nr;
  76. while (last > first) {
  77. int next = first + ((last - first) >> 1);
  78. struct diff_rename_src *src = &(rename_src[next]);
  79. int cmp = strcmp(one->path, src->p->one->path);
  80. if (!cmp)
  81. return src;
  82. if (cmp < 0) {
  83. last = next;
  84. continue;
  85. }
  86. first = next+1;
  87. }
  88. /* insert to make it at "first" */
  89. ALLOC_GROW(rename_src, rename_src_nr + 1, rename_src_alloc);
  90. rename_src_nr++;
  91. if (first < rename_src_nr)
  92. MOVE_ARRAY(rename_src + first + 1, rename_src + first,
  93. rename_src_nr - first - 1);
  94. rename_src[first].p = p;
  95. rename_src[first].score = score;
  96. return &(rename_src[first]);
  97. }
  98. static int basename_same(struct diff_filespec *src, struct diff_filespec *dst)
  99. {
  100. int src_len = strlen(src->path), dst_len = strlen(dst->path);
  101. while (src_len && dst_len) {
  102. char c1 = src->path[--src_len];
  103. char c2 = dst->path[--dst_len];
  104. if (c1 != c2)
  105. return 0;
  106. if (c1 == '/')
  107. return 1;
  108. }
  109. return (!src_len || src->path[src_len - 1] == '/') &&
  110. (!dst_len || dst->path[dst_len - 1] == '/');
  111. }
  112. struct diff_score {
  113. int src; /* index in rename_src */
  114. int dst; /* index in rename_dst */
  115. unsigned short score;
  116. short name_score;
  117. };
  118. struct prefetch_options {
  119. struct repository *repo;
  120. int skip_unmodified;
  121. };
  122. static void prefetch(void *prefetch_options)
  123. {
  124. struct prefetch_options *options = prefetch_options;
  125. int i;
  126. struct oid_array to_fetch = OID_ARRAY_INIT;
  127. for (i = 0; i < rename_dst_nr; i++) {
  128. if (rename_dst[i].pair)
  129. /*
  130. * The loop in diffcore_rename() will not need these
  131. * blobs, so skip prefetching.
  132. */
  133. continue; /* already found exact match */
  134. diff_add_if_missing(options->repo, &to_fetch,
  135. rename_dst[i].two);
  136. }
  137. for (i = 0; i < rename_src_nr; i++) {
  138. if (options->skip_unmodified &&
  139. diff_unmodified_pair(rename_src[i].p))
  140. /*
  141. * The loop in diffcore_rename() will not need these
  142. * blobs, so skip prefetching.
  143. */
  144. continue;
  145. diff_add_if_missing(options->repo, &to_fetch,
  146. rename_src[i].p->one);
  147. }
  148. promisor_remote_get_direct(options->repo, to_fetch.oid, to_fetch.nr);
  149. oid_array_clear(&to_fetch);
  150. }
  151. static int estimate_similarity(struct repository *r,
  152. struct diff_filespec *src,
  153. struct diff_filespec *dst,
  154. int minimum_score,
  155. int skip_unmodified)
  156. {
  157. /* src points at a file that existed in the original tree (or
  158. * optionally a file in the destination tree) and dst points
  159. * at a newly created file. They may be quite similar, in which
  160. * case we want to say src is renamed to dst or src is copied into
  161. * dst, and then some edit has been applied to dst.
  162. *
  163. * Compare them and return how similar they are, representing
  164. * the score as an integer between 0 and MAX_SCORE.
  165. *
  166. * When there is an exact match, it is considered a better
  167. * match than anything else; the destination does not even
  168. * call into this function in that case.
  169. */
  170. unsigned long max_size, delta_size, base_size, src_copied, literal_added;
  171. int score;
  172. struct diff_populate_filespec_options dpf_options = {
  173. .check_size_only = 1
  174. };
  175. struct prefetch_options prefetch_options = {r, skip_unmodified};
  176. if (r == the_repository && has_promisor_remote()) {
  177. dpf_options.missing_object_cb = prefetch;
  178. dpf_options.missing_object_data = &prefetch_options;
  179. }
  180. /* We deal only with regular files. Symlink renames are handled
  181. * only when they are exact matches --- in other words, no edits
  182. * after renaming.
  183. */
  184. if (!S_ISREG(src->mode) || !S_ISREG(dst->mode))
  185. return 0;
  186. /*
  187. * Need to check that source and destination sizes are
  188. * filled in before comparing them.
  189. *
  190. * If we already have "cnt_data" filled in, we know it's
  191. * all good (avoid checking the size for zero, as that
  192. * is a possible size - we really should have a flag to
  193. * say whether the size is valid or not!)
  194. */
  195. if (!src->cnt_data &&
  196. diff_populate_filespec(r, src, &dpf_options))
  197. return 0;
  198. if (!dst->cnt_data &&
  199. diff_populate_filespec(r, dst, &dpf_options))
  200. return 0;
  201. max_size = ((src->size > dst->size) ? src->size : dst->size);
  202. base_size = ((src->size < dst->size) ? src->size : dst->size);
  203. delta_size = max_size - base_size;
  204. /* We would not consider edits that change the file size so
  205. * drastically. delta_size must be smaller than
  206. * (MAX_SCORE-minimum_score)/MAX_SCORE * min(src->size, dst->size).
  207. *
  208. * Note that base_size == 0 case is handled here already
  209. * and the final score computation below would not have a
  210. * divide-by-zero issue.
  211. */
  212. if (max_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE)
  213. return 0;
  214. dpf_options.check_size_only = 0;
  215. if (!src->cnt_data && diff_populate_filespec(r, src, &dpf_options))
  216. return 0;
  217. if (!dst->cnt_data && diff_populate_filespec(r, dst, &dpf_options))
  218. return 0;
  219. if (diffcore_count_changes(r, src, dst,
  220. &src->cnt_data, &dst->cnt_data,
  221. &src_copied, &literal_added))
  222. return 0;
  223. /* How similar are they?
  224. * what percentage of material in dst are from source?
  225. */
  226. if (!dst->size)
  227. score = 0; /* should not happen */
  228. else
  229. score = (int)(src_copied * MAX_SCORE / max_size);
  230. return score;
  231. }
  232. static void record_rename_pair(int dst_index, int src_index, int score)
  233. {
  234. struct diff_filespec *src, *dst;
  235. struct diff_filepair *dp;
  236. if (rename_dst[dst_index].pair)
  237. die("internal error: dst already matched.");
  238. src = rename_src[src_index].p->one;
  239. src->rename_used++;
  240. src->count++;
  241. dst = rename_dst[dst_index].two;
  242. dst->count++;
  243. dp = diff_queue(NULL, src, dst);
  244. dp->renamed_pair = 1;
  245. if (!strcmp(src->path, dst->path))
  246. dp->score = rename_src[src_index].score;
  247. else
  248. dp->score = score;
  249. rename_dst[dst_index].pair = dp;
  250. }
  251. /*
  252. * We sort the rename similarity matrix with the score, in descending
  253. * order (the most similar first).
  254. */
  255. static int score_compare(const void *a_, const void *b_)
  256. {
  257. const struct diff_score *a = a_, *b = b_;
  258. /* sink the unused ones to the bottom */
  259. if (a->dst < 0)
  260. return (0 <= b->dst);
  261. else if (b->dst < 0)
  262. return -1;
  263. if (a->score == b->score)
  264. return b->name_score - a->name_score;
  265. return b->score - a->score;
  266. }
  267. struct file_similarity {
  268. struct hashmap_entry entry;
  269. int index;
  270. struct diff_filespec *filespec;
  271. };
  272. static unsigned int hash_filespec(struct repository *r,
  273. struct diff_filespec *filespec)
  274. {
  275. if (!filespec->oid_valid) {
  276. if (diff_populate_filespec(r, filespec, NULL))
  277. return 0;
  278. hash_object_file(r->hash_algo, filespec->data, filespec->size,
  279. "blob", &filespec->oid);
  280. }
  281. return oidhash(&filespec->oid);
  282. }
  283. static int find_identical_files(struct hashmap *srcs,
  284. int dst_index,
  285. struct diff_options *options)
  286. {
  287. int renames = 0;
  288. struct diff_filespec *target = rename_dst[dst_index].two;
  289. struct file_similarity *p, *best = NULL;
  290. int i = 100, best_score = -1;
  291. unsigned int hash = hash_filespec(options->repo, target);
  292. /*
  293. * Find the best source match for specified destination.
  294. */
  295. p = hashmap_get_entry_from_hash(srcs, hash, NULL,
  296. struct file_similarity, entry);
  297. hashmap_for_each_entry_from(srcs, p, entry) {
  298. int score;
  299. struct diff_filespec *source = p->filespec;
  300. /* False hash collision? */
  301. if (!oideq(&source->oid, &target->oid))
  302. continue;
  303. /* Non-regular files? If so, the modes must match! */
  304. if (!S_ISREG(source->mode) || !S_ISREG(target->mode)) {
  305. if (source->mode != target->mode)
  306. continue;
  307. }
  308. /* Give higher scores to sources that haven't been used already */
  309. score = !source->rename_used;
  310. if (source->rename_used && options->detect_rename != DIFF_DETECT_COPY)
  311. continue;
  312. score += basename_same(source, target);
  313. if (score > best_score) {
  314. best = p;
  315. best_score = score;
  316. if (score == 2)
  317. break;
  318. }
  319. /* Too many identical alternatives? Pick one */
  320. if (!--i)
  321. break;
  322. }
  323. if (best) {
  324. record_rename_pair(dst_index, best->index, MAX_SCORE);
  325. renames++;
  326. }
  327. return renames;
  328. }
  329. static void insert_file_table(struct repository *r,
  330. struct hashmap *table, int index,
  331. struct diff_filespec *filespec)
  332. {
  333. struct file_similarity *entry = xmalloc(sizeof(*entry));
  334. entry->index = index;
  335. entry->filespec = filespec;
  336. hashmap_entry_init(&entry->entry, hash_filespec(r, filespec));
  337. hashmap_add(table, &entry->entry);
  338. }
  339. /*
  340. * Find exact renames first.
  341. *
  342. * The first round matches up the up-to-date entries,
  343. * and then during the second round we try to match
  344. * cache-dirty entries as well.
  345. */
  346. static int find_exact_renames(struct diff_options *options)
  347. {
  348. int i, renames = 0;
  349. struct hashmap file_table;
  350. /* Add all sources to the hash table in reverse order, because
  351. * later on they will be retrieved in LIFO order.
  352. */
  353. hashmap_init(&file_table, NULL, NULL, rename_src_nr);
  354. for (i = rename_src_nr-1; i >= 0; i--)
  355. insert_file_table(options->repo,
  356. &file_table, i,
  357. rename_src[i].p->one);
  358. /* Walk the destinations and find best source match */
  359. for (i = 0; i < rename_dst_nr; i++)
  360. renames += find_identical_files(&file_table, i, options);
  361. /* Free the hash data structure and entries */
  362. hashmap_free_entries(&file_table, struct file_similarity, entry);
  363. return renames;
  364. }
  365. #define NUM_CANDIDATE_PER_DST 4
  366. static void record_if_better(struct diff_score m[], struct diff_score *o)
  367. {
  368. int i, worst;
  369. /* find the worst one */
  370. worst = 0;
  371. for (i = 1; i < NUM_CANDIDATE_PER_DST; i++)
  372. if (score_compare(&m[i], &m[worst]) > 0)
  373. worst = i;
  374. /* is it better than the worst one? */
  375. if (score_compare(&m[worst], o) > 0)
  376. m[worst] = *o;
  377. }
  378. /*
  379. * Returns:
  380. * 0 if we are under the limit;
  381. * 1 if we need to disable inexact rename detection;
  382. * 2 if we would be under the limit if we were given -C instead of -C -C.
  383. */
  384. static int too_many_rename_candidates(int num_create,
  385. struct diff_options *options)
  386. {
  387. int rename_limit = options->rename_limit;
  388. int num_src = rename_src_nr;
  389. int i;
  390. options->needed_rename_limit = 0;
  391. /*
  392. * This basically does a test for the rename matrix not
  393. * growing larger than a "rename_limit" square matrix, ie:
  394. *
  395. * num_create * num_src > rename_limit * rename_limit
  396. */
  397. if (rename_limit <= 0)
  398. rename_limit = 32767;
  399. if ((num_create <= rename_limit || num_src <= rename_limit) &&
  400. ((uint64_t)num_create * (uint64_t)num_src
  401. <= (uint64_t)rename_limit * (uint64_t)rename_limit))
  402. return 0;
  403. options->needed_rename_limit =
  404. num_src > num_create ? num_src : num_create;
  405. /* Are we running under -C -C? */
  406. if (!options->flags.find_copies_harder)
  407. return 1;
  408. /* Would we bust the limit if we were running under -C? */
  409. for (num_src = i = 0; i < rename_src_nr; i++) {
  410. if (diff_unmodified_pair(rename_src[i].p))
  411. continue;
  412. num_src++;
  413. }
  414. if ((num_create <= rename_limit || num_src <= rename_limit) &&
  415. ((uint64_t)num_create * (uint64_t)num_src
  416. <= (uint64_t)rename_limit * (uint64_t)rename_limit))
  417. return 2;
  418. return 1;
  419. }
  420. static int find_renames(struct diff_score *mx, int dst_cnt, int minimum_score, int copies)
  421. {
  422. int count = 0, i;
  423. for (i = 0; i < dst_cnt * NUM_CANDIDATE_PER_DST; i++) {
  424. struct diff_rename_dst *dst;
  425. if ((mx[i].dst < 0) ||
  426. (mx[i].score < minimum_score))
  427. break; /* there is no more usable pair. */
  428. dst = &rename_dst[mx[i].dst];
  429. if (dst->pair)
  430. continue; /* already done, either exact or fuzzy. */
  431. if (!copies && rename_src[mx[i].src].p->one->rename_used)
  432. continue;
  433. record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
  434. count++;
  435. }
  436. return count;
  437. }
  438. void diffcore_rename(struct diff_options *options)
  439. {
  440. int detect_rename = options->detect_rename;
  441. int minimum_score = options->rename_score;
  442. struct diff_queue_struct *q = &diff_queued_diff;
  443. struct diff_queue_struct outq;
  444. struct diff_score *mx;
  445. int i, j, rename_count, skip_unmodified = 0;
  446. int num_create, dst_cnt;
  447. struct progress *progress = NULL;
  448. if (!minimum_score)
  449. minimum_score = DEFAULT_RENAME_SCORE;
  450. for (i = 0; i < q->nr; i++) {
  451. struct diff_filepair *p = q->queue[i];
  452. if (!DIFF_FILE_VALID(p->one)) {
  453. if (!DIFF_FILE_VALID(p->two))
  454. continue; /* unmerged */
  455. else if (options->single_follow &&
  456. strcmp(options->single_follow, p->two->path))
  457. continue; /* not interested */
  458. else if (!options->flags.rename_empty &&
  459. is_empty_blob_oid(&p->two->oid))
  460. continue;
  461. else if (add_rename_dst(p->two) < 0) {
  462. warning("skipping rename detection, detected"
  463. " duplicate destination '%s'",
  464. p->two->path);
  465. goto cleanup;
  466. }
  467. }
  468. else if (!options->flags.rename_empty &&
  469. is_empty_blob_oid(&p->one->oid))
  470. continue;
  471. else if (!DIFF_PAIR_UNMERGED(p) && !DIFF_FILE_VALID(p->two)) {
  472. /*
  473. * If the source is a broken "delete", and
  474. * they did not really want to get broken,
  475. * that means the source actually stays.
  476. * So we increment the "rename_used" score
  477. * by one, to indicate ourselves as a user
  478. */
  479. if (p->broken_pair && !p->score)
  480. p->one->rename_used++;
  481. register_rename_src(p);
  482. }
  483. else if (detect_rename == DIFF_DETECT_COPY) {
  484. /*
  485. * Increment the "rename_used" score by
  486. * one, to indicate ourselves as a user.
  487. */
  488. p->one->rename_used++;
  489. register_rename_src(p);
  490. }
  491. }
  492. if (rename_dst_nr == 0 || rename_src_nr == 0)
  493. goto cleanup; /* nothing to do */
  494. /*
  495. * We really want to cull the candidates list early
  496. * with cheap tests in order to avoid doing deltas.
  497. */
  498. rename_count = find_exact_renames(options);
  499. /* Did we only want exact renames? */
  500. if (minimum_score == MAX_SCORE)
  501. goto cleanup;
  502. /*
  503. * Calculate how many renames are left (but all the source
  504. * files still remain as options for rename/copies!)
  505. */
  506. num_create = (rename_dst_nr - rename_count);
  507. /* All done? */
  508. if (!num_create)
  509. goto cleanup;
  510. switch (too_many_rename_candidates(num_create, options)) {
  511. case 1:
  512. goto cleanup;
  513. case 2:
  514. options->degraded_cc_to_c = 1;
  515. skip_unmodified = 1;
  516. break;
  517. default:
  518. break;
  519. }
  520. if (options->show_rename_progress) {
  521. progress = start_delayed_progress(
  522. _("Performing inexact rename detection"),
  523. (uint64_t)rename_dst_nr * (uint64_t)rename_src_nr);
  524. }
  525. mx = xcalloc(st_mult(NUM_CANDIDATE_PER_DST, num_create), sizeof(*mx));
  526. for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
  527. struct diff_filespec *two = rename_dst[i].two;
  528. struct diff_score *m;
  529. if (rename_dst[i].pair)
  530. continue; /* dealt with exact match already. */
  531. m = &mx[dst_cnt * NUM_CANDIDATE_PER_DST];
  532. for (j = 0; j < NUM_CANDIDATE_PER_DST; j++)
  533. m[j].dst = -1;
  534. for (j = 0; j < rename_src_nr; j++) {
  535. struct diff_filespec *one = rename_src[j].p->one;
  536. struct diff_score this_src;
  537. if (skip_unmodified &&
  538. diff_unmodified_pair(rename_src[j].p))
  539. continue;
  540. this_src.score = estimate_similarity(options->repo,
  541. one, two,
  542. minimum_score,
  543. skip_unmodified);
  544. this_src.name_score = basename_same(one, two);
  545. this_src.dst = i;
  546. this_src.src = j;
  547. record_if_better(m, &this_src);
  548. /*
  549. * Once we run estimate_similarity,
  550. * We do not need the text anymore.
  551. */
  552. diff_free_filespec_blob(one);
  553. diff_free_filespec_blob(two);
  554. }
  555. dst_cnt++;
  556. display_progress(progress, (uint64_t)(i+1)*(uint64_t)rename_src_nr);
  557. }
  558. stop_progress(&progress);
  559. /* cost matrix sorted by most to least similar pair */
  560. STABLE_QSORT(mx, dst_cnt * NUM_CANDIDATE_PER_DST, score_compare);
  561. rename_count += find_renames(mx, dst_cnt, minimum_score, 0);
  562. if (detect_rename == DIFF_DETECT_COPY)
  563. rename_count += find_renames(mx, dst_cnt, minimum_score, 1);
  564. free(mx);
  565. cleanup:
  566. /* At this point, we have found some renames and copies and they
  567. * are recorded in rename_dst. The original list is still in *q.
  568. */
  569. DIFF_QUEUE_CLEAR(&outq);
  570. for (i = 0; i < q->nr; i++) {
  571. struct diff_filepair *p = q->queue[i];
  572. struct diff_filepair *pair_to_free = NULL;
  573. if (DIFF_PAIR_UNMERGED(p)) {
  574. diff_q(&outq, p);
  575. }
  576. else if (!DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) {
  577. /*
  578. * Creation
  579. *
  580. * We would output this create record if it has
  581. * not been turned into a rename/copy already.
  582. */
  583. struct diff_rename_dst *dst = locate_rename_dst(p->two);
  584. if (dst && dst->pair) {
  585. diff_q(&outq, dst->pair);
  586. pair_to_free = p;
  587. }
  588. else
  589. /* no matching rename/copy source, so
  590. * record this as a creation.
  591. */
  592. diff_q(&outq, p);
  593. }
  594. else if (DIFF_FILE_VALID(p->one) && !DIFF_FILE_VALID(p->two)) {
  595. /*
  596. * Deletion
  597. *
  598. * We would output this delete record if:
  599. *
  600. * (1) this is a broken delete and the counterpart
  601. * broken create remains in the output; or
  602. * (2) this is not a broken delete, and rename_dst
  603. * does not have a rename/copy to move p->one->path
  604. * out of existence.
  605. *
  606. * Otherwise, the counterpart broken create
  607. * has been turned into a rename-edit; or
  608. * delete did not have a matching create to
  609. * begin with.
  610. */
  611. if (DIFF_PAIR_BROKEN(p)) {
  612. /* broken delete */
  613. struct diff_rename_dst *dst = locate_rename_dst(p->one);
  614. if (dst && dst->pair)
  615. /* counterpart is now rename/copy */
  616. pair_to_free = p;
  617. }
  618. else {
  619. if (p->one->rename_used)
  620. /* this path remains */
  621. pair_to_free = p;
  622. }
  623. if (pair_to_free)
  624. ;
  625. else
  626. diff_q(&outq, p);
  627. }
  628. else if (!diff_unmodified_pair(p))
  629. /* all the usual ones need to be kept */
  630. diff_q(&outq, p);
  631. else
  632. /* no need to keep unmodified pairs */
  633. pair_to_free = p;
  634. if (pair_to_free)
  635. diff_free_filepair(pair_to_free);
  636. }
  637. diff_debug_queue("done copying original", &outq);
  638. free(q->queue);
  639. *q = outq;
  640. diff_debug_queue("done collapsing", q);
  641. for (i = 0; i < rename_dst_nr; i++)
  642. free_filespec(rename_dst[i].two);
  643. FREE_AND_NULL(rename_dst);
  644. rename_dst_nr = rename_dst_alloc = 0;
  645. FREE_AND_NULL(rename_src);
  646. rename_src_nr = rename_src_alloc = 0;
  647. return;
  648. }