Coverage Report

Created: 2026-11-12 06:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/diffcore-rename.c
Line
Count
Source
1
/*
2
 *
3
 * Copyright (C) 2005 Junio C Hamano
4
 */
5
6
#include "git-compat-util.h"
7
#include "diff.h"
8
#include "diffcore.h"
9
#include "object-file.h"
10
#include "hashmap.h"
11
#include "mem-pool.h"
12
#include "oid-array.h"
13
#include "progress.h"
14
#include "promisor-remote.h"
15
#include "string-list.h"
16
#include "strmap.h"
17
#include "trace2.h"
18
19
/* Table of rename/copy destinations */
20
21
static struct diff_rename_dst {
22
  struct diff_filepair *p;
23
  struct diff_filespec *filespec_to_free;
24
  int is_rename; /* false -> just a create; true -> rename or copy */
25
} *rename_dst;
26
static int rename_dst_nr, rename_dst_alloc;
27
/* Mapping from break source pathname to break destination index */
28
static struct strintmap *break_idx = NULL;
29
30
static struct diff_rename_dst *locate_rename_dst(struct diff_filepair *p)
31
0
{
32
  /* Lookup by p->ONE->path */
33
0
  int idx = break_idx ? strintmap_get(break_idx, p->one->path) : -1;
34
0
  return (idx == -1 || idx == rename_dst_nr) ? NULL : &rename_dst[idx];
35
0
}
36
37
/*
38
 * Returns 0 on success, -1 if we found a duplicate.
39
 */
40
static int add_rename_dst(struct diff_filepair *p)
41
0
{
42
0
  ALLOC_GROW(rename_dst, rename_dst_nr + 1, rename_dst_alloc);
43
0
  rename_dst[rename_dst_nr].p = p;
44
0
  rename_dst[rename_dst_nr].filespec_to_free = NULL;
45
0
  rename_dst[rename_dst_nr].is_rename = 0;
46
0
  rename_dst_nr++;
47
0
  return 0;
48
0
}
49
50
/* Table of rename/copy src files */
51
static struct diff_rename_src {
52
  struct diff_filepair *p;
53
  unsigned short score; /* to remember the break score */
54
} *rename_src;
55
static int rename_src_nr, rename_src_alloc;
56
57
static void register_rename_src(struct diff_filepair *p)
58
0
{
59
0
  if (p->broken_pair) {
60
0
    if (!break_idx) {
61
0
      break_idx = xmalloc(sizeof(*break_idx));
62
0
      strintmap_init_with_options(break_idx, -1, NULL, 0);
63
0
    }
64
0
    strintmap_set(break_idx, p->one->path, rename_dst_nr);
65
0
  }
66
67
0
  ALLOC_GROW(rename_src, rename_src_nr + 1, rename_src_alloc);
68
0
  rename_src[rename_src_nr].p = p;
69
0
  rename_src[rename_src_nr].score = p->score;
70
0
  rename_src_nr++;
71
0
}
72
73
static int basename_same(struct diff_filespec *src, struct diff_filespec *dst)
74
0
{
75
0
  int src_len = strlen(src->path), dst_len = strlen(dst->path);
76
0
  while (src_len && dst_len) {
77
0
    char c1 = src->path[--src_len];
78
0
    char c2 = dst->path[--dst_len];
79
0
    if (c1 != c2)
80
0
      return 0;
81
0
    if (c1 == '/')
82
0
      return 1;
83
0
  }
84
0
  return (!src_len || src->path[src_len - 1] == '/') &&
85
0
    (!dst_len || dst->path[dst_len - 1] == '/');
86
0
}
87
88
struct diff_score {
89
  int src; /* index in rename_src */
90
  int dst; /* index in rename_dst */
91
  unsigned short score;
92
  short name_score;
93
};
94
95
struct inexact_prefetch_options {
96
  struct repository *repo;
97
  int skip_unmodified;
98
};
99
static void inexact_prefetch(void *prefetch_options)
100
0
{
101
0
  struct inexact_prefetch_options *options = prefetch_options;
102
0
  int i;
103
0
  struct oid_array to_fetch = OID_ARRAY_INIT;
104
105
0
  for (i = 0; i < rename_dst_nr; i++) {
106
0
    if (rename_dst[i].p->renamed_pair)
107
      /*
108
       * The loop in diffcore_rename() will not need these
109
       * blobs, so skip prefetching.
110
       */
111
0
      continue; /* already found exact match */
112
0
    diff_add_if_missing(options->repo, &to_fetch,
113
0
            rename_dst[i].p->two);
114
0
  }
115
0
  for (i = 0; i < rename_src_nr; i++) {
116
0
    if (options->skip_unmodified &&
117
0
        diff_unmodified_pair(rename_src[i].p))
118
      /*
119
       * The loop in diffcore_rename() will not need these
120
       * blobs, so skip prefetching.
121
       */
122
0
      continue;
123
0
    diff_add_if_missing(options->repo, &to_fetch,
124
0
            rename_src[i].p->one);
125
0
  }
126
0
  promisor_remote_get_direct(options->repo, to_fetch.oid, to_fetch.nr);
127
0
  oid_array_clear(&to_fetch);
128
0
}
129
130
static int estimate_similarity(struct repository *r,
131
             struct diff_filespec *src,
132
             struct diff_filespec *dst,
133
             int minimum_score,
134
             struct diff_populate_filespec_options *dpf_opt)
135
0
{
136
  /* src points at a file that existed in the original tree (or
137
   * optionally a file in the destination tree) and dst points
138
   * at a newly created file.  They may be quite similar, in which
139
   * case we want to say src is renamed to dst or src is copied into
140
   * dst, and then some edit has been applied to dst.
141
   *
142
   * Compare them and return how similar they are, representing
143
   * the score as an integer between 0 and MAX_SCORE.
144
   *
145
   * When there is an exact match, it is considered a better
146
   * match than anything else; the destination does not even
147
   * call into this function in that case.
148
   */
149
0
  unsigned long max_size, delta_size, base_size, src_copied, literal_added;
150
0
  int score;
151
152
  /* We deal only with regular files.  Symlink renames are handled
153
   * only when they are exact matches --- in other words, no edits
154
   * after renaming.
155
   */
156
0
  if (!S_ISREG(src->mode) || !S_ISREG(dst->mode))
157
0
    return 0;
158
159
  /*
160
   * Need to check that source and destination sizes are
161
   * filled in before comparing them.
162
   *
163
   * If we already have "cnt_data" filled in, we know it's
164
   * all good (avoid checking the size for zero, as that
165
   * is a possible size - we really should have a flag to
166
   * say whether the size is valid or not!)
167
   */
168
0
  dpf_opt->check_size_only = 1;
169
170
0
  if (!src->cnt_data &&
171
0
      diff_populate_filespec(r, src, dpf_opt))
172
0
    return 0;
173
0
  if (!dst->cnt_data &&
174
0
      diff_populate_filespec(r, dst, dpf_opt))
175
0
    return 0;
176
177
0
  max_size = ((src->size > dst->size) ? src->size : dst->size);
178
0
  base_size = ((src->size < dst->size) ? src->size : dst->size);
179
0
  delta_size = max_size - base_size;
180
181
  /* We would not consider edits that change the file size so
182
   * drastically.  delta_size must be smaller than
183
   * (MAX_SCORE-minimum_score)/MAX_SCORE * min(src->size, dst->size).
184
   *
185
   * Note that base_size == 0 case is handled here already
186
   * and the final score computation below would not have a
187
   * divide-by-zero issue.
188
   */
189
0
  if (max_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE)
190
0
    return 0;
191
192
0
  dpf_opt->check_size_only = 0;
193
194
0
  if (!src->cnt_data && diff_populate_filespec(r, src, dpf_opt))
195
0
    return 0;
196
0
  if (!dst->cnt_data && diff_populate_filespec(r, dst, dpf_opt))
197
0
    return 0;
198
199
0
  if (diffcore_count_changes(r, src, dst,
200
0
           &src->cnt_data, &dst->cnt_data,
201
0
           &src_copied, &literal_added))
202
0
    return 0;
203
204
  /* How similar are they?
205
   * what percentage of material in dst are from source?
206
   */
207
0
  if (!dst->size)
208
0
    score = 0; /* should not happen */
209
0
  else
210
0
    score = (int)(src_copied * MAX_SCORE / max_size);
211
0
  return score;
212
0
}
213
214
static void record_rename_pair(int dst_index, int src_index, int score)
215
0
{
216
0
  struct diff_filepair *src = rename_src[src_index].p;
217
0
  struct diff_filepair *dst = rename_dst[dst_index].p;
218
219
0
  if (dst->renamed_pair)
220
0
    die("internal error: dst already matched.");
221
222
0
  src->one->rename_used++;
223
0
  src->one->count++;
224
225
0
  rename_dst[dst_index].filespec_to_free = dst->one;
226
0
  rename_dst[dst_index].is_rename = 1;
227
228
0
  dst->one = src->one;
229
0
  dst->renamed_pair = 1;
230
0
  if (!strcmp(dst->one->path, dst->two->path))
231
0
    dst->score = rename_src[src_index].score;
232
0
  else
233
0
    dst->score = score;
234
0
}
235
236
/*
237
 * We sort the rename similarity matrix with the score, in descending
238
 * order (the most similar first).
239
 */
