@@ -1151,6 +1151,26 @@ static int conflict_rename_dir(struct merge_options *o,
1151
1151
{
1152
1152
const struct diff_filespec * dest = pair -> two ;
1153
1153
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 */
1154
1174
if (update_file (o , 1 , & dest -> oid , dest -> mode , dest -> path ))
1155
1175
return -1 ;
1156
1176
return 0 ;
@@ -1169,7 +1189,8 @@ static int handle_change_delete(struct merge_options *o,
1169
1189
const char * update_path = path ;
1170
1190
int ret = 0 ;
1171
1191
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 ))) {
1173
1194
update_path = alt_path = unique_path (o , path , change_branch );
1174
1195
}
1175
1196
@@ -1295,6 +1316,12 @@ static int handle_file(struct merge_options *o,
1295
1316
dst_name = unique_path (o , rename -> path , cur_branch );
1296
1317
output (o , 1 , _ ("%s is a directory in %s adding as %s instead" ),
1297
1318
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 );
1298
1325
}
1299
1326
}
1300
1327
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,
1420
1447
char * new_path2 = unique_path (o , path , ci -> branch2 );
1421
1448
output (o , 1 , _ ("Renaming %s to %s and %s to %s instead" ),
1422
1449
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 );
1424
1462
ret = update_file (o , 0 , & mfi_c1 .oid , mfi_c1 .mode , new_path1 );
1425
1463
if (!ret )
1426
1464
ret = update_file (o , 0 , & mfi_c2 .oid , mfi_c2 .mode ,
0 commit comments