Skip to content

Commit 0c4fd73

Browse files
newrengitster
authored andcommitted
Move computation of dir_rename_count from merge-ort to diffcore-rename
Move the computation of dir_rename_count from merge-ort.c to diffcore-rename.c, making slight adjustments to the data structures based on the move. While the diffstat looks large, viewing this commit with --color-moved makes it clear that only about 20 lines changed. With this patch, the computation of dir_rename_count is still only done after inexact rename detection, but subsequent commits will add a preliminary computation of dir_rename_count after exact rename detection, followed by some updates after inexact rename detection. Reviewed-by: Derrick Stolee <[email protected]> Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent ae8cf74 commit 0c4fd73

File tree

3 files changed

+145
-130
lines changed

3 files changed

+145
-130
lines changed

diffcore-rename.c

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,129 @@ static char *get_dirname(const char *filename)
380380
return slash ? xstrndup(filename, slash - filename) : xstrdup("");
381381
}
382382

383+
static void dirname_munge(char *filename)
384+
{
385+
char *slash = strrchr(filename, '/');
386+
if (!slash)
387+
slash = filename;
388+
*slash = '\0';
389+
}
390+
391+
static void increment_count(struct strmap *dir_rename_count,
392+
char *old_dir,
393+
char *new_dir)
394+
{
395+
struct strintmap *counts;
396+
struct strmap_entry *e;
397+
398+
/* Get the {new_dirs -> counts} mapping using old_dir */
399+
e = strmap_get_entry(dir_rename_count, old_dir);
400+
if (e) {
401+
counts = e->value;
402+
} else {
403+
counts = xmalloc(sizeof(*counts));
404+
strintmap_init_with_options(counts, 0, NULL, 1);
405+
strmap_put(dir_rename_count, old_dir, counts);
406+
}
407+
408+
/* Increment the count for new_dir */
409+
strintmap_incr(counts, new_dir, 1);
410+
}
411+
412+
static void update_dir_rename_counts(struct strmap *dir_rename_count,
413+
struct strset *dirs_removed,
414+
const char *oldname,
415+
const char *newname)
416+
{
417+
char *old_dir = xstrdup(oldname);
418+
char *new_dir = xstrdup(newname);
419+
char new_dir_first_char = new_dir[0];
420+
int first_time_in_loop = 1;
421+
422+
while (1) {
423+
dirname_munge(old_dir);
424+
dirname_munge(new_dir);
425+
426+
/*
427+
* When renaming
428+
* "a/b/c/d/e/foo.c" -> "a/b/some/thing/else/e/foo.c"
429+
* then this suggests that both
430+
* a/b/c/d/e/ => a/b/some/thing/else/e/
431+
* a/b/c/d/ => a/b/some/thing/else/
432+
* so we want to increment counters for both. We do NOT,
433+
* however, also want to suggest that there was the following
434+
* rename:
435+
* a/b/c/ => a/b/some/thing/
436+
* so we need to quit at that point.
437+
*
438+
* Note the when first_time_in_loop, we only strip off the
439+
* basename, and we don't care if that's different.
440+
*/
441+
if (!first_time_in_loop) {
442+
char *old_sub_dir = strchr(old_dir, '\0')+1;
443+
char *new_sub_dir = strchr(new_dir, '\0')+1;
444+
if (!*new_dir) {
445+
/*
446+
* Special case when renaming to root directory,
447+
* i.e. when new_dir == "". In this case, we had
448+
* something like
449+
* a/b/subdir => subdir
450+
* and so dirname_munge() sets things up so that
451+
* old_dir = "a/b\0subdir\0"
452+
* new_dir = "\0ubdir\0"
453+
* We didn't have a '/' to overwrite a '\0' onto
454+
* in new_dir, so we have to compare differently.
455+
*/
456+
if (new_dir_first_char != old_sub_dir[0] ||
457+
strcmp(old_sub_dir+1, new_sub_dir))
458+
break;
459+
} else {
460+
if (strcmp(old_sub_dir, new_sub_dir))
461+
break;
462+
}
463+
}
464+
465+
if (strset_contains(dirs_removed, old_dir))
466+
increment_count(dir_rename_count, old_dir, new_dir);
467+
else
468+
break;
469+
470+
/* If we hit toplevel directory ("") for old or new dir, quit */
471+
if (!*old_dir || !*new_dir)
472+
break;
473+
474+
first_time_in_loop = 0;
475+
}
476+
477+
/* Free resources we don't need anymore */
478+
free(old_dir);
479+
free(new_dir);
480+
}
481+
482+
static void compute_dir_rename_counts(struct strmap *dir_rename_count,
483+
struct strset *dirs_removed)
484+
{
485+
int i;
486+
487+
/* Set up dir_rename_count */
488+
for (i = 0; i < rename_dst_nr; ++i) {
489+
/* File not part of directory rename counts if not a rename */
490+
if (!rename_dst[i].is_rename)
491+
continue;
492+
493+
/*
494+
* Make dir_rename_count contain a map of a map:
495+
* old_directory -> {new_directory -> count}
496+
* In other words, for every pair look at the directories for
497+
* the old filename and the new filename and count how many
498+
* times that pairing occurs.
499+
*/
500+
update_dir_rename_counts(dir_rename_count, dirs_removed,
501+
rename_dst[i].p->one->path,
502+
rename_dst[i].p->two->path);
503+
}
504+
}
505+
383506
static void initialize_dir_rename_info(struct dir_rename_info *info)
384507
{
385508
int i;
@@ -790,7 +913,9 @@ static void remove_unneeded_paths_from_src(int detecting_copies)
790913
rename_src_nr = new_num_src;
791914
}
792915

