@matheusbsbs / matheus-bagliano / commits / e8141fcf54
Fork 0

builtin-apply: keep information about files to be deleted

Example correct diff generated by `diff -M -B' might look like this: diff --git a/file1 b/file2 similarity index 100% rename from file1 rename to file2 diff --git a/file2 b/file1 similarity index 100% rename from file2 rename to file1 Information about removing `file2' comes after information about creation of new `file2' (renamed from `file1'). Existing implementation isn't able to apply such patch, because it has to know in advance which files will be removed. This patch populates fn_table with information about removal of files before calling check_patch() for each patch to be applied. Signed-off-by: Michał Kiedrowicz <michal.kiedrowicz@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michał Kiedrowicz committed Apr 11, 2009 at 21:31 UTC e8141fcf54b4e8c2c12300da1ad1bc3573a4e204
2 files changed +47 -8
builtin-apply.c
+46 -7
@@ -2271,6 +2271,25 @@ static struct patch *in_fn_table(const char *name)
2271 return NULL;
2272 }
2273
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 +
2293 static void add_to_fn_table(struct patch *patch)
2294 {
2295 struct string_list_item *item;
@@ -2291,7 +2310,22 @@ static void add_to_fn_table(struct patch *patch)
2310 */
2311 if ((patch->new_name == NULL) || (patch->is_rename)) {
2312 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;
2329 }
2330 }
2331
@@ -2304,8 +2338,8 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
2338 struct patch *tpatch;
2339
2340 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)) {
2343 return error("patch %s has been renamed/deleted",
2344 patch->old_name);
2345 }
@@ -2399,10 +2433,9 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
2433 assert(patch->is_new <= 0);
2434
2435 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))
2438 return error("%s: has been deleted/renamed", old_name);
2405 - }
2439 st_mode = tpatch->new_mode;
2440 } else if (!cached) {
2441 stat_ret = lstat(old_name, st);
@@ -2410,6 +2443,9 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
2443 return error("%s: %s", old_name, strerror(errno));
2444 }
2445
2446 + if (to_be_deleted(tpatch))
2447 + tpatch = NULL;
2448 +
2449 if (check_index && !tpatch) {
2450 int pos = cache_name_pos(old_name, strlen(old_name));
2451 if (pos < 0) {
@@ -2471,6 +2507,7 @@ static int check_patch(struct patch *patch)
2507 const char *new_name = patch->new_name;
2508 const char *name = old_name ? old_name : new_name;
2509 struct cache_entry *ce = NULL;
2510 + struct patch *tpatch;
2511 int ok_if_exists;
2512 int status;
2513
@@ -2481,7 +2518,8 @@ static int check_patch(struct patch *patch)
2518 return status;
2519 old_name = patch->old_name;
2520
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)))
2523 /*
2524 * A type-change diff is always split into a patch to
2525 * delete old, immediately followed by a patch to
@@ -2533,6 +2571,7 @@ static int check_patch_list(struct patch *patch)
2571 {
2572 int err = 0;
2573
2574 + prepare_fn_table(patch);
2575 while (patch) {
2576 if (apply_verbosely)
2577 say_patch_name(stderr,
t/t4130-apply-criss-cross-rename.sh
+1 -1
@@ -31,7 +31,7 @@ test_expect_success 'diff -M -B' '
31
32 '
33
34 -test_expect_failure 'apply' '
34 +test_expect_success 'apply' '
35 git apply diff
36 '
37