@@ -1141,6 +1141,26 @@ static int conflict_rename_dir(struct merge_options *o,
1141
1141
{
1142
1142
const struct diff_filespec * dest = pair -> two ;
1143
1143
1144
+ if (!o -> call_depth && would_lose_untracked (dest -> path )) {
1145
+ char * alt_path = unique_path (o , dest -> path , rename_branch );
1146
+
1147
+ output (o , 1 , _ ("Error: Refusing to lose untracked file at %s; "
1148
+ "writing to %s instead." ),
1149
+ dest -> path , alt_path );
1150
+ /*
1151
+ * Write the file in worktree at alt_path, but not in the
1152
+ * index. Instead, write to dest->path for the index but
1153
+ * only at the higher appropriate stage.
1154
+ */
1155
+ if (update_file (o , 0 , & dest -> oid , dest -> mode , alt_path ))
1156
+ return -1 ;
1157
+ free (alt_path );
1158
+ return update_stages (o , dest -> path , NULL ,
1159
+ rename_branch == o -> branch1 ? dest : NULL ,
1160
+ rename_branch == o -> branch1 ? NULL : dest );
1161
+ }
1162
+
1163
+ /* Update dest->path both in index and in worktree */
1144
1164
if (update_file (o , 1 , & dest -> oid , dest -> mode , dest -> path ))
1145
1165
return -1 ;
1146
1166
return 0 ;
@@ -1159,7 +1179,8 @@ static int handle_change_delete(struct merge_options *o,
1159
1179
const char * update_path = path ;
1160
1180
int ret = 0 ;
1161
1181
1162
- if (dir_in_way (path , !o -> call_depth , 0 )) {
1182
+ if (dir_in_way (path , !o -> call_depth , 0 ) ||
1183
+ (!o -> call_depth && would_lose_untracked (path ))) {
1163
1184
update_path = alt_path = unique_path (o , path , change_branch );
1164
1185
}
1165
1186
@@ -1285,6 +1306,12 @@ static int handle_file(struct merge_options *o,
1285
1306
dst_name = unique_path (o , rename -> path , cur_branch );
1286
1307
output (o , 1 , _ ("%s is a directory in %s adding as %s instead" ),
1287
1308
rename -> path , other_branch , dst_name );
1309
+ } else if (!o -> call_depth &&
1310
+ would_lose_untracked (rename -> path )) {
1311
+ dst_name = unique_path (o , rename -> path , cur_branch );
1312
+ output (o , 1 , _ ("Refusing to lose untracked file at %s; "
1313
+ "adding as %s instead" ),
1314
+ rename -> path , dst_name );
1288
1315
}
1289
1316
}
1290
1317
if ((ret = update_file (o , 0 , & rename -> oid , rename -> mode , dst_name )))
@@ -1410,7 +1437,18 @@ static int conflict_rename_rename_2to1(struct merge_options *o,
1410
1437
char * new_path2 = unique_path (o , path , ci -> branch2 );
1411
1438
output (o , 1 , _ ("Renaming %s to %s and %s to %s instead" ),
1412
1439
a -> path , new_path1 , b -> path , new_path2 );
1413
- remove_file (o , 0 , path , 0 );
1440
+ if (would_lose_untracked (path ))
1441
+ /*
1442
+ * Only way we get here is if both renames were from
1443
+ * a directory rename AND user had an untracked file
1444
+ * at the location where both files end up after the
1445
+ * two directory renames. See testcase 10d of t6043.
1446
+ */
1447
+ output (o , 1 , _ ("Refusing to lose untracked file at "
1448
+ "%s, even though it's in the way." ),
1449
+ path );
1450
+ else
1451
+ remove_file (o , 0 , path , 0 );
1414
1452
ret = update_file (o , 0 , & mfi_c1 .oid , mfi_c1 .mode , new_path1 );
1415
1453
if (!ret )
1416
1454
ret = update_file (o , 0 , & mfi_c2 .oid , mfi_c2 .mode ,
0 commit comments