240
static int score_compare(const void *a_, const void *b_)
241
0
{
242
0
  const struct diff_score *a = a_, *b = b_;
243
244
  /* sink the unused ones to the bottom */
245
0
  if (a->dst < 0)
246
0
    return (0 <= b->dst);
247
0
  else if (b->dst < 0)
248
0
    return -1;
249
250
0
  if (a->score == b->score)
251
0
    return b->name_score - a->name_score;
252
253
0
  return b->score - a->score;
254
0
}
255
256
struct file_similarity {
257
  struct hashmap_entry entry;
258
  int index;
259
  struct diff_filespec *filespec;
260
};
261
262
static unsigned int hash_filespec(struct repository *r,
263
          struct diff_filespec *filespec)
264
0
{
265
0
  if (!filespec->oid_valid) {
266
0
    if (diff_populate_filespec(r, filespec, NULL))
267
0
      return 0;
268
0
    hash_object_file(r->hash_algo, filespec->data, filespec->size,
269
0
         OBJ_BLOB, &filespec->oid);
270
0
  }
271
0
  return oidhash(&filespec->oid);
272
0
}
273
274
static int find_identical_files(struct hashmap *srcs,
275
        int dst_index,
276
        struct diff_options *options)
277
0
{
278
0
  int renames = 0;
279
0
  struct diff_filespec *target = rename_dst[dst_index].p->two;
280
0
  struct file_similarity *p, *best = NULL;
281
0
  int i = 100, best_score = -1;
282
0
  unsigned int hash = hash_filespec(options->repo, target);
283
284
  /*
285
   * Find the best source match for specified destination.
286
   */
287
0
  p = hashmap_get_entry_from_hash(srcs, hash, NULL,
288
0
          struct file_similarity, entry);
289
0
  hashmap_for_each_entry_from(srcs, p, entry) {
290
0
    int score;
291
0
    struct diff_filespec *source = p->filespec;
292
293
    /* False hash collision? */
294
0
    if (!oideq(&source->oid, &target->oid))
295
0
      continue;
296
    /* Non-regular files? If so, the modes must match! */
297
0
    if (!S_ISREG(source->mode) || !S_ISREG(target->mode)) {
298
0
      if (source->mode != target->mode)
299
0
        continue;
300
0
    }
301
    /* Give higher scores to sources that haven't been used already */
302
0
    score = !source->rename_used;
303
0
    if (source->rename_used && options->detect_rename != DIFF_DETECT_COPY)
304
0
      continue;
305
0
    score += basename_same(source, target);
306
0
    if (score > best_score) {
307
0
      best = p;
308
0
      best_score = score;
309
0
      if (score == 2)
310
0
        break;
311
0
    }
312
313
    /* Too many identical alternatives? Pick one */
314
0
    if (!--i)
315
0
      break;
316
0
  }
317
0
  if (best) {
318
0
    record_rename_pair(dst_index, best->index, MAX_SCORE);
319
0
    renames++;
320
0
  }
321
0
  return renames;
322
0
}
323
324
static void insert_file_table(struct repository *r,
325
            struct mem_pool *pool,
326
            struct hashmap *table, int index,
327
            struct diff_filespec *filespec)
328
0
{
329
0
  struct file_similarity *entry = mem_pool_alloc(pool, sizeof(*entry));
330
331
0
  entry->index = index;
332
0
  entry->filespec = filespec;
333
334
0
  hashmap_entry_init(&entry->entry, hash_filespec(r, filespec));
335
0
  hashmap_add(table, &entry->entry);
336
0
}
337
338
/*
339
 * Find exact renames first.
340
 *
341
 * The first round matches up the up-to-date entries,
342
 * and then during the second round we try to match
343
 * cache-dirty entries as well.
344
 */
345
static int find_exact_renames(struct diff_options *options,
346
            struct mem_pool *pool)
347
0
{
348
0
  int i, renames = 0;
349
0
  struct hashmap file_table;
350
351
  /* Add all sources to the hash table in reverse order, because
352
   * later on they will be retrieved in LIFO order.
353
   */
354
0
  hashmap_init(&file_table, NULL, NULL, rename_src_nr);
355
0
  for (i = rename_src_nr-1; i >= 0; i--)
356
0
    insert_file_table(options->repo, pool,
357
0
          &file_table, i,
358
0
          rename_src[i].p->one);
359
360
  /* Walk the destinations and find best source match */
361
0
  for (i = 0; i < rename_dst_nr; i++)
362
0
    renames += find_identical_files(&file_table, i, options);
363
364
  /* Free the hash data structure (entries will be freed with the pool) */
365
0
  hashmap_clear(&file_table);
366
367
0
  return renames;
368
0
}
369
370
struct dir_rename_info {
371
  struct strintmap idx_map;
372
  struct strmap dir_rename_guess;
373
  struct strmap *dir_rename_count;
374
  struct strintmap *relevant_source_dirs;
375
  unsigned setup;
376
};
377
378
static char *get_dirname(const char *filename)
379
0
{
380
0
  const char *slash = strrchr(filename, '/');
381
0
  return slash ? xstrndup(filename, slash - filename) : xstrdup("");
382
0
}
383
384
static void dirname_munge(char *filename)
385
0
{
386
0
  char *slash = strrchr(filename, '/');
387
0
  if (!slash)
388
0
    slash = filename;
389
0
  *slash = '\0';
390
0
}
391
392
static const char *get_highest_rename_path(struct strintmap *counts)
393
0
{
394
0
  int highest_count = 0;
395
0
  const char *highest_destination_dir = NULL;
396
0
  struct hashmap_iter iter;
397
0
  struct strmap_entry *entry;
398
399
0
  strintmap_for_each_entry(counts, &iter, entry) {
400
0
    const char *destination_dir = entry->key;
401
0
    intptr_t count = (intptr_t)entry->value;
402
0
    if (count > highest_count) {
403
0
      highest_count = count;
404
0
      highest_destination_dir = destination_dir;
405
0
    }
406
0
  }
407
0
  return highest_destination_dir;
408
0
}
409
410
static const char *UNKNOWN_DIR = "/";  /* placeholder -- short, illegal directory */
411
412
static int dir_rename_already_determinable(struct strintmap *counts)
413
0
{
414
0
  struct hashmap_iter iter;
415
0
  struct strmap_entry *entry;
416
0
  int first = 0, second = 0, unknown = 0;
417
0
  strintmap_for_each_entry(counts, &iter, entry) {
418
0
    const char *destination_dir = entry->key;
419
0
    intptr_t count = (intptr_t)entry->value;
420
0
    if (!strcmp(destination_dir, UNKNOWN_DIR)) {
421
0
      unknown = count;
422
0
    } else if (count >= first) {
423
0
      second = first;
424
0
      first = count;
425
0
    } else if (count >= second) {
426
0
      second = count;
427
0
    }
428
0
  }
429
0
  return first > second + unknown;
430
0
}
431
432
static void increment_count(struct dir_rename_info *info,
433
          const char *old_dir,
434
          const char *new_dir)
435
0
{
436
0
  struct strintmap *counts;
437
0
  struct strmap_entry *e;
438
439
  /* Get the {new_dirs -> counts} mapping using old_dir */
440
0
  e = strmap_get_entry(info->dir_rename_count, old_dir);
441
0
  if (e) {
442
0
    counts = e->value;
443
0
  } else {
444
0
    counts = xmalloc(sizeof(*counts));
445
0
    strintmap_init_with_options(counts, 0, NULL, 1);
446
0
    strmap_put(info->dir_rename_count, old_dir, counts);
447
0
  }
448
449
  /* Increment the count for new_dir */
450
0
  strintmap_incr(counts, new_dir, 1);
451
0
}
452
453
static void update_dir_rename_counts(struct dir_rename_info *info,
454
             struct strintmap *dirs_removed,
455
             const char *oldname,
456
             const char *newname)
