@@ -1151,6 +1151,26 @@ static int conflict_rename_dir(struct merge_options *o,
11511151{
11521152 const struct diff_filespec * dest = pair -> two ;
11531153
1154+ if (!o -> call_depth && would_lose_untracked (dest -> path )) {
1155+ char * alt_path = unique_path (o , dest -> path , rename_branch );
1156+
1157+ output (o , 1 , _ ("Error: Refusing to lose untracked file at %s; "
1158+ "writing to %s instead." ),
1159+ dest -> path , alt_path );
1160+ /*
1161+ * Write the file in worktree at alt_path, but not in the
1162+ * index. Instead, write to dest->path for the index but
1163+ * only at the higher appropriate stage.
1164+ */
1165+ if (update_file (o , 0 , & dest -> oid , dest -> mode , alt_path ))
1166+ return -1 ;
1167+ free (alt_path );
1168+ return update_stages (o , dest -> path , NULL ,
1169+ rename_branch == o -> branch1 ? dest : NULL ,
1170+ rename_branch == o -> branch1 ? NULL : dest );
1171+ }
1172+
1173+ /* Update dest->path both in index and in worktree */
11541174 if (update_file (o , 1 , & dest -> oid , dest -> mode , dest -> path ))
11551175 return -1 ;
11561176 return 0 ;
@@ -1169,7 +1189,8 @@ static int handle_change_delete(struct merge_options *o,
11691189 const char * update_path = path ;
11701190 int ret = 0 ;
11711191
1172- if (dir_in_way (path , !o -> call_depth , 0 )) {
1192+ if (dir_in_way (path , !o -> call_depth , 0 ) ||
1193+ (!o -> call_depth && would_lose_untracked (path ))) {
11731194 update_path = alt_path = unique_path (o , path , change_branch );
11741195 }
11751196
@@ -1295,6 +1316,12 @@ static int handle_file(struct merge_options *o,
12951316 dst_name = unique_path (o , rename -> path , cur_branch );
12961317 output (o , 1 , _ ("%s is a directory in %s adding as %s instead" ),
12971318 rename -> path , other_branch , dst_name );
1319+ } else if (!o -> call_depth &&
1320+ would_lose_untracked (rename -> path )) {
1321+ dst_name = unique_path (o , rename -> path , cur_branch );
1322+ output (o , 1 , _ ("Refusing to lose untracked file at %s; "
1323+ "adding as %s instead" ),
1324+ rename -> path , dst_name );
12981325 }
12991326 }
13001327 if ((ret = update_file (o , 0 , & rename -> oid , rename -> mode , dst_name )))
@@ -1420,7 +1447,18 @@ static int conflict_rename_rename_2to1(struct merge_options *o,
14201447 char * new_path2 = unique_path (o , path , ci -> branch2 );
14211448 output (o , 1 , _ ("Renaming %s to %s and %s to %s instead" ),
14221449 a -> path , new_path1 , b -> path , new_path2 );
1423- remove_file (o , 0 , path , 0 );
1450+ if (would_lose_untracked (path ))
1451+ /*
1452+ * Only way we get here is if both renames were from
1453+ * a directory rename AND user had an untracked file
1454+ * at the location where both files end up after the
1455+ * two directory renames. See testcase 10d of t6043.
1456+ */
1457+ output (o , 1 , _ ("Refusing to lose untracked file at "
1458+ "%s, even though it's in the way." ),
1459+ path );
1460+ else
1461+ remove_file (o , 0 , path , 0 );
14241462 ret = update_file (o , 0 , & mfi_c1 .oid , mfi_c1 .mode , new_path1 );
14251463 if (!ret )
14261464 ret = update_file (o , 0 , & mfi_c2 .oid , mfi_c2 .mode ,
0 commit comments