793-
void diffcore_rename(struct diff_options *options)
916+
void diffcore_rename_extended(struct diff_options *options,
917+
struct strset *dirs_removed,
918+
struct strmap *dir_rename_count)
794919
{
795920
int detect_rename = options->detect_rename;
796921
int minimum_score = options->rename_score;
@@ -805,6 +930,7 @@ void diffcore_rename(struct diff_options *options)
805930

806931
trace2_region_enter("diff", "setup", options->repo);
807932
info.setup = 0;
933+
assert(!dir_rename_count || strmap_empty(dir_rename_count));
808934
want_copies = (detect_rename == DIFF_DETECT_COPY);
809935
if (!minimum_score)
810936
minimum_score = DEFAULT_RENAME_SCORE;
@@ -999,6 +1125,11 @@ void diffcore_rename(struct diff_options *options)
9991125
trace2_region_leave("diff", "inexact renames", options->repo);
10001126

10011127
cleanup:
1128+
/*
1129+
* Now that renames have been computed, compute dir_rename_count */
1130+
if (dirs_removed && dir_rename_count)
1131+
compute_dir_rename_counts(dir_rename_count, dirs_removed);
1132+
10021133
/* At this point, we have found some renames and copies and they
10031134
* are recorded in rename_dst. The original list is still in *q.
10041135
*/
@@ -1082,3 +1213,8 @@ void diffcore_rename(struct diff_options *options)
10821213
trace2_region_leave("diff", "write back to queue", options->repo);
10831214
return;
10841215
}
1216+
1217+
void diffcore_rename(struct diff_options *options)
1218+
{
1219+
diffcore_rename_extended(options, NULL, NULL);
1220+
}

diffcore.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
struct diff_options;
1010
struct repository;
11+
struct strmap;
12+
struct strset;
1113
struct userdiff_driver;
1214

