@@ -864,6 +864,21 @@ static void get_renamed_dir_portion(const char *old_path, const char *new_path,
*new_dir = xstrndup(new_path, end_of_new - new_path);
}
+/*
+ * See if there is a directory rename for path, and if there are any file
+ * level conflicts on the given side for the renamed location. If there is
+ * a rename and there are no conflicts, return the new name. Otherwise,
+ * return NULL.
+ */
+static char *handle_path_level_conflicts(struct merge_options *opt,
+ const char *path,
+ unsigned side_index,
+ struct strmap_entry *rename_info,
+ struct strmap *collisions)
+{
+ die("Not yet implemented");
+}
+
static void increment_count(struct strmap *dir_rename_count,
char *old_dir,
char *new_dir)
@@ -1079,7 +1094,57 @@ static char *check_for_directory_rename(struct merge_options *opt,
struct strmap *collisions,
int *clean_merge)
{
- die("Not yet implemented.");
+ char *new_path = NULL;
+ struct strmap_entry *rename_info;
+ struct strmap_entry *otherinfo = NULL;
+ const char *new_dir;
+
+ if (strmap_empty(dir_renames))
+ return new_path;
+ rename_info = check_dir_renamed(path, dir_renames);
+ if (!rename_info)
+ return new_path;
+ /* old_dir = rename_info->key; */
+ new_dir = rename_info->value;
+
+ /*
+ * This next part is a little weird. We do not want to do an
+ * implicit rename into a directory we renamed on our side, because
+ * that will result in a spurious rename/rename(1to2) conflict. An
+ * example:
+ * Base commit: dumbdir/afile, otherdir/bfile
+ * Side 1: smrtdir/afile, otherdir/bfile
+ * Side 2: dumbdir/afile, dumbdir/bfile
+ * Here, while working on Side 1, we could notice that otherdir was
+ * renamed/merged to dumbdir, and change the diff_filepair for
+ * otherdir/bfile into a rename into dumbdir/bfile. However, Side
+ * 2 will notice the rename from dumbdir to smrtdir, and do the
+ * transitive rename to move it from dumbdir/bfile to
+ * smrtdir/bfile. That gives us bfile in dumbdir vs being in
+ * smrtdir, a rename/rename(1to2) conflict. We really just want
+ * the file to end up in smrtdir. And the way to achieve that is
+ * to not let Side1 do the rename to dumbdir, since we know that is
+ * the source of one of our directory renames.
+ *
+ * That's why otherinfo and dir_rename_exclusions is here.
+ *
+ * As it turns out, this also prevents N-way transient rename
+ * confusion; See testcases 9c and 9d of t6043.
+ */
+ otherinfo = strmap_get_entry(dir_rename_exclusions, new_dir);
+ if (otherinfo) {
+ path_msg(opt, rename_info->key, 1,
+ _("WARNING: Avoiding applying %s -> %s rename "
+ "to %s, because %s itself was renamed."),
+ rename_info->key, new_dir, path, new_dir);
+ return NULL;
+ }
+
+ new_path = handle_path_level_conflicts(opt, path, side_index,
+ rename_info, collisions);
+ *clean_merge &= (new_path != NULL);
+
+ return new_path;
}
static void apply_directory_rename_modifications(struct merge_options *opt,