summaryrefslogtreecommitdiff
path: root/builtin-apply.c
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2006-07-17 07:10:47 (GMT)
committerJunio C Hamano <junkio@cox.net>2006-07-17 07:10:47 (GMT)
commit7f95aef28fa1e2662aebb4556c71ad6912d395e5 (patch)
tree57fbcb9b99c40bdf75742df2e21637294998921c /builtin-apply.c
parenteed46644ca48ad08e1fd71e14afbe801399e8a67 (diff)
downloadgit-7f95aef28fa1e2662aebb4556c71ad6912d395e5.zip
git-7f95aef28fa1e2662aebb4556c71ad6912d395e5.tar.gz
git-7f95aef28fa1e2662aebb4556c71ad6912d395e5.tar.bz2
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 <junkio@cox.net>
Diffstat (limited to 'builtin-apply.c')
-rw-r--r--builtin-apply.c29
1 files changed, 24 insertions, 5 deletions
diff --git a/builtin-apply.c b/builtin-apply.c
index 37404e2..8f7cf44 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;
}