1315
/* This header file is internal between diff.c and its diff transformers
@@ -161,6 +163,9 @@ void diff_q(struct diff_queue_struct *, struct diff_filepair *);
161163

162164
void diffcore_break(struct repository *, int);
163165
void diffcore_rename(struct diff_options *);
166+
void diffcore_rename_extended(struct diff_options *options,
167+
struct strset *dirs_removed,
168+
struct strmap *dir_rename_count);
164169
void diffcore_merge_broken(void);
165170
void diffcore_pickaxe(struct diff_options *);
166171
void diffcore_order(const char *orderfile);

merge-ort.c

Lines changed: 3 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,131 +1302,6 @@ static char *handle_path_level_conflicts(struct merge_options *opt,
13021302
return new_path;
13031303
}
13041304

1305-
static void dirname_munge(char *filename)
1306-
{
1307-
char *slash = strrchr(filename, '/');
1308-
if (!slash)
1309-
slash = filename;
1310-
*slash = '\0';
1311-
}
1312-
1313-
static void increment_count(struct strmap *dir_rename_count,
1314-
char *old_dir,
1315-
char *new_dir)
1316-
{
1317-
struct strintmap *counts;
1318-
struct strmap_entry *e;
1319-
1320-
/* Get the {new_dirs -> counts} mapping using old_dir */
1321-
e = strmap_get_entry(dir_rename_count, old_dir);
1322-
if (e) {
1323-
counts = e->value;
1324-
} else {
1325-
counts = xmalloc(sizeof(*counts));
1326-
strintmap_init_with_options(counts, 0, NULL, 1);
1327-
strmap_put(dir_rename_count, old_dir, counts);
1328-
}
1329-
1330-
/* Increment the count for new_dir */
1331-
strintmap_incr(counts, new_dir, 1);
1332-
}
1333-
1334-
static void update_dir_rename_counts(struct strmap *dir_rename_count,
1335-
struct strset *dirs_removed,
1336-
const char *oldname,
1337-
const char *newname)
1338-
{
1339-
char *old_dir = xstrdup(oldname);
1340-
char *new_dir = xstrdup(newname);
1341-
char new_dir_first_char = new_dir[0];
1342-
int first_time_in_loop = 1;
1343-
1344-
while (1) {
1345-
dirname_munge(old_dir);
1346-
dirname_munge(new_dir);
1347-
1348-
/*
1349-
* When renaming
1350-
* "a/b/c/d/e/foo.c" -> "a/b/some/thing/else/e/foo.c"
1351-
* then this suggests that both
1352-
* a/b/c/d/e/ => a/b/some/thing/else/e/
1353-
* a/b/c/d/ => a/b/some/thing/else/
1354-
* so we want to increment counters for both. We do NOT,
1355-
* however, also want to suggest that there was the following
1356-
* rename:
1357-
* a/b/c/ => a/b/some/thing/
1358-
* so we need to quit at that point.
1359-
*
1360-
* Note the when first_time_in_loop, we only strip off the
1361-
* basename, and we don't care if that's different.
1362-
*/
1363-
if (!first_time_in_loop) {
1364-
char *old_sub_dir = strchr(old_dir, '\0')+1;
1365-
char *new_sub_dir = strchr(new_dir, '\0')+1;
1366-
if (!*new_dir) {
1367-
/*
1368-
* Special case when renaming to root directory,
1369-
* i.e. when new_dir == "". In this case, we had
1370-
* something like
1371-
* a/b/subdir => subdir
1372-
* and so dirname_munge() sets things up so that
1373-
* old_dir = "a/b\0subdir\0"
1374-
* new_dir = "\0ubdir\0"
1375-
* We didn't have a '/' to overwrite a '\0' onto
1376-
* in new_dir, so we have to compare differently.
1377-
*/
1378-
if (new_dir_first_char != old_sub_dir[0] ||
1379-
strcmp(old_sub_dir+1, new_sub_dir))
1380-
break;
1381-
} else {
1382-
if (strcmp(old_sub_dir, new_sub_dir))
1383-
break;
1384-
}
1385-
}
1386-
1387-
if (strset_contains(dirs_removed, old_dir))
1388-
increment_count(dir_rename_count, old_dir, new_dir);
1389-
else
1390-
break;
1391-
1392-
/* If we hit toplevel directory ("") for old or new dir, quit */
1393-
if (!*old_dir || !*new_dir)
1394-
break;
1395-
1396-
first_time_in_loop = 0;
1397-
}
1398-
1399-
/* Free resources we don't need anymore */
1400-
free(old_dir);
1401-
free(new_dir);
1402-
}
1403-
1404-
static void compute_rename_counts(struct diff_queue_struct *pairs,
1405-
struct strmap *dir_rename_count,
1406-
struct strset *dirs_removed)
1407-
{
1408-
int i;
1409-
1410-
for (i = 0; i < pairs->nr; ++i) {
1411-
struct diff_filepair *pair = pairs->queue[i];
1412-
1413-
/* File not part of directory rename if it wasn't renamed */
1414-
if (pair->status != 'R')
1415-
continue;
1416-
1417-
/*
1418-
* Make dir_rename_count contain a map of a map:
1419-
* old_directory -> {new_directory -> count}
1420-
* In other words, for every pair look at the directories for
1421-
* the old filename and the new filename and count how many
1422-
* times that pairing occurs.
1423-
*/
1424-
update_dir_rename_counts(dir_rename_count, dirs_removed,
1425-
pair->one->path,
1426-
pair->two->path);
1427-
}
1428-
}
1429-
14301305
static void get_provisional_directory_renames(struct merge_options *opt,
14311306
unsigned side,
14321307
int *clean)
@@ -1435,9 +1310,6 @@ static void get_provisional_directory_renames(struct merge_options *opt,
14351310
struct strmap_entry *entry;
14361311
struct rename_info *renames = &opt->priv->renames;
14371312

1438-
compute_rename_counts(&renames->pairs[side],
1439-
&renames->dir_rename_count[side],
1440-
&renames->dirs_removed[side]);
14411313
/*
14421314
* Collapse
14431315
* dir_rename_count: old_directory -> {new_directory -> count}
@@ -2162,7 +2034,9 @@ static void detect_regular_renames(struct merge_options *opt,
21622034

21632035
diff_queued_diff = renames->pairs[side_index];
21642036
trace2_region_enter("diff", "diffcore_rename", opt->repo);
2165-
diffcore_rename(&diff_opts);
2037+
diffcore_rename_extended(&diff_opts,
2038+
&renames->dirs_removed[side_index],
2039+
&renames->dir_rename_count[side_index]);
21662040
trace2_region_leave("diff", "diffcore_rename", opt->repo);
21672041
resolve_diffpair_statuses(&diff_queued_diff);
21682042

0 commit comments

Comments
 (0)