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@xxxxxxxxx> --- builtin-apply.c | 44 +++++++++++++++++++++++++++++++++++++++----- 1 files changed, 39 insertions(+), 5 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index 1926cd8..6f6bf85 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2271,6 +2271,16 @@ static struct patch *in_fn_table(const char *name) return NULL; } +static int to_be_deleted(struct patch *patch) +{ + return patch == (struct patch *) -2; +} + +static int was_deleted(struct patch *patch) +{ + return patch == (struct patch *) -1; +} + static void add_to_fn_table(struct patch *patch) { struct string_list_item *item; @@ -2295,6 +2305,24 @@ static void add_to_fn_table(struct patch *patch) } } +static void prepare_fn_table(struct patch *patch) +{ + /* + * store information about incoming file deletion + */ + + while (patch) { + + if ((patch->new_name == NULL) || (patch->is_rename)) { + struct string_list_item *item = + string_list_insert(patch->old_name, &fn_table); + item->util = (struct patch *) -2; + } + + patch = patch->next; + } +} + static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce) { struct strbuf buf = STRBUF_INIT; @@ -2304,8 +2332,8 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry * struct patch *tpatch; if (!(patch->is_copy || patch->is_rename) && - ((tpatch = in_fn_table(patch->old_name)) != NULL)) { - if (tpatch == (struct patch *) -1) { + (tpatch = in_fn_table(patch->old_name)) != NULL && !to_be_deleted(tpatch)) { + if (was_deleted(tpatch)) { return error("patch %s has been renamed/deleted", patch->old_name); } @@ -2399,8 +2427,8 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s assert(patch->is_new <= 0); if (!(patch->is_copy || patch->is_rename) && - (tpatch = in_fn_table(old_name)) != NULL) { - if (tpatch == (struct patch *) -1) { + (tpatch = in_fn_table(old_name)) != NULL && !to_be_deleted(tpatch)) { + if (was_deleted(tpatch)) { return error("%s: has been deleted/renamed", old_name); } st_mode = tpatch->new_mode; @@ -2410,6 +2438,8 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s return error("%s: %s", old_name, strerror(errno)); } + if(to_be_deleted(tpatch)) tpatch = NULL; + if (check_index && !tpatch) { int pos = cache_name_pos(old_name, strlen(old_name)); if (pos < 0) { @@ -2471,6 +2501,7 @@ static int check_patch(struct patch *patch) const char *new_name = patch->new_name; const char *name = old_name ? old_name : new_name; struct cache_entry *ce = NULL; + struct patch *tpatch; int ok_if_exists; int status; @@ -2481,7 +2512,8 @@ static int check_patch(struct patch *patch) return status; old_name = patch->old_name; - if (in_fn_table(new_name) == (struct patch *) -1) + if ((tpatch = in_fn_table(new_name)) && + (was_deleted(tpatch) || to_be_deleted(tpatch))) /* * A type-change diff is always split into a patch to * delete old, immediately followed by a patch to @@ -2533,6 +2565,8 @@ static int check_patch_list(struct patch *patch) { int err = 0; + prepare_fn_table(patch); + while (patch) { if (apply_verbosely) say_patch_name(stderr, -- 1.6.0.6 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html