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