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 <dstolee@microsoft.com> Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
ae8cf74d3f
commit
0c4fd732f0
@ -380,6 +380,129 @@ static char *get_dirname(const char *filename)
|
|||||||
return slash ? xstrndup(filename, slash - filename) : xstrdup("");
|
return slash ? xstrndup(filename, slash - filename) : xstrdup("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dirname_munge(char *filename)
|
||||||
|
{
|
||||||
|
char *slash = strrchr(filename, '/');
|
||||||
|
if (!slash)
|
||||||
|
slash = filename;
|
||||||
|
*slash = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void increment_count(struct strmap *dir_rename_count,
|
||||||
|
char *old_dir,
|
||||||
|
char *new_dir)
|
||||||
|
{
|
||||||
|
struct strintmap *counts;
|
||||||
|
struct strmap_entry *e;
|
||||||
|
|
||||||
|
/* Get the {new_dirs -> counts} mapping using old_dir */
|
||||||
|
e = strmap_get_entry(dir_rename_count, old_dir);
|
||||||
|
if (e) {
|
||||||
|
counts = e->value;
|
||||||
|
} else {
|
||||||
|
counts = xmalloc(sizeof(*counts));
|
||||||
|
strintmap_init_with_options(counts, 0, NULL, 1);
|
||||||
|
strmap_put(dir_rename_count, old_dir, counts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increment the count for new_dir */
|
||||||
|
strintmap_incr(counts, new_dir, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_dir_rename_counts(struct strmap *dir_rename_count,
|
||||||
|
struct strset *dirs_removed,
|
||||||
|
const char *oldname,
|
||||||
|
const char *newname)
|
||||||
|
{
|
||||||
|
char *old_dir = xstrdup(oldname);
|
||||||
|
char *new_dir = xstrdup(newname);
|
||||||
|
char new_dir_first_char = new_dir[0];
|
||||||
|
int first_time_in_loop = 1;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
dirname_munge(old_dir);
|
||||||
|
dirname_munge(new_dir);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When renaming
|
||||||
|
* "a/b/c/d/e/foo.c" -> "a/b/some/thing/else/e/foo.c"
|
||||||
|
* then this suggests that both
|
||||||
|
* a/b/c/d/e/ => a/b/some/thing/else/e/
|
||||||
|
* a/b/c/d/ => a/b/some/thing/else/
|
||||||
|
* so we want to increment counters for both. We do NOT,
|
||||||
|
* however, also want to suggest that there was the following
|
||||||
|
* rename:
|
||||||
|
* a/b/c/ => a/b/some/thing/
|
||||||
|
* so we need to quit at that point.
|
||||||
|
*
|
||||||
|
* Note the when first_time_in_loop, we only strip off the
|
||||||
|
* basename, and we don't care if that's different.
|
||||||
|
*/
|
||||||
|
if (!first_time_in_loop) {
|
||||||
|
char *old_sub_dir = strchr(old_dir, '\0')+1;
|
||||||
|
char *new_sub_dir = strchr(new_dir, '\0')+1;
|
||||||
|
if (!*new_dir) {
|
||||||
|
/*
|
||||||
|
* Special case when renaming to root directory,
|
||||||
|
* i.e. when new_dir == "". In this case, we had
|
||||||
|
* something like
|
||||||
|
* a/b/subdir => subdir
|
||||||
|
* and so dirname_munge() sets things up so that
|
||||||
|
* old_dir = "a/b\0subdir\0"
|
||||||
|
* new_dir = "\0ubdir\0"
|
||||||
|
* We didn't have a '/' to overwrite a '\0' onto
|
||||||
|
* in new_dir, so we have to compare differently.
|
||||||
|
*/
|
||||||
|
if (new_dir_first_char != old_sub_dir[0] ||
|
||||||
|
strcmp(old_sub_dir+1, new_sub_dir))
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (strcmp(old_sub_dir, new_sub_dir))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strset_contains(dirs_removed, old_dir))
|
||||||
|
increment_count(dir_rename_count, old_dir, new_dir);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* If we hit toplevel directory ("") for old or new dir, quit */
|
||||||
|
if (!*old_dir || !*new_dir)
|
||||||
|
break;
|
||||||
|
|
||||||
|
first_time_in_loop = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free resources we don't need anymore */
|
||||||
|
free(old_dir);
|
||||||
|
free(new_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void compute_dir_rename_counts(struct strmap *dir_rename_count,
|
||||||
|
struct strset *dirs_removed)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Set up dir_rename_count */
|
||||||
|
for (i = 0; i < rename_dst_nr; ++i) {
|
||||||
|
/* File not part of directory rename counts if not a rename */
|
||||||
|
if (!rename_dst[i].is_rename)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make dir_rename_count contain a map of a map:
|
||||||
|
* old_directory -> {new_directory -> count}
|
||||||
|
* In other words, for every pair look at the directories for
|
||||||
|
* the old filename and the new filename and count how many
|
||||||
|
* times that pairing occurs.
|
||||||
|
*/
|
||||||
|
update_dir_rename_counts(dir_rename_count, dirs_removed,
|
||||||
|
rename_dst[i].p->one->path,
|
||||||
|
rename_dst[i].p->two->path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void initialize_dir_rename_info(struct dir_rename_info *info)
|
static void initialize_dir_rename_info(struct dir_rename_info *info)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -790,7 +913,9 @@ static void remove_unneeded_paths_from_src(int detecting_copies)
|
|||||||
rename_src_nr = new_num_src;
|
rename_src_nr = new_num_src;
|
||||||
}
|
}
|
||||||
|
|
||||||
void diffcore_rename(struct diff_options *options)
|
void diffcore_rename_extended(struct diff_options *options,
|
||||||
|
struct strset *dirs_removed,
|
||||||
|
struct strmap *dir_rename_count)
|
||||||
{
|
{
|
||||||
int detect_rename = options->detect_rename;
|
int detect_rename = options->detect_rename;
|
||||||
int minimum_score = options->rename_score;
|
int minimum_score = options->rename_score;
|
||||||
@ -805,6 +930,7 @@ void diffcore_rename(struct diff_options *options)
|
|||||||
|
|
||||||
trace2_region_enter("diff", "setup", options->repo);
|
trace2_region_enter("diff", "setup", options->repo);
|
||||||
info.setup = 0;
|
info.setup = 0;
|
||||||
|
assert(!dir_rename_count || strmap_empty(dir_rename_count));
|
||||||
want_copies = (detect_rename == DIFF_DETECT_COPY);
|
want_copies = (detect_rename == DIFF_DETECT_COPY);
|
||||||
if (!minimum_score)
|
if (!minimum_score)
|
||||||
minimum_score = DEFAULT_RENAME_SCORE;
|
minimum_score = DEFAULT_RENAME_SCORE;
|
||||||
@ -999,6 +1125,11 @@ void diffcore_rename(struct diff_options *options)
|
|||||||
trace2_region_leave("diff", "inexact renames", options->repo);
|
trace2_region_leave("diff", "inexact renames", options->repo);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
/*
|
||||||
|
* Now that renames have been computed, compute dir_rename_count */
|
||||||
|
if (dirs_removed && dir_rename_count)
|
||||||
|
compute_dir_rename_counts(dir_rename_count, dirs_removed);
|
||||||
|
|
||||||
/* At this point, we have found some renames and copies and they
|
/* At this point, we have found some renames and copies and they
|
||||||
* are recorded in rename_dst. The original list is still in *q.
|
* are recorded in rename_dst. The original list is still in *q.
|
||||||
*/
|
*/
|
||||||
@ -1082,3 +1213,8 @@ void diffcore_rename(struct diff_options *options)
|
|||||||
trace2_region_leave("diff", "write back to queue", options->repo);
|
trace2_region_leave("diff", "write back to queue", options->repo);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void diffcore_rename(struct diff_options *options)
|
||||||
|
{
|
||||||
|
diffcore_rename_extended(options, NULL, NULL);
|
||||||
|
}
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
struct diff_options;
|
struct diff_options;
|
||||||
struct repository;
|
struct repository;
|
||||||
|
struct strmap;
|
||||||
|
struct strset;
|
||||||
struct userdiff_driver;
|
struct userdiff_driver;
|
||||||
|
|
||||||
/* This header file is internal between diff.c and its diff transformers
|
/* 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 *);
|
|||||||
|
|
||||||
void diffcore_break(struct repository *, int);
|
void diffcore_break(struct repository *, int);
|
||||||
void diffcore_rename(struct diff_options *);
|
void diffcore_rename(struct diff_options *);
|
||||||
|
void diffcore_rename_extended(struct diff_options *options,
|
||||||
|
struct strset *dirs_removed,
|
||||||
|
struct strmap *dir_rename_count);
|
||||||
void diffcore_merge_broken(void);
|
void diffcore_merge_broken(void);
|
||||||
void diffcore_pickaxe(struct diff_options *);
|
void diffcore_pickaxe(struct diff_options *);
|
||||||
void diffcore_order(const char *orderfile);
|
void diffcore_order(const char *orderfile);
|
||||||
|
132
merge-ort.c
132
merge-ort.c
@ -1302,131 +1302,6 @@ static char *handle_path_level_conflicts(struct merge_options *opt,
|
|||||||
return new_path;
|
return new_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dirname_munge(char *filename)
|
|
||||||
{
|
|
||||||
char *slash = strrchr(filename, '/');
|
|
||||||
if (!slash)
|
|
||||||
slash = filename;
|
|
||||||
*slash = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static void increment_count(struct strmap *dir_rename_count,
|
|
||||||
char *old_dir,
|
|
||||||
char *new_dir)
|
|
||||||
{
|
|
||||||
struct strintmap *counts;
|
|
||||||
struct strmap_entry *e;
|
|
||||||
|
|
||||||
/* Get the {new_dirs -> counts} mapping using old_dir */
|
|
||||||
e = strmap_get_entry(dir_rename_count, old_dir);
|
|
||||||
if (e) {
|
|
||||||
counts = e->value;
|
|
||||||
} else {
|
|
||||||
counts = xmalloc(sizeof(*counts));
|
|
||||||
strintmap_init_with_options(counts, 0, NULL, 1);
|
|
||||||
strmap_put(dir_rename_count, old_dir, counts);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Increment the count for new_dir */
|
|
||||||
strintmap_incr(counts, new_dir, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_dir_rename_counts(struct strmap *dir_rename_count,
|
|
||||||
struct strset *dirs_removed,
|
|
||||||
const char *oldname,
|
|
||||||
const char *newname)
|
|
||||||
{
|
|
||||||
char *old_dir = xstrdup(oldname);
|
|
||||||
char *new_dir = xstrdup(newname);
|
|
||||||
char new_dir_first_char = new_dir[0];
|
|
||||||
int first_time_in_loop = 1;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
dirname_munge(old_dir);
|
|
||||||
dirname_munge(new_dir);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When renaming
|
|
||||||
* "a/b/c/d/e/foo.c" -> "a/b/some/thing/else/e/foo.c"
|
|
||||||
* then this suggests that both
|
|
||||||
* a/b/c/d/e/ => a/b/some/thing/else/e/
|
|
||||||
* a/b/c/d/ => a/b/some/thing/else/
|
|
||||||
* so we want to increment counters for both. We do NOT,
|
|
||||||
* however, also want to suggest that there was the following
|
|
||||||
* rename:
|
|
||||||
* a/b/c/ => a/b/some/thing/
|
|
||||||
* so we need to quit at that point.
|
|
||||||
*
|
|
||||||
* Note the when first_time_in_loop, we only strip off the
|
|
||||||
* basename, and we don't care if that's different.
|
|
||||||
*/
|
|
||||||
if (!first_time_in_loop) {
|
|
||||||
char *old_sub_dir = strchr(old_dir, '\0')+1;
|
|
||||||
char *new_sub_dir = strchr(new_dir, '\0')+1;
|
|
||||||
if (!*new_dir) {
|
|
||||||
/*
|
|
||||||
* Special case when renaming to root directory,
|
|
||||||
* i.e. when new_dir == "". In this case, we had
|
|
||||||
* something like
|
|
||||||
* a/b/subdir => subdir
|
|
||||||
* and so dirname_munge() sets things up so that
|
|
||||||
* old_dir = "a/b\0subdir\0"
|
|
||||||
* new_dir = "\0ubdir\0"
|
|
||||||
* We didn't have a '/' to overwrite a '\0' onto
|
|
||||||
* in new_dir, so we have to compare differently.
|
|
||||||
*/
|
|
||||||
if (new_dir_first_char != old_sub_dir[0] ||
|
|
||||||
strcmp(old_sub_dir+1, new_sub_dir))
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
if (strcmp(old_sub_dir, new_sub_dir))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strset_contains(dirs_removed, old_dir))
|
|
||||||
increment_count(dir_rename_count, old_dir, new_dir);
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* If we hit toplevel directory ("") for old or new dir, quit */
|
|
||||||
if (!*old_dir || !*new_dir)
|
|
||||||
break;
|
|
||||||
|
|
||||||
first_time_in_loop = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free resources we don't need anymore */
|
|
||||||
free(old_dir);
|
|
||||||
free(new_dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void compute_rename_counts(struct diff_queue_struct *pairs,
|
|
||||||
struct strmap *dir_rename_count,
|
|
||||||
struct strset *dirs_removed)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < pairs->nr; ++i) {
|
|
||||||
struct diff_filepair *pair = pairs->queue[i];
|
|
||||||
|
|
||||||
/* File not part of directory rename if it wasn't renamed */
|
|
||||||
if (pair->status != 'R')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make dir_rename_count contain a map of a map:
|
|
||||||
* old_directory -> {new_directory -> count}
|
|
||||||
* In other words, for every pair look at the directories for
|
|
||||||
* the old filename and the new filename and count how many
|
|
||||||
* times that pairing occurs.
|
|
||||||
*/
|
|
||||||
update_dir_rename_counts(dir_rename_count, dirs_removed,
|
|
||||||
pair->one->path,
|
|
||||||
pair->two->path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void get_provisional_directory_renames(struct merge_options *opt,
|
static void get_provisional_directory_renames(struct merge_options *opt,
|
||||||
unsigned side,
|
unsigned side,
|
||||||
int *clean)
|
int *clean)
|
||||||
@ -1435,9 +1310,6 @@ static void get_provisional_directory_renames(struct merge_options *opt,
|
|||||||
struct strmap_entry *entry;
|
struct strmap_entry *entry;
|
||||||
struct rename_info *renames = &opt->priv->renames;
|
struct rename_info *renames = &opt->priv->renames;
|
||||||
|
|
||||||
compute_rename_counts(&renames->pairs[side],
|
|
||||||
&renames->dir_rename_count[side],
|
|
||||||
&renames->dirs_removed[side]);
|
|
||||||
/*
|
/*
|
||||||
* Collapse
|
* Collapse
|
||||||
* dir_rename_count: old_directory -> {new_directory -> count}
|
* dir_rename_count: old_directory -> {new_directory -> count}
|
||||||
@ -2162,7 +2034,9 @@ static void detect_regular_renames(struct merge_options *opt,
|
|||||||
|
|
||||||
diff_queued_diff = renames->pairs[side_index];
|
diff_queued_diff = renames->pairs[side_index];
|
||||||
trace2_region_enter("diff", "diffcore_rename", opt->repo);
|
trace2_region_enter("diff", "diffcore_rename", opt->repo);
|
||||||
diffcore_rename(&diff_opts);
|
diffcore_rename_extended(&diff_opts,
|
||||||
|
&renames->dirs_removed[side_index],
|
||||||
|
&renames->dir_rename_count[side_index]);
|
||||||
trace2_region_leave("diff", "diffcore_rename", opt->repo);
|
trace2_region_leave("diff", "diffcore_rename", opt->repo);
|
||||||
resolve_diffpair_statuses(&diff_queued_diff);
|
resolve_diffpair_statuses(&diff_queued_diff);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user