@@ -864,6 +864,21 @@ static void get_renamed_dir_portion(const char *old_path, const char *new_path,
864
864
* new_dir = xstrndup (new_path , end_of_new - new_path );
865
865
}
866
866
867
+ /*
868
+ * See if there is a directory rename for path, and if there are any file
869
+ * level conflicts on the given side for the renamed location. If there is
870
+ * a rename and there are no conflicts, return the new name. Otherwise,
871
+ * return NULL.
872
+ */
873
+ static char * handle_path_level_conflicts (struct merge_options * opt ,
874
+ const char * path ,
875
+ unsigned side_index ,
876
+ struct strmap_entry * rename_info ,
877
+ struct strmap * collisions )
878
+ {
879
+ die ("Not yet implemented" );
880
+ }
881
+
867
882
static void increment_count (struct strmap * dir_rename_count ,
868
883
char * old_dir ,
869
884
char * new_dir )
@@ -1078,7 +1093,57 @@ static char *check_for_directory_rename(struct merge_options *opt,
1078
1093
struct strmap * collisions ,
1079
1094
int * clean_merge )
1080
1095
{
1081
- die ("Not yet implemented." );
1096
+ char * new_path = NULL ;
1097
+ struct strmap_entry * rename_info ;
1098
+ struct strmap_entry * otherinfo = NULL ;
1099
+ const char * new_dir ;
1100
+
1101
+ if (strmap_empty (dir_renames ))
1102
+ return new_path ;
1103
+ rename_info = check_dir_renamed (path , dir_renames );
1104
+ if (!rename_info )
1105
+ return new_path ;
1106
+ /* old_dir = rename_info->key; */
1107
+ new_dir = rename_info -> value ;
1108
+
1109
+ /*
1110
+ * This next part is a little weird. We do not want to do an
1111
+ * implicit rename into a directory we renamed on our side, because
1112
+ * that will result in a spurious rename/rename(1to2) conflict. An
1113
+ * example:
1114
+ * Base commit: dumbdir/afile, otherdir/bfile
1115
+ * Side 1: smrtdir/afile, otherdir/bfile
1116
+ * Side 2: dumbdir/afile, dumbdir/bfile
1117
+ * Here, while working on Side 1, we could notice that otherdir was
1118
+ * renamed/merged to dumbdir, and change the diff_filepair for
1119
+ * otherdir/bfile into a rename into dumbdir/bfile. However, Side
1120
+ * 2 will notice the rename from dumbdir to smrtdir, and do the
1121
+ * transitive rename to move it from dumbdir/bfile to
1122
+ * smrtdir/bfile. That gives us bfile in dumbdir vs being in
1123
+ * smrtdir, a rename/rename(1to2) conflict. We really just want
1124
+ * the file to end up in smrtdir. And the way to achieve that is
1125
+ * to not let Side1 do the rename to dumbdir, since we know that is
1126
+ * the source of one of our directory renames.
1127
+ *
1128
+ * That's why otherinfo and dir_rename_exclusions is here.
1129
+ *
1130
+ * As it turns out, this also prevents N-way transient rename
1131
+ * confusion; See testcases 9c and 9d of t6043.
1132
+ */
1133
+ otherinfo = strmap_get_entry (dir_rename_exclusions , new_dir );
1134
+ if (otherinfo ) {
1135
+ path_msg (opt , rename_info -> key , 1 ,
1136
+ _ ("WARNING: Avoiding applying %s -> %s rename "
1137
+ "to %s, because %s itself was renamed." ),
1138
+ rename_info -> key , new_dir , path , new_dir );
1139
+ return NULL ;
1140
+ }
1141
+
1142
+ new_path = handle_path_level_conflicts (opt , path , side_index ,
1143
+ rename_info , collisions );
1144
+ * clean_merge &= (new_path != NULL );
1145
+
1146
+ return new_path ;
1082
1147
}
1083
1148
1084
1149
static void apply_directory_rename_modifications (struct merge_options * opt ,
0 commit comments