@@ -2271,6 +2271,25 @@ static struct patch *in_fn_table(const char *name)
22712271 return NULL ;
22722272}
22732273
2274+ /*
2275+ * item->util in the filename table records the status of the path.
2276+ * Usually it points at a patch (whose result records the contents
2277+ * of it after applying it), but it could be PATH_WAS_DELETED for a
2278+ * path that a previously applied patch has already removed.
2279+ */
2280+ #define PATH_TO_BE_DELETED ((struct patch *) -2)
2281+ #define PATH_WAS_DELETED ((struct patch *) -1)
2282+
2283+ static int to_be_deleted (struct patch * patch )
2284+ {
2285+ return patch == PATH_TO_BE_DELETED ;
2286+ }
2287+
2288+ static int was_deleted (struct patch * patch )
2289+ {
2290+ return patch == PATH_WAS_DELETED ;
2291+ }
2292+
22742293static void add_to_fn_table (struct patch * patch )
22752294{
22762295 struct string_list_item * item ;
@@ -2291,7 +2310,22 @@ static void add_to_fn_table(struct patch *patch)
22912310 */
22922311 if ((patch -> new_name == NULL ) || (patch -> is_rename )) {
22932312 item = string_list_insert (patch -> old_name , & fn_table );
2294- item -> util = (struct patch * ) -1 ;
2313+ item -> util = PATH_WAS_DELETED ;
2314+ }
2315+ }
2316+
2317+ static void prepare_fn_table (struct patch * patch )
2318+ {
2319+ /*
2320+ * store information about incoming file deletion
2321+ */
2322+ while (patch ) {
2323+ if ((patch -> new_name == NULL ) || (patch -> is_rename )) {
2324+ struct string_list_item * item ;
2325+ item = string_list_insert (patch -> old_name , & fn_table );
2326+ item -> util = PATH_TO_BE_DELETED ;
2327+ }
2328+ patch = patch -> next ;
22952329 }
22962330}
22972331
@@ -2304,8 +2338,8 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
23042338 struct patch * tpatch ;
23052339
23062340 if (!(patch -> is_copy || patch -> is_rename ) &&
2307- (( tpatch = in_fn_table (patch -> old_name )) != NULL )) {
2308- if (tpatch == ( struct patch * ) -1 ) {
2341+ (tpatch = in_fn_table (patch -> old_name )) != NULL && ! to_be_deleted ( tpatch )) {
2342+ if (was_deleted ( tpatch ) ) {
23092343 return error ("patch %s has been renamed/deleted" ,
23102344 patch -> old_name );
23112345 }
@@ -2399,17 +2433,19 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
23992433 assert (patch -> is_new <= 0 );
24002434
24012435 if (!(patch -> is_copy || patch -> is_rename ) &&
2402- (tpatch = in_fn_table (old_name )) != NULL ) {
2403- if (tpatch == ( struct patch * ) -1 ) {
2436+ (tpatch = in_fn_table (old_name )) != NULL && ! to_be_deleted ( tpatch ) ) {
2437+ if (was_deleted ( tpatch ))
24042438 return error ("%s: has been deleted/renamed" , old_name );
2405- }
24062439 st_mode = tpatch -> new_mode ;
24072440 } else if (!cached ) {
24082441 stat_ret = lstat (old_name , st );
24092442 if (stat_ret && errno != ENOENT )
24102443 return error ("%s: %s" , old_name , strerror (errno ));
24112444 }
24122445
2446+ if (to_be_deleted (tpatch ))
2447+ tpatch = NULL ;
2448+
24132449 if (check_index && !tpatch ) {
24142450 int pos = cache_name_pos (old_name , strlen (old_name ));
24152451 if (pos < 0 ) {
@@ -2471,6 +2507,7 @@ static int check_patch(struct patch *patch)
24712507 const char * new_name = patch -> new_name ;
24722508 const char * name = old_name ? old_name : new_name ;
24732509 struct cache_entry * ce = NULL ;
2510+ struct patch * tpatch ;
24742511 int ok_if_exists ;
24752512 int status ;
24762513
@@ -2481,7 +2518,8 @@ static int check_patch(struct patch *patch)
24812518 return status ;
24822519 old_name = patch -> old_name ;
24832520
2484- if (in_fn_table (new_name ) == (struct patch * ) -1 )
2521+ if ((tpatch = in_fn_table (new_name )) &&
2522+ (was_deleted (tpatch ) || to_be_deleted (tpatch )))
24852523 /*
24862524 * A type-change diff is always split into a patch to
24872525 * delete old, immediately followed by a patch to
@@ -2533,6 +2571,7 @@ static int check_patch_list(struct patch *patch)
25332571{
25342572 int err = 0 ;
25352573
2574+ prepare_fn_table (patch );
25362575 while (patch ) {
25372576 if (apply_verbosely )
25382577 say_patch_name (stderr ,
0 commit comments