457
0
{
458
0
  char *old_dir;
459
0
  char *new_dir;
460
0
  const char new_dir_first_char = newname[0];
461
0
  int first_time_in_loop = 1;
462
463
0
  if (!info->setup)
464
    /*
465
     * info->setup is 0 here in two cases: (1) all auxiliary
466
     * vars (like dirs_removed) were NULL so
467
     * initialize_dir_rename_info() returned early, or (2)
468
     * either break detection or copy detection are active so
469
     * that we never called initialize_dir_rename_info().  In
470
     * the former case, we don't have enough info to know if
471
     * directories were renamed (because dirs_removed lets us
472
     * know about a necessary prerequisite, namely if they were
473
     * removed), and in the latter, we don't care about
474
     * directory renames or find_basename_matches.
475
     *
476
     * This matters because both basename and inexact matching
477
     * will also call update_dir_rename_counts().  In either of
478
     * the above two cases info->dir_rename_counts will not
479
     * have been properly initialized which prevents us from
480
     * updating it, but in these two cases we don't care about
481
     * dir_rename_counts anyway, so we can just exit early.
482
     */
483
0
    return;
484
485
486
0
  old_dir = xstrdup(oldname);
487
0
  new_dir = xstrdup(newname);
488
489
0
  while (1) {
490
0
    int drd_flag = NOT_RELEVANT;
491
492
    /* Get old_dir, skip if its directory isn't relevant. */
493
0
    dirname_munge(old_dir);
494
0
    if (info->relevant_source_dirs &&
495
0
        !strintmap_contains(info->relevant_source_dirs, old_dir))
496
0
      break;
497
498
    /* Get new_dir */
499
0
    dirname_munge(new_dir);
500
501
    /*
502
     * When renaming
503
     *   "a/b/c/d/e/foo.c" -> "a/b/some/thing/else/e/foo.c"
504
     * then this suggests that both
505
     *   a/b/c/d/e/ => a/b/some/thing/else/e/
506
     *   a/b/c/d/   => a/b/some/thing/else/
507
     * so we want to increment counters for both.  We do NOT,
508
     * however, also want to suggest that there was the following
509
     * rename:
510
     *   a/b/c/ => a/b/some/thing/
511
     * so we need to quit at that point.
512
     *
513
     * Note the when first_time_in_loop, we only strip off the
514
     * basename, and we don't care if that's different.
515
     */
516
0
    if (!first_time_in_loop) {
517
0
      char *old_sub_dir = strchr(old_dir, '\0')+1;
518
0
      char *new_sub_dir = strchr(new_dir, '\0')+1;
519
0
      if (!*new_dir) {
520
        /*
521
         * Special case when renaming to root directory,
522
         * i.e. when new_dir == "".  In this case, we had
523
         * something like
524
         *    a/b/subdir => subdir
525
         * and so dirname_munge() sets things up so that
526
         *    old_dir = "a/b\0subdir\0"
527
         *    new_dir = "\0ubdir\0"
528
         * We didn't have a '/' to overwrite a '\0' onto
529
         * in new_dir, so we have to compare differently.
530
         */
531
0
        if (new_dir_first_char != old_sub_dir[0] ||
532
0
            strcmp(old_sub_dir+1, new_sub_dir))
533
0
          break;
534
0
      } else {
535
0
        if (strcmp(old_sub_dir, new_sub_dir))
536
0
          break;
537
0
      }
538
0
    }
539
540
    /*
541
     * Above we suggested that we'd keep recording renames for
542
     * all ancestor directories where the trailing directories
543
     * matched, i.e. for
544
     *   "a/b/c/d/e/foo.c" -> "a/b/some/thing/else/e/foo.c"
545
     * we'd increment rename counts for each of
546
     *   a/b/c/d/e/ => a/b/some/thing/else/e/
547
     *   a/b/c/d/   => a/b/some/thing/else/
548
     * However, we only need the rename counts for directories
549
     * in dirs_removed whose value is RELEVANT_FOR_SELF.
550
     * However, we add one special case of also recording it for
551
     * first_time_in_loop because find_basename_matches() can
552
     * use that as a hint to find a good pairing.
553
     */
554
0
    if (dirs_removed)
555
0
      drd_flag = strintmap_get(dirs_removed, old_dir);
556
0
    if (drd_flag == RELEVANT_FOR_SELF || first_time_in_loop)
557
0
      increment_count(info, old_dir, new_dir);
558
559
0
    first_time_in_loop = 0;
560
0
    if (drd_flag == NOT_RELEVANT)
561
0
      break;
562
    /* If we hit toplevel directory ("") for old or new dir, quit */
563
0
    if (!*old_dir || !*new_dir)
564
0
      break;
565
0
  }
566
567
  /* Free resources we don't need anymore */
568
0
  free(old_dir);
569
0
  free(new_dir);
570
0
}
571
572
static void initialize_dir_rename_info(struct dir_rename_info *info,
573
               struct strintmap *relevant_sources,
574
               struct strintmap *dirs_removed,
575
               struct strmap *dir_rename_count,
576
               struct strmap *cached_pairs)
577
0
{
578
0
  struct hashmap_iter iter;
579
0
  struct strmap_entry *entry;
580
0
  int i;
581
582
0
  if (!dirs_removed && !relevant_sources) {
583
0
    info->setup = 0;
584
0
    return;
585
0
  }
586
0
  info->setup = 1;
587
588
0
  info->dir_rename_count = dir_rename_count;
589
0
  if (!info->dir_rename_count) {
590
0
    info->dir_rename_count = xmalloc(sizeof(*dir_rename_count));
591
0
    strmap_init(info->dir_rename_count);
592
0
  }
593
0
  strintmap_init_with_options(&info->idx_map, -1, NULL, 0);
594
0
  strmap_init_with_options(&info->dir_rename_guess, NULL, 0);
595
596
  /* Setup info->relevant_source_dirs */
597
0
  info->relevant_source_dirs = NULL;
598
0
  if (dirs_removed || !relevant_sources) {
599
0
    info->relevant_source_dirs = dirs_removed; /* might be NULL */
600
0
  } else {
601
0
    info->relevant_source_dirs = xmalloc(sizeof(struct strintmap));
602
0
    strintmap_init(info->relevant_source_dirs, 0 /* unused */);
603
0
    strintmap_for_each_entry(relevant_sources, &iter, entry) {
604
0
      char *dirname = get_dirname(entry->key);
605
0
      if (!dirs_removed ||
606
0
          strintmap_contains(dirs_removed, dirname))
607
0
        strintmap_set(info->relevant_source_dirs,
608
0
                dirname, 0 /* value irrelevant */);
609
0
      free(dirname);
610
0
    }
611
0
  }
612
613
  /*
614
   * Loop setting up both info->idx_map, and doing setup of
615
   * info->dir_rename_count.
616
   */
617
0
  for (i = 0; i < rename_dst_nr; ++i) {
618
    /*
619
     * For non-renamed files, make idx_map contain mapping of
620
     *   filename -> index (index within rename_dst, that is)
621
     */
622
0
    if (!rename_dst[i].is_rename) {
623
0
      char *filename = rename_dst[i].p->two->path;
624
0
      strintmap_set(&info->idx_map, filename, i);
625
0
      continue;
626
0
    }
627
628
    /*
629
     * For everything else (i.e. renamed files), make
630
     * dir_rename_count contain a map of a map:
631
     *   old_directory -> {new_directory -> count}
632
     * In other words, for every pair look at the directories for
633
     * the old filename and the new filename and count how many
634
     * times that pairing occurs.
635
     */
636
0
    update_dir_rename_counts(info, dirs_removed,
637
0
           rename_dst[i].p->one->path,
638
0
           rename_dst[i].p->two->path);
639
0
  }
640
641
  /* Add cached_pairs to counts */
642
0
  strmap_for_each_entry(cached_pairs, &iter, entry) {
643
0
    const char *old_name = entry->key;
644
0
    const char *new_name = entry->value;
645
0
    if (!new_name)
646
      /* known delete; ignore it */
647
0
      continue;
648
649
0
    update_dir_rename_counts(info, dirs_removed, old_name, new_name);
650
0
  }
651
652
  /*
653
   * Now we collapse
654
   *    dir_rename_count: old_directory -> {new_directory -> count}
655
   * down to
656
   *    dir_rename_guess: old_directory -> best_new_directory
657
   * where best_new_directory is the one with the highest count.
658
   */
659
0
  strmap_for_each_entry(info->dir_rename_count, &iter, entry) {
660
    /* entry->key is source_dir */
661
0
    struct strintmap *counts = entry->value;
662
0
    char *best_newdir;
663
664
0
    best_newdir = xstrdup(get_highest_rename_path(counts));
665
0
    strmap_put(&info->dir_rename_guess, entry->key,
666
0
         best_newdir);
667
0
  }
668
0
}
669
670
void partial_clear_dir_rename_count(struct strmap *dir_rename_count)
671
0
{
672
0
  struct hashmap_iter iter;
673
0
  struct strmap_entry *entry;
674
675
0
  strmap_for_each_entry(dir_rename_count, &iter, entry) {
676
0
    struct strintmap *counts = entry->value;
677
0
    strintmap_clear(counts);
678
0
  }
679
0
  strmap_partial_clear(dir_rename_count, 1);
680
0
}
681
682
static void cleanup_dir_rename_info(struct dir_rename_info *info,
683
            struct strintmap *dirs_removed,
684
            int keep_dir_rename_count)
