Skip to content

Commit e242e95

Browse files
committed
merge-ort: record the reason that we want a rename for a diretory
When a directory is removed on one side of history, and a new file is added to that directory on the other side of history, we need to detect a potential rename of the directory so that the new file can be moved to the right directory. However, diffcore-rename can take advantage of the difference between whether the current directory had a new file added or only some ancestor of the current directory had a new file added. (And, obviously, can take advantage of whether neither the current directory nor any ancestor had a new file added to it.) Save this extra information in dirs_removed. Signed-off-by: Elijah Newren <[email protected]>
1 parent 5cc59e9 commit e242e95

File tree

3 files changed

+45
-4
lines changed

3 files changed

+45
-4
lines changed

diffcore-rename.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,7 @@ static void cleanup_dir_rename_info(struct dir_rename_info *info,
667667
const char *source_dir = entry->key;
668668
struct strintmap *counts = entry->value;
669669

670-
if (!strintmap_contains(dirs_removed, source_dir)) {
670+
if (!strintmap_get(dirs_removed, source_dir)) {
671671
string_list_append(&to_remove, source_dir);
672672
strintmap_clear(counts);
673673
continue;

diffcore.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,12 @@ enum file_rename_relevance {
167167
RELEVANT_CONTENT = 1,
168168
RELEVANT_LOCATION = 2
169169
};
170+
/* dir_rename_relevance: the reason we want rename information for a dir */
171+
enum dir_rename_relevance {
172+
NOT_RELEVANT = 0,
173+
RELEVANT_FOR_ANCESTOR = 1,
174+
RELEVANT_FOR_SELF = 2
175+
};
170176
void partial_clear_dir_rename_count(struct strmap *dir_rename_count);
171177

172178
void diffcore_break(struct repository *, int);

merge-ort.c

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ struct rename_info {
7373

7474
/*
7575
* dirs_removed: directories removed on a given side of history.
76+
*
77+
* The keys of dirs_removed[side] are the directories that were removed
78+
* on the given side of history. The value of the strintmap for each
79+
* directory is a value from enum dir_rename_relevance.
7680
*/
7781
struct strintmap dirs_removed[3];
7882

@@ -735,10 +739,41 @@ static void collect_rename_info(struct merge_options *opt,
735739
if (dirmask == 1 || dirmask == 3 || dirmask == 5) {
736740
/* absent_mask = 0x07 - dirmask; sides = absent_mask/2 */
737741
unsigned sides = (0x07 - dirmask)/2;
742+
unsigned relevance = (renames->dir_rename_mask == 0x07) ?
743+
RELEVANT_FOR_ANCESTOR : NOT_RELEVANT;
744+
/*
745+
* Record relevance of this directory. However, note that
746+
* when collect_merge_info_callback() recurses into this
747+
* directory and calls collect_rename_info() on paths
748+
* within that directory, if we find a path that was added
749+
* to this directory on the other side of history, we will
750+
* upgrade this value to RELEVANT_FOR_SELF; see below.
751+
*/
738752
if (sides & 1)
739-
strintmap_set(&renames->dirs_removed[1], fullname, 1);
753+
strintmap_set(&renames->dirs_removed[1], fullname,
754+
relevance);
740755
if (sides & 2)
741-
strintmap_set(&renames->dirs_removed[2], fullname, 1);
756+
strintmap_set(&renames->dirs_removed[2], fullname,
757+
relevance);
758+
}
759+
760+
/*
761+
* Here's the block that potentially upgrades to RELEVANT_FOR_SELF.
762+
* When we run across a file added to a directory. In such a case,
763+
* find the directory of the file and upgrade its relevance.
764+
*/
765+
if (renames->dir_rename_mask == 0x07 &&
766+
(filemask == 2 || filemask == 4)) {
767+
/*
768+
* Need directory rename for parent directory on other side
769+
* of history from added file. Thus
770+
* side = (~filemask & 0x06) >> 1
771+
* or
772+
* side = 3 - (filemask/2).
773+
*/
774+
unsigned side = 3 - (filemask >> 1);
775+
strintmap_set(&renames->dirs_removed[side], dirname,
776+
RELEVANT_FOR_SELF);
742777
}
743778

744779
if (filemask == 0 || filemask == 7)
@@ -3453,7 +3488,7 @@ static void merge_start(struct merge_options *opt, struct merge_result *result)
34533488
renames = &opt->priv->renames;
34543489
for (i = MERGE_SIDE1; i <= MERGE_SIDE2; i++) {
34553490
strintmap_init_with_options(&renames->dirs_removed[i],
3456-
0, NULL, 0);
3491+
NOT_RELEVANT, NULL, 0);
34573492
strmap_init_with_options(&renames->dir_rename_count[i],
34583493
NULL, 1);
34593494
strmap_init_with_options(&renames->dir_renames[i],

0 commit comments

Comments
 (0)