From 7f95aef28fa1e2662aebb4556c71ad6912d395e5 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 17 Jul 2006 00:10:47 -0700 Subject: [PATCH] apply: handle type-changing patch correctly. A type-change diff is always split into a patch to delete old, immediately followed by a patch to create new. check_patch() routine noticed that the path to be created already exists in the working tree and/or in the index when looking at the creation patch and mistakenly thought it to be an error. Signed-off-by: Junio C Hamano --- builtin-apply.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index 37404e2e6a..8f7cf44c69 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -1664,13 +1664,14 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry * return 0; } -static int check_patch(struct patch *patch) +static int check_patch(struct patch *patch, struct patch *prev_patch) { struct stat st; const char *old_name = patch->old_name; const char *new_name = patch->new_name; const char *name = old_name ? old_name : new_name; struct cache_entry *ce = NULL; + int ok_if_exists; if (old_name) { int changed = 0; @@ -1728,13 +1729,28 @@ static int check_patch(struct patch *patch) old_name, st_mode, patch->old_mode); } + if (new_name && prev_patch && prev_patch->is_delete && + !strcmp(prev_patch->old_name, new_name)) + /* A type-change diff is always split into a patch to + * delete old, immediately followed by a patch to + * create new (see diff.c::run_diff()); in such a case + * it is Ok that the entry to be deleted by the + * previous patch is still in the working tree and in + * the index. + */ + ok_if_exists = 1; + else + ok_if_exists = 0; + if (new_name && (patch->is_new | patch->is_rename | patch->is_copy)) { - if (check_index && cache_name_pos(new_name, strlen(new_name)) >= 0) + if (check_index && + cache_name_pos(new_name, strlen(new_name)) >= 0 && + !ok_if_exists) return error("%s: already exists in index", new_name); if (!cached) { struct stat nst; if (!lstat(new_name, &nst)) { - if (S_ISDIR(nst.st_mode)) + if (S_ISDIR(nst.st_mode) || ok_if_exists) ; /* ok */ else return error("%s: already exists in working directory", new_name); @@ -1767,10 +1783,13 @@ static int check_patch(struct patch *patch) static int check_patch_list(struct patch *patch) { + struct patch *prev_patch = NULL; int error = 0; - for (;patch ; patch = patch->next) - error |= check_patch(patch); + for (prev_patch = NULL; patch ; patch = patch->next) { + error |= check_patch(patch, prev_patch); + prev_patch = patch; + } return error; } -- 2.11.4.GIT