685
0
{
686
0
  struct hashmap_iter iter;
687
0
  struct strmap_entry *entry;
688
0
  struct string_list to_remove = STRING_LIST_INIT_NODUP;
689
690
0
  if (!info->setup)
691
0
    return;
692
693
  /* idx_map */
694
0
  strintmap_clear(&info->idx_map);
695
696
  /* dir_rename_guess */
697
0
  strmap_clear(&info->dir_rename_guess, 1);
698
699
  /* relevant_source_dirs */
700
0
  if (info->relevant_source_dirs &&
701
0
      info->relevant_source_dirs != dirs_removed) {
702
0
    strintmap_clear(info->relevant_source_dirs);
703
0
    FREE_AND_NULL(info->relevant_source_dirs);
704
0
  }
705
706
  /* dir_rename_count */
707
0
  if (!keep_dir_rename_count) {
708
0
    partial_clear_dir_rename_count(info->dir_rename_count);
709
0
    strmap_clear(info->dir_rename_count, 1);
710
0
    FREE_AND_NULL(info->dir_rename_count);
711
0
    return;
712
0
  }
713
714
  /*
715
   * Although dir_rename_count was passed in
716
   * diffcore_rename_extended() and we want to keep it around and
717
   * return it to that caller, we first want to remove any counts in
718
   * the maps associated with UNKNOWN_DIR entries and any data
719
   * associated with directories that weren't renamed.
720
   */
721
0
  strmap_for_each_entry(info->dir_rename_count, &iter, entry) {
722
0
    const char *source_dir = entry->key;
723
0
    struct strintmap *counts = entry->value;
724
725
0
    if (!strintmap_get(dirs_removed, source_dir)) {
726
0
      string_list_append(&to_remove, source_dir);
727
0
      strintmap_clear(counts);
728
0
      continue;
729
0
    }
730
731
0
    if (strintmap_contains(counts, UNKNOWN_DIR))
732
0
      strintmap_remove(counts, UNKNOWN_DIR);
733
0
  }
734
0
  for (size_t i = 0; i < to_remove.nr; ++i)
735
0
    strmap_remove(info->dir_rename_count,
736
0
            to_remove.items[i].string, 1);
737
0
  string_list_clear(&to_remove, 0);
738
0
}
739
740
static const char *get_basename(const char *filename)
741
0
{
742
  /*
743
   * gitbasename() has to worry about special drives, multiple
744
   * directory separator characters, trailing slashes, NULL or
745
   * empty strings, etc.  We only work on filenames as stored in
746
   * git, and thus get to ignore all those complications.
747
   */
748
0
  const char *base = strrchr(filename, '/');
749
0
  return base ? base + 1 : filename;
750
0
}
751
752
static int idx_possible_rename(char *filename, struct dir_rename_info *info)
753
0
{
754
  /*
755
   * Our comparison of files with the same basename (see
756
   * find_basename_matches() below), is only helpful when after exact
757
   * rename detection we have exactly one file with a given basename
758
   * among the rename sources and also only exactly one file with
759
   * that basename among the rename destinations.  When we have
760
   * multiple files with the same basename in either set, we do not
761
   * know which to compare against.  However, there are some
762
   * filenames that occur in large numbers (particularly
763
   * build-related filenames such as 'Makefile', '.gitignore', or
764
   * 'build.gradle' that potentially exist within every single
765
   * subdirectory), and for performance we want to be able to quickly
766
   * find renames for these files too.
767
   *
768
   * The reason basename comparisons are a useful heuristic was that it
769
   * is common for people to move files across directories while keeping
770
   * their filename the same.  If we had a way of determining or even
771
   * making a good educated guess about which directory these non-unique
772
   * basename files had moved the file to, we could check it.
773
   * Luckily...
774
   *
775
   * When an entire directory is in fact renamed, we have two factors
776
   * helping us out:
777
   *   (a) the original directory disappeared giving us a hint
778
   *       about when we can apply an extra heuristic.
779
   *   (a) we often have several files within that directory and
780
   *       subdirectories that are renamed without changes
781
   * So, rules for a heuristic:
782
   *   (0) If there basename matches are non-unique (the condition under
783
   *       which this function is called) AND
784
   *   (1) the directory in which the file was found has disappeared
785
   *       (i.e. dirs_removed is non-NULL and has a relevant entry) THEN
786
   *   (2) use exact renames of files within the directory to determine
787
   *       where the directory is likely to have been renamed to.  IF
788
   *       there is at least one exact rename from within that
789
   *       directory, we can proceed.
790
   *   (3) If there are multiple places the directory could have been
791
   *       renamed to based on exact renames, ignore all but one of them.
792
   *       Just use the destination with the most renames going to it.
793
   *   (4) Check if applying that directory rename to the original file
794
   *       would result in a destination filename that is in the
795
   *       potential rename set.  If so, return the index of the
796
   *       destination file (the index within rename_dst).
797
   *   (5) Compare the original file and returned destination for
798
   *       similarity, and if they are sufficiently similar, record the
799
   *       rename.
800
   *
801
   * This function, idx_possible_rename(), is only responsible for (4).
802
   * The conditions/steps in (1)-(3) are handled via setting up
803
   * dir_rename_count and dir_rename_guess in
804
   * initialize_dir_rename_info().  Steps (0) and (5) are handled by
805
   * the caller of this function.
806
   */
807
0
  char *old_dir, *new_dir;
808
0
  struct strbuf new_path = STRBUF_INIT;
809
0
  int idx;
810
811
0
  if (!info->setup)
812
0
    return -1;
813
814
0
  old_dir = get_dirname(filename);
815
0
  new_dir = strmap_get(&info->dir_rename_guess, old_dir);
816
0
  free(old_dir);
817
0
  if (!new_dir)
818
0
    return -1;
819
820
0
  strbuf_addstr(&new_path, new_dir);
821
0
  strbuf_addch(&new_path, '/');
822
0
  strbuf_addstr(&new_path, get_basename(filename));
823
824
0
  idx = strintmap_get(&info->idx_map, new_path.buf);
825
0
  strbuf_release(&new_path);
826
0
  return idx;
827
0
}
828
829
struct basename_prefetch_options {
830
  struct repository *repo;
831
  struct strintmap *relevant_sources;
832
  struct strintmap *sources;
833
  struct strintmap *dests;
834
  struct dir_rename_info *info;
835
};
836
static void basename_prefetch(void *prefetch_options)
837
0
{
838
0
  struct basename_prefetch_options *options = prefetch_options;
839
0
  struct strintmap *relevant_sources = options->relevant_sources;
840
0
  struct strintmap *sources = options->sources;
841
0
  struct strintmap *dests = options->dests;
842
0
  struct dir_rename_info *info = options->info;
843
0
  int i;
844
0
  struct oid_array to_fetch = OID_ARRAY_INIT;
845
846
  /*
847
   * TODO: The following loops mirror the code/logic from
848
   * find_basename_matches(), though not quite exactly.  Maybe
849
   * abstract the iteration logic out somehow?
850
   */
851
0
  for (i = 0; i < rename_src_nr; ++i) {
852
0
    char *filename = rename_src[i].p->one->path;
853
0
    const char *base = NULL;
854
0
    intptr_t src_index;
855
0
    intptr_t dst_index;
856
857
    /* Skip irrelevant sources */
858
0
    if (relevant_sources &&
859
0
        !strintmap_contains(relevant_sources, filename))
860
0
      continue;
861
862
    /*
863
     * If the basename is unique among remaining sources, then
864
     * src_index will equal 'i' and we can attempt to match it
865
     * to a unique basename in the destinations.  Otherwise,
866
     * use directory rename heuristics, if possible.
867
     */
868
0
    base = get_basename(filename);
869
0
    src_index = strintmap_get(sources, base);
870
0
    assert(src_index == -1 || src_index == i);
871
872
0
    if (strintmap_contains(dests, base)) {
873
0
      struct diff_filespec *one, *two;
874
875
      /* Find a matching destination, if possible */
876
0
      dst_index = strintmap_get(dests, base);
877
0
      if (src_index == -1 || dst_index == -1) {
878
0
        src_index = i;
879
0
        dst_index = idx_possible_rename(filename, info);
880
0
      }
881
0
      if (dst_index == -1)
882
0
        continue;
883
884
      /* Ignore this dest if already used in a rename */
885
0
      if (rename_dst[dst_index].is_rename)
886
0
        continue; /* already used previously */
887
888
0
      one = rename_src[src_index].p->one;
889
0
      two = rename_dst[dst_index].p->two;
890
891
      /* Add the pairs */
892
0
      diff_add_if_missing(options->repo, &to_fetch, two);
893
0
      diff_add_if_missing(options->repo, &to_fetch, one);
894
0
    }
895
0
  }
896
897
0
  promisor_remote_get_direct(options->repo, to_fetch.oid, to_fetch.nr);
898
0
  oid_array_clear(&to_fetch);
899
0
}
900
901
static int find_basename_matches(struct diff_options *options,
902
         int minimum_score,
903
         struct dir_rename_info *info,
904
         struct strintmap *relevant_sources,
905
         struct strintmap *dirs_removed)
906
0
{
907
  /*
908
   * When I checked in early 2020, over 76% of file renames in linux
909
   * just moved files to a different directory but kept the same
910
   * basename.  gcc did that with over 64% of renames, gecko did it
911
   * with over 79%, and WebKit did it with over 89%.
912
   *
913
   * Therefore we can bypass the normal exhaustive NxM matrix
914
   * comparison of similarities between all potential rename sources
915
   * and destinations by instead using file basename as a hint (i.e.
916
   * the portion of the filename after the last '/'), checking for
917
   * similarity between files with the same basename, and if we find
918
   * a pair that are sufficiently similar, record the rename pair and
919
   * exclude those two from the NxM matrix.
920
   *
921
   * This *might* cause us to find a less than optimal pairing (if
922
   * there is another file that we are even more similar to but has a
923
   * different basename).  Given the huge performance advantage
924
   * basename matching provides, and given the frequency with which
925
   * people use the same basename in real world projects, that's a
926
   * trade-off we are willing to accept when doing just rename
927
   * detection.
928
   *
929
   * If someone wants copy detection that implies they are willing to
930
   * spend more cycles to find similarities between files, so it may
931
   * be less likely that this heuristic is wanted.  If someone is
932
   * doing break detection, that means they do not want filename
933
   * similarity to imply any form of content similarity, and thus
934
   * this heuristic would definitely be incompatible.
935
   */
936
937
0
  int i, renames = 0;
938
0
  struct strintmap sources;
939
0
  struct strintmap dests;
940
0
  struct diff_populate_filespec_options dpf_options = {
941
0
    .check_binary = 0,
942
0
    .missing_object_cb = NULL,
943
0
    .missing_object_data = NULL
944
0
  };
945
0
  struct basename_prefetch_options prefetch_options = {
946
0
    .repo = options->repo,
947
0
    .relevant_sources = relevant_sources,
948
0
    .sources = &sources,
949
0
    .dests = &dests,
950
0
    .info = info
951
0
  };
952
953
  /*
954
   * Create maps of basename -> fullname(s) for remaining sources and
955
   * dests.
956
   */
957
0
  strintmap_init_with_options(&sources, -1, NULL, 0);
958
0
  strintmap_init_with_options(&dests, -1, NULL, 0);
959
0
  for (i = 0; i < rename_src_nr; ++i) {
960
0
    char *filename = rename_src[i].p->one->path;
961
0
    const char *base;
962
963
    /* exact renames removed in remove_unneeded_paths_from_src() */
964
0
    assert(!rename_src[i].p->one->rename_used);
965
966
    /* Record index within rename_src (i) if basename is unique */
967
0
    base = get_basename(filename);
968
0
    if (strintmap_contains(&sources, base))
969
0
      strintmap_set(&sources, base, -1);
970
0
    else
971
0
      strintmap_set(&sources, base, i);
972
0
  }
973
0
  for (i = 0; i < rename_dst_nr; ++i) {
974
0
    char *filename = rename_dst[i].p->two->path;
975
0
    const char *base;
976
977
0
    if (rename_dst[i].is_rename)
978
0
      continue; /* involved in exact match already. */
979
980
    /* Record index within rename_dst (i) if basename is unique */
981
0
    base = get_basename(filename);
982
0
    if (strintmap_contains(&dests, base))
983
0
      strintmap_set(&dests, base, -1);
984
0
    else
985
0
      strintmap_set(&dests, base, i);
986
0
  }
987
988
0
  if (repo_has_promisor_remote(options->repo)) {
989
0
    dpf_options.missing_object_cb = basename_prefetch;
990
0
    dpf_options.missing_object_data = &prefetch_options;
991
0
  }
992
993
  /* Now look for basename matchups and do similarity estimation */
994
0
  for (i = 0; i < rename_src_nr; ++i) {
995
0
    char *filename = rename_src[i].p->one->path;
996
0
    const char *base = NULL;
997
0
    intptr_t src_index;
998
0
    intptr_t dst_index;
999
1000
    /* Skip irrelevant sources */
1001
0
    if (relevant_sources &&
1002
0
        !strintmap_contains(relevant_sources, filename))
1003
0
      continue;
1004
1005
    /*
1006
     * If the basename is unique among remaining sources, then
1007
     * src_index will equal 'i' and we can attempt to match it
1008
     * to a unique basename in the destinations.  Otherwise,
1009
     * use directory rename heuristics, if possible.
1010
     */
1011
0
    base = get_basename(filename);
1012
0
    src_index = strintmap_get(&sources, base);
1013
0
    assert(src_index == -1 || src_index == i);
1014
1015
0
    if (strintmap_contains(&dests, base)) {
1016
0
      struct diff_filespec *one, *two;
1017
0
      int score;
1018
1019
      /* Find a matching destination, if possible */
1020
0
      dst_index = strintmap_get(&dests, base);
1021
0
      if (src_index == -1 || dst_index == -1) {
1022
0
        src_index = i;
1023
0
        dst_index = idx_possible_rename(filename, info);
1024
0
      }
1025
0
      if (dst_index == -1)
1026
0
        continue;
1027
1028
      /* Ignore this dest if already used in a rename */
1029
0
      if (rename_dst[dst_index].is_rename)
1030
0
        continue; /* already used previously */
1031
1032
      /* Estimate the similarity */
1033
0
      one = rename_src[src_index].p->one;
1034
0
      two = rename_dst[dst_index].p->two;
1035
0
      score = estimate_similarity(options->repo, one, two,
1036
0
                minimum_score, &dpf_options);
1037
1038
      /* If sufficiently similar, record as rename pair */
1039
0
      if (score < minimum_score)
1040
0
        continue;
1041
0
      record_rename_pair(dst_index, src_index, score);
1042
0
      renames++;
1043
0
      update_dir_rename_counts(info, dirs_removed,
1044
0
             one->path, two->path);
1045
1046
      /*
1047
       * Found a rename so don't need text anymore; if we
1048
       * didn't find a rename, the filespec_blob would get
1049
       * re-used when doing the matrix of comparisons.
1050
       */
1051
0
      diff_free_filespec_blob(one);
1052
0
      diff_free_filespec_blob(two);
1053
0
    }
1054
0
  }
1055
1056
0
  strintmap_clear(&sources);
1057
0
  strintmap_clear(&dests);
1058
1059
0
  return renames;
1060
0
}
1061
1062
0
#define NUM_CANDIDATE_PER_DST 4
1063
static void record_if_better(struct diff_score m[], struct diff_score *o)
1064
0
{
1065
0
  int i, worst;
1066
1067
  /* find the worst one */
1068
0
  worst = 0;
1069
0
  for (i = 1; i < NUM_CANDIDATE_PER_DST; i++)
1070
0
    if (score_compare(&m[i], &m[worst]) > 0)
1071
0
      worst = i;
1072
1073
  /* is it better than the worst one? */
1074
0
  if (score_compare(&m[worst], o) > 0)
1075
0
    m[worst] = *o;
1076
0
}
1077
1078
/*
1079
 * Returns:
1080
 * 0 if we are under the limit;
1081
 * 1 if we need to disable inexact rename detection;
1082
 * 2 if we would be under the limit if we were given -C instead of -C -C.
1083
 */
1084
static int too_many_rename_candidates(int num_destinations, int num_sources,
1085
              struct diff_options *options)
1086
0
{
1087
0
  int rename_limit = options->rename_limit;
1088
0
  int i, limited_sources;
1089
1090
0
  options->needed_rename_limit = 0;
1091
1092
  /*
1093
   * This basically does a test for the rename matrix not
1094
   * growing larger than a "rename_limit" square matrix, ie:
1095
   *
1096
   *    num_destinations * num_sources > rename_limit * rename_limit
1097
   *
1098
   * We use st_mult() to check overflow conditions; in the
1099
   * exceptional circumstance that size_t isn't large enough to hold
1100
   * the multiplication, the system won't be able to allocate enough
1101
   * memory for the matrix anyway.
1102
   */
1103
0
  if (rename_limit <= 0)
1104
0
    return 0; /* treat as unlimited */
1105
0
  if (st_mult(num_destinations, num_sources)
1106
0
      <= st_mult(rename_limit, rename_limit))
1107
0
    return 0;
1108
1109
0
  options->needed_rename_limit =
1110
0
    num_sources > num_destinations ? num_sources : num_destinations;
1111
1112
  /* Are we running under -C -C? */
1113
0
  if (!options->flags.find_copies_harder)
1114
0
    return 1;
1115
1116
  /* Would we bust the limit if we were running under -C? */
1117
0
  for (limited_sources = i = 0; i < num_sources; i++) {
1118
0
    if (diff_unmodified_pair(rename_src[i].p))
1119
0
      continue;
1120
0
    limited_sources++;
1121
0
  }
1122
0
  if (st_mult(num_destinations, limited_sources)
1123
0
      <= st_mult(rename_limit, rename_limit))
1124
0
    return 2;
1125
0
  return 1;
1126
0
}
1127
1128
static int find_renames(struct diff_score *mx,
1129
      int dst_cnt,
1130
      int minimum_score,
1131
      int copies,
1132
      struct dir_rename_info *info,
1133
      struct strintmap *dirs_removed)
1134
0
{
1135
0
  int count = 0, i;
1136
1137
0
  for (i = 0; i < dst_cnt * NUM_CANDIDATE_PER_DST; i++) {
1138
0
    struct diff_rename_dst *dst;
1139
1140
0
    if ((mx[i].dst < 0) ||
1141
0
        (mx[i].score < minimum_score))
1142
0
      break; /* there is no more usable pair. */
1143
0
    dst = &rename_dst[mx[i].dst];
1144
0
    if (dst->is_rename)
1145
0
      continue; /* already done, either exact or fuzzy. */
1146
0
    if (!copies && rename_src[mx[i].src].p->one->rename_used)
1147
0
      continue;
1148
0
    record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
1149
0
    count++;
1150
0
    update_dir_rename_counts(info, dirs_removed,
1151
0
           rename_src[mx[i].src].p->one->path,
1152
0
           rename_dst[mx[i].dst].p->two->path);
1153
0
  }
1154
0
  return count;
1155
0
}
1156
1157
static void remove_unneeded_paths_from_src(int detecting_copies,
1158
             struct strintmap *interesting)
1159
0
{
1160
0
  int i, new_num_src;
1161
1162
0
  if (detecting_copies && !interesting)
1163
0
    return; /* nothing to remove */
1164
0
  if (break_idx)
1165
0
    return; /* culling incompatible with break detection */
1166
1167
  /*
1168
   * Note on reasons why we cull unneeded sources but not destinations:
1169
   *   1) Pairings are stored in rename_dst (not rename_src), which we
1170
   *      need to keep around.  So, we just can't cull rename_dst even
1171
   *      if we wanted to.  But doing so wouldn't help because...
1172
   *
1173
   *   2) There is a matrix pairwise comparison that follows the
1174
   *      "Performing inexact rename detection" progress message.
1175
   *      Iterating over the destinations is done in the outer loop,
1176
   *      hence we only iterate over each of those once and we can
1177
   *      easily skip the outer loop early if the destination isn't
1178
   *      relevant.  That's only one check per destination path to
1179
   *      skip.
1180
   *
1181
   *      By contrast, the sources are iterated in the inner loop; if
1182
   *      we check whether a source can be skipped, then we'll be
1183
   *      checking it N separate times, once for each destination.
1184
   *      We don't want to have to iterate over known-not-needed
1185
   *      sources N times each, so avoid that by removing the sources
1186
   *      from rename_src here.
1187
   */
1188
0
  for (i = 0, new_num_src = 0; i < rename_src_nr; i++) {
1189
0
    struct diff_filespec *one = rename_src[i].p->one;
1190
1191
    /*
1192
     * renames are stored in rename_dst, so if a rename has
1193
     * already been detected using this source, we can just
1194
     * remove the source knowing rename_dst has its info.
1195
     */
1196
0
    if (!detecting_copies && one->rename_used)
1197
0
      continue;
1198
1199
    /* If we don't care about the source path, skip it */
1200
0
    if (interesting && !strintmap_contains(interesting, one->path))
1201
0
      continue;
1202
1203
0
    if (new_num_src < i)
1204
0
      memcpy(&rename_src[new_num_src], &rename_src[i],
1205
0
             sizeof(struct diff_rename_src));
1206
0
    new_num_src++;
1207
0
  }
1208
1209
0
  rename_src_nr = new_num_src;
1210
0
}
1211
1212
static void handle_early_known_dir_renames(struct dir_rename_info *info,
1213
             struct strintmap *relevant_sources,
1214
             struct strintmap *dirs_removed)
1215
0
{
1216
  /*
1217
   * Directory renames are determined via an aggregate of all renames
1218
   * under them and using a "majority wins" rule.  The fact that
1219
   * "majority wins", though, means we don't need all the renames
1220
   * under the given directory, we only need enough to ensure we have
1221
   * a majority.
1222
   */
1223
1224
0
  int i, new_num_src;
1225
0
  struct hashmap_iter iter;
1226
0
  struct strmap_entry *entry;
1227
1228
0
  if (!dirs_removed || !relevant_sources)
1229
0
    return; /* nothing to cull */
1230
0
  if (break_idx)
1231
0
    return; /* culling incompatbile with break detection */
1232
1233
  /*
1234
   * Supplement dir_rename_count with number of potential renames,
1235
   * marking all potential rename sources as mapping to UNKNOWN_DIR.
1236
   */
1237
0
  for (i = 0; i < rename_src_nr; i++) {
1238
0
    char *old_dir;
1239
0
    struct diff_filespec *one = rename_src[i].p->one;
1240
1241
    /*
1242
     * sources that are part of a rename will have already been
1243
     * removed by a prior call to remove_unneeded_paths_from_src()
1244
     */
1245
0
    assert(!one->rename_used);
1246
1247
0
    old_dir = get_dirname(one->path);
1248
0
    while (*old_dir != '\0' &&
1249
0
           NOT_RELEVANT != strintmap_get(dirs_removed, old_dir)) {
1250
0
      char *freeme = old_dir;
1251
1252
0
      increment_count(info, old_dir, UNKNOWN_DIR);
1253
0
      old_dir = get_dirname(old_dir);
1254
1255
      /* Free resources we don't need anymore */
1256
0
      free(freeme);
1257
0
    }
1258
    /*
1259
     * old_dir and new_dir free'd in increment_count, but
1260
     * get_dirname() gives us a new pointer we need to free for
1261
     * old_dir.  Also, if the loop runs 0 times we need old_dir
1262
     * to be freed.
1263
     */
1264
0
    free(old_dir);
1265
0
  }
1266
1267
  /*
1268
   * For any directory which we need a potential rename detected for
1269
   * (i.e. those marked as RELEVANT_FOR_SELF in dirs_removed), check
1270
   * whether we have enough renames to satisfy the "majority rules"
1271
   * requirement such that detecting any more renames of files under
1272
   * it won't change the result.  For any such directory, mark that
1273
   * we no longer need to detect a rename for it.  However, since we
1274
   * might need to still detect renames for an ancestor of that
1275
   * directory, use RELEVANT_FOR_ANCESTOR.
1276
   */
1277
0
  strmap_for_each_entry(info->dir_rename_count, &iter, entry) {
1278
    /* entry->key is source_dir */
1279
0
    struct strintmap *counts = entry->value;
1280
1281
0
    if (strintmap_get(dirs_removed, entry->key) ==
1282
0
        RELEVANT_FOR_SELF &&
1283
0
        dir_rename_already_determinable(counts)) {
1284
0
      strintmap_set(dirs_removed, entry->key,
1285
0
              RELEVANT_FOR_ANCESTOR);
1286
0
    }
1287
0
  }
1288
1289
0
  for (i = 0, new_num_src = 0; i < rename_src_nr; i++) {
1290
0
    struct diff_filespec *one = rename_src[i].p->one;
1291
0
    int val;
1292
1293
0
    val = strintmap_get(relevant_sources, one->path);
1294
1295
    /*
1296
     * sources that were not found in relevant_sources should
1297
     * have already been removed by a prior call to
1298
     * remove_unneeded_paths_from_src()
1299
     */
1300
0
    assert(val != -1);
1301
1302
0
    if (val == RELEVANT_LOCATION) {
1303
0
      int removable = 1;
1304
0
      char *dir = get_dirname(one->path);
1305
0
      while (1) {
1306
0
        char *freeme = dir;
1307
0
        int res = strintmap_get(dirs_removed, dir);
1308
1309
        /* Quit if not found or irrelevant */
1310
0
        if (res == NOT_RELEVANT)
1311
0
          break;
1312
        /* If RELEVANT_FOR_SELF, can't remove */
1313
0
        if (res == RELEVANT_FOR_SELF) {
1314
0
          removable = 0;
1315
0
          break;
1316
0
        }
1317
        /* Else continue searching upwards */
1318
0
        assert(res == RELEVANT_FOR_ANCESTOR);
1319
0
        dir = get_dirname(dir);
1320
0
        free(freeme);
1321
0
      }
1322
0
      free(dir);
1323
0
      if (removable) {
1324
0
        strintmap_set(relevant_sources, one->path,
1325
0
                RELEVANT_NO_MORE);
1326
0
        continue;
1327
0
      }
1328
0
    }
1329
1330
0
    if (new_num_src < i)
1331
0
      memcpy(&rename_src[new_num_src], &rename_src[i],
1332
0
             sizeof(struct diff_rename_src));
1333
0
    new_num_src++;
1334
0
  }
1335
1336
0
  rename_src_nr = new_num_src;
1337
0
}
1338
1339
static void free_filespec_data(struct diff_filespec *spec)
1340
0
{
1341
0
  if (!--spec->count)
1342
0
    diff_free_filespec_data(spec);
1343
0
}
1344
1345
static void pool_free_filespec(struct mem_pool *pool,
1346
             struct diff_filespec *spec)
1347
0
{
1348
0
  if (!pool) {
1349
0
    free_filespec(spec);
1350
0
    return;
1351
0
  }
1352
1353
  /*
1354
   * Similar to free_filespec(), but only frees the data.  The spec
1355
   * itself was allocated in the pool and should not be individually
1356
   * freed.
1357
   */
1358
0
  free_filespec_data(spec);
1359
0
}
1360
1361
void pool_diff_free_filepair(struct mem_pool *pool,
1362
           struct diff_filepair *p)
1363
0
{
1364
0
  if (!pool) {
1365
0
    diff_free_filepair(p);
1366
0
    return;
1367
0
  }
1368
1369
  /*
1370
   * Similar to diff_free_filepair() but only frees the data from the
1371
   * filespecs; not the filespecs or the filepair which were
1372
   * allocated from the pool.
1373
   */
1374
0
  free_filespec_data(p->one);
1375
0
  free_filespec_data(p->two);
1376
0
}
1377
1378
void diffcore_rename_extended(struct diff_options *options,
1379
            struct mem_pool *pool,
1380
            struct strintmap *relevant_sources,
1381
            struct strintmap *dirs_removed,
1382
            struct strmap *dir_rename_count,
1383
            struct strmap *cached_pairs)
1384
0
{
1385
0
  int detect_rename = options->detect_rename;
1386
0
  int minimum_score = options->rename_score;
1387
0
  struct diff_queue_struct *q = &diff_queued_diff;
1388
0
  struct diff_queue_struct outq = DIFF_QUEUE_INIT;
1389
0
  struct diff_score *mx;
1390
0
  int i, j, rename_count, skip_unmodified = 0;
1391
0
  int num_destinations, dst_cnt;
1392
0
  int num_sources, want_copies;
1393
0
  struct progress *progress = NULL;
1394
0
  struct mem_pool local_pool;
1395
0
  struct dir_rename_info info;
1396
0
  struct diff_populate_filespec_options dpf_options = {
1397
0
    .check_binary = 0,
1398
0
    .missing_object_cb = NULL,
1399
0
    .missing_object_data = NULL
1400
0
  };
1401
0
  struct inexact_prefetch_options prefetch_options = {
1402
0
    .repo = options->repo
1403
0
  };
1404
1405
0
  trace2_region_enter("diff", "setup", options->repo);
1406
0
  info.setup = 0;
1407
0
  ASSERT(!dir_rename_count || strmap_empty(dir_rename_count));
1408
0
  want_copies = (detect_rename == DIFF_DETECT_COPY);
1409
0
  if (dirs_removed && (break_idx || want_copies))
1410
0
    BUG("dirs_removed incompatible with break/copy detection");
1411
0
  if (break_idx && relevant_sources)
1412
0
    BUG("break detection incompatible with source specification");
1413
0
  if (!minimum_score)
1414
0
    minimum_score = DEFAULT_RENAME_SCORE;
1415
1416
0
  for (i = 0; i < q->nr; i++) {
1417
0
    struct diff_filepair *p = q->queue[i];
1418
0
    if (!DIFF_FILE_VALID(p->one)) {
1419
0
      if (!DIFF_FILE_VALID(p->two))
1420
0
        continue; /* unmerged */
1421
0
      else if (options->single_follow &&
1422
0
         strcmp(options->single_follow, p->two->path))
1423
0
        continue; /* not interested */
1424
0
      else if (!options->flags.rename_empty &&
1425
0
         is_empty_blob_oid(&p->two->oid,
1426
0
               options->repo->hash_algo))
1427
0
        continue;
1428
0
      else if (add_rename_dst(p) < 0) {
1429
0
        warning("skipping rename detection, detected"
1430
0
          " duplicate destination '%s'",
1431
0
          p->two->path);
1432
0
        goto cleanup;
1433
0
      }
1434
0
    }
1435
0
    else if (!options->flags.rename_empty &&
1436
0
       is_empty_blob_oid(&p->one->oid,
1437
0
             options->repo->hash_algo))
1438
0
      continue;
1439
0
    else if (!DIFF_PAIR_UNMERGED(p) && !DIFF_FILE_VALID(p->two)) {
1440
      /*
1441
       * If the source is a broken "delete", and
1442
       * they did not really want to get broken,
1443
       * that means the source actually stays.
1444
       * So we increment the "rename_used" score
1445
       * by one, to indicate ourselves as a user
1446
       */
1447
0
      if (p->broken_pair && !p->score)
1448
0
        p->one->rename_used++;
1449
0
      register_rename_src(p);
1450
0
    }
1451
0
    else if (want_copies) {
1452
      /*
1453
       * Increment the "rename_used" score by
1454
       * one, to indicate ourselves as a user.
1455
       */
1456
0
      p->one->rename_used++;
1457
0
      register_rename_src(p);
1458
0
    }
1459
0
  }
1460
0
  trace2_region_leave("diff", "setup", options->repo);
1461
0
  if (rename_dst_nr == 0 || rename_src_nr == 0)
1462
0
    goto cleanup; /* nothing to do */
1463
1464
0
  trace2_region_enter("diff", "exact renames", options->repo);
1465
0
  mem_pool_init(&local_pool, 32*1024);
1466
  /*
1467
   * We really want to cull the candidates list early
1468
   * with cheap tests in order to avoid doing deltas.
1469
   */
1470
0
  rename_count = find_exact_renames(options, &local_pool);
1471
  /*
1472
   * Discard local_pool immediately instead of at "cleanup:" in order
1473
   * to reduce maximum memory usage; inexact rename detection uses up
1474
   * a fair amount of memory, and mem_pools can too.
1475
   */
1476
0
  mem_pool_discard(&local_pool, 0);
1477
0
  trace2_region_leave("diff", "exact renames", options->repo);
1478
1479
  /* Did we only want exact renames? */
1480
0
  if (minimum_score == MAX_SCORE)
1481
0
    goto cleanup;
1482
1483
0
  num_sources = rename_src_nr;
1484
1485
0
  if (want_copies || break_idx) {
1486
    /*
1487
     * Cull sources:
1488
     *   - remove ones corresponding to exact renames
1489
     *   - remove ones not found in relevant_sources
1490
     */
1491
0
    trace2_region_enter("diff", "cull after exact", options->repo);
1492
0
    remove_unneeded_paths_from_src(want_copies, relevant_sources);
1493
0
    trace2_region_leave("diff", "cull after exact", options->repo);
1494
0
  } else {
1495
    /* Determine minimum score to match basenames */
1496
0
    double factor = 0.5;
1497
0
    char *basename_factor = getenv("GIT_BASENAME_FACTOR");
1498
0
    int min_basename_score;
1499
1500
0
    if (basename_factor)
1501
0
      factor = strtol(basename_factor, NULL, 10)/100.0;
1502
0
    assert(factor >= 0.0 && factor <= 1.0);
1503
0
    min_basename_score = minimum_score +
1504
0
      (int)(factor * (MAX_SCORE - minimum_score));
1505
1506
    /*
1507
     * Cull sources:
1508
     *   - remove ones involved in renames (found via exact match)
1509
     */
1510
0
    trace2_region_enter("diff", "cull after exact", options->repo);
1511
0
    remove_unneeded_paths_from_src(want_copies, NULL);
1512
0
    trace2_region_leave("diff", "cull after exact", options->repo);
1513
1514
    /* Preparation for basename-driven matching. */
1515
0
    trace2_region_enter("diff", "dir rename setup", options->repo);
1516
0
    initialize_dir_rename_info(&info, relevant_sources,
1517
0
             dirs_removed, dir_rename_count,
1518
0
             cached_pairs);
1519
0
    trace2_region_leave("diff", "dir rename setup", options->repo);
1520
1521
    /* Utilize file basenames to quickly find renames. */
1522
0
    trace2_region_enter("diff", "basename matches", options->repo);
1523
0
    rename_count += find_basename_matches(options,
1524
0
                  min_basename_score,
1525
0
                  &info,
1526
0
                  relevant_sources,
1527
0
                  dirs_removed);
1528
0
    trace2_region_leave("diff", "basename matches", options->repo);
1529
1530
    /*
1531
     * Cull sources, again:
1532
     *   - remove ones involved in renames (found via basenames)
1533
     *   - remove ones not found in relevant_sources
1534
     * and
1535
     *   - remove ones in relevant_sources which are needed only
1536
     *     for directory renames IF no ancestry directory
1537
     *     actually needs to know any more individual path
1538
     *     renames under them
1539
     */
1540
0
    trace2_region_enter("diff", "cull basename", options->repo);
1541
0
    remove_unneeded_paths_from_src(want_copies, relevant_sources);
1542
0
    handle_early_known_dir_renames(&info, relevant_sources,
1543
0
                 dirs_removed);
1544
0
    trace2_region_leave("diff", "cull basename", options->repo);
1545
0
  }
1546
1547
  /* Calculate how many rename destinations are left */
1548
0
  num_destinations = (rename_dst_nr - rename_count);
1549
0
  num_sources = rename_src_nr; /* rename_src_nr reflects lower number */
1550
1551
  /* All done? */
1552
0
  if (!num_destinations || !num_sources)
1553
0
    goto cleanup;
1554
1555
0
  switch (too_many_rename_candidates(num_destinations, num_sources,
1556
0
             options)) {
1557
0
  case 1:
1558
0
    goto cleanup;
1559
0
  case 2:
1560
0
    options->degraded_cc_to_c = 1;
1561
0
    skip_unmodified = 1;
1562
0
    break;
1563
0
  default:
1564
0
    break;
1565
0
  }
1566
1567
0
  trace2_region_enter("diff", "inexact renames", options->repo);
1568
0
  if (options->show_rename_progress) {
1569
0
    progress = start_delayed_progress(
1570
0
        options->repo,
1571
0
        _("Performing inexact rename detection"),
1572
0
        (uint64_t)num_destinations * (uint64_t)num_sources);
1573
0
  }
1574
1575
  /* Finish setting up dpf_options */
1576
0
  prefetch_options.skip_unmodified = skip_unmodified;
1577
0
  if (repo_has_promisor_remote(options->repo)) {
1578
0
    dpf_options.missing_object_cb = inexact_prefetch;
1579
0
    dpf_options.missing_object_data = &prefetch_options;
1580
0
  }
1581
1582
0
  CALLOC_ARRAY(mx, st_mult(NUM_CANDIDATE_PER_DST, num_destinations));
1583
0
  for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
1584
0
    struct diff_filespec *two = rename_dst[i].p->two;
1585
0
    struct diff_score *m;
1586
1587
0
    if (rename_dst[i].is_rename)
1588
0
      continue; /* exact or basename match already handled */
1589
1590
0
    m = &mx[dst_cnt * NUM_CANDIDATE_PER_DST];
1591
0
    for (j = 0; j < NUM_CANDIDATE_PER_DST; j++)
1592
0
      m[j].dst = -1;
1593
1594
0
    for (j = 0; j < rename_src_nr; j++) {
1595
0
      struct diff_filespec *one = rename_src[j].p->one;
1596
0
      struct diff_score this_src;
1597
1598
0
      assert(!one->rename_used || want_copies || break_idx);
1599
1600
0
      if (skip_unmodified &&
1601
0
          diff_unmodified_pair(rename_src[j].p))
1602
0
        continue;
1603
1604
0
      this_src.score = estimate_similarity(options->repo,
1605
0
                   one, two,
1606
0
                   minimum_score,
1607
0
                   &dpf_options);
1608
0
      this_src.name_score = basename_same(one, two);
1609
0
      this_src.dst = i;
1610
0
      this_src.src = j;
1611
0
      record_if_better(m, &this_src);
1612
      /*
1613
       * Once we run estimate_similarity,
1614
       * We do not need the text anymore.
1615
       */
1616
0
      diff_free_filespec_blob(one);
1617
0
      diff_free_filespec_blob(two);
1618
0
    }
1619
0
    dst_cnt++;
1620
0
    display_progress(progress,
1621
0
         (uint64_t)dst_cnt * (uint64_t)num_sources);
1622
0
  }
1623
0
  stop_progress(&progress);
1624
1625
  /* cost matrix sorted by most to least similar pair */
1626
0
  STABLE_QSORT(mx, dst_cnt * NUM_CANDIDATE_PER_DST, score_compare);
1627
1628
0
  rename_count += find_renames(mx, dst_cnt, minimum_score, 0,
1629
0
             &info, dirs_removed);
1630
0
  if (want_copies)
1631
0
    rename_count += find_renames(mx, dst_cnt, minimum_score, 1,
1632
0
               &info, dirs_removed);
1633
0
  free(mx);
1634
0
  trace2_region_leave("diff", "inexact renames", options->repo);
1635
1636
0
 cleanup:
1637
  /* At this point, we have found some renames and copies and they
1638
   * are recorded in rename_dst.  The original list is still in *q.
1639
   */
1640
0
  trace2_region_enter("diff", "write back to queue", options->repo);
1641
0
  for (i = 0; i < q->nr; i++) {
1642
0
    struct diff_filepair *p = q->queue[i];
1643
0
    struct diff_filepair *pair_to_free = NULL;
1644
1645
0
    if (DIFF_PAIR_UNMERGED(p)) {
1646
0
      diff_q(&outq, p);
1647
0
    }
1648
0
    else if (!DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) {
1649
      /* Creation */
1650
0
      diff_q(&outq, p);
1651
0
    }
1652
0
    else if (DIFF_FILE_VALID(p->one) && !DIFF_FILE_VALID(p->two)) {
1653
      /*
1654
       * Deletion
1655
       *
1656
       * We would output this delete record if:
1657
       *
1658
       * (1) this is a broken delete and the counterpart
1659
       *     broken create remains in the output; or
1660
       * (2) this is not a broken delete, and rename_dst
1661
       *     does not have a rename/copy to move p->one->path
1662
       *     out of existence.
1663
       *
1664
       * Otherwise, the counterpart broken create
1665
       * has been turned into a rename-edit; or
1666
       * delete did not have a matching create to
1667
       * begin with.
1668
       */
1669
0
      if (DIFF_PAIR_BROKEN(p)) {
1670
        /* broken delete */
1671
0
        struct diff_rename_dst *dst = locate_rename_dst(p);
1672
0
        if (options->single_follow && dst &&
1673
0
            strcmp(dst->p->two->path, p->two->path))
1674
0
          dst = NULL;
1675
0
        if (dst && dst->is_rename)
1676
          /* counterpart is now rename/copy */
1677
0
          pair_to_free = p;
1678
0
      }
1679
0
      else {
1680
0
        if (p->one->rename_used)
1681
          /* this path remains */
1682
0
          pair_to_free = p;
1683
0
      }
1684
1685
0
      if (!pair_to_free)
1686
0
        diff_q(&outq, p);
1687
0
    }
1688
0
    else if (!diff_unmodified_pair(p))
1689
      /* all the usual ones need to be kept */
1690
0
      diff_q(&outq, p);
1691
0
    else
1692
      /* no need to keep unmodified pairs */
1693
0
      pair_to_free = p;
1694
1695
0
    if (pair_to_free)
1696
0
      pool_diff_free_filepair(pool, pair_to_free);
1697
0
  }
1698
0
  diff_debug_queue("done copying original", &outq);
1699
1700
0
  free(q->queue);
1701
0
  *q = outq;
1702
0
  diff_debug_queue("done collapsing", q);
1703
1704
0
  for (i = 0; i < rename_dst_nr; i++)
1705
0
    if (rename_dst[i].filespec_to_free)
1706
0
      pool_free_filespec(pool, rename_dst[i].filespec_to_free);
1707
1708
0
  cleanup_dir_rename_info(&info, dirs_removed, dir_rename_count != NULL);
1709
0
  FREE_AND_NULL(rename_dst);
1710
0
  rename_dst_nr = rename_dst_alloc = 0;
1711
0
  FREE_AND_NULL(rename_src);
1712
0
  rename_src_nr = rename_src_alloc = 0;
1713
0
  if (break_idx) {
1714
0
    strintmap_clear(break_idx);
1715
0
    FREE_AND_NULL(break_idx);
1716
0
  }
1717
0
  trace2_region_leave("diff", "write back to queue", options->repo);
1718
0
  return;
1719
0
}
1720
1721
void diffcore_rename(struct diff_options *options)
1722
0
{
1723
0
  diffcore_rename_extended(options, NULL, NULL, NULL, NULL, NULL);
1724
0
}