builtin-apply: accept patch to an empty file
authorJunio C Hamano <gitster@pobox.com>
Sat, 17 May 2008 08:51:31 +0000 (01:51 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 17 May 2008 08:51:31 +0000 (01:51 -0700)
A patch from a foreign SCM (or plain "diff" output) often have both
preimage and postimage filename on ---/+++ lines even for a patch that
creates a new file.  However, when there is a filename for preimage, we
used to insist the file to exist (either in the work tree and/or in the
index).  When we cannot be sure by parsing the patch that it is not a
creation patch, we shouldn't complain when if there is no such a file.
This commit fixes the logic.

Refactor the code that validates the preimage file into a separate
function while we are at it, as it is getting rather big.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin-apply.c

index 776e5963b72248e999f7e444dbdce6a488656121..10b1f88a3c05656af73ede98f9b5544a4e947731 100644 (file)
@@ -2267,16 +2267,11 @@ static int verify_index_match(struct cache_entry *ce, struct stat *st)
        return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID);
 }
 
-static int check_patch(struct patch *patch, struct patch *prev_patch)
+static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)
 {
-       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;
-
-       patch->rejected = 1; /* we will drop this after we succeed */
+       int stat_ret = 0;
+       unsigned st_mode = 0;
 
        /*
         * Make sure that we do not have local modifications from the
@@ -2284,58 +2279,84 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
         * we have the preimage file to be patched in the work tree,
         * unless --cached, which tells git to apply only in the index.
         */
-       if (old_name) {
-               int stat_ret = 0;
-               unsigned st_mode = 0;
-
-               if (!cached)
-                       stat_ret = lstat(old_name, &st);
-               if (check_index) {
-                       int pos = cache_name_pos(old_name, strlen(old_name));
-                       if (pos < 0)
-                               return error("%s: does not exist in index",
-                                            old_name);
-                       ce = active_cache[pos];
-                       if (stat_ret < 0) {
-                               struct checkout costate;
-                               if (errno != ENOENT)
-                                       return error("%s: %s", old_name,
-                                                    strerror(errno));
-                               /* checkout */
-                               costate.base_dir = "";
-                               costate.base_dir_len = 0;
-                               costate.force = 0;
-                               costate.quiet = 0;
-                               costate.not_new = 0;
-                               costate.refresh_cache = 1;
-                               if (checkout_entry(ce,
-                                                  &costate,
-                                                  NULL) ||
-                                   lstat(old_name, &st))
-                                       return -1;
-                       }
-                       if (!cached && verify_index_match(ce, &st))
-                               return error("%s: does not match index",
-                                            old_name);
-                       if (cached)
-                               st_mode = ce->ce_mode;
-               } else if (stat_ret < 0)
-                       return error("%s: %s", old_name, strerror(errno));
-
-               if (!cached)
-                       st_mode = ce_mode_from_stat(ce, st.st_mode);
+       if (!old_name)
+               return 0;
 
+       assert(patch->is_new <= 0);
+       if (!cached) {
+               stat_ret = lstat(old_name, st);
+               if (stat_ret && errno != ENOENT)
+                       return error("%s: %s", old_name, strerror(errno));
+       }
+       if (check_index) {
+               int pos = cache_name_pos(old_name, strlen(old_name));
+               if (pos < 0) {
+                       if (patch->is_new < 0)
+                               goto is_new;
+                       return error("%s: does not exist in index", old_name);
+               }
+               *ce = active_cache[pos];
+               if (stat_ret < 0) {
+                       struct checkout costate;
+                       /* checkout */
+                       costate.base_dir = "";
+                       costate.base_dir_len = 0;
+                       costate.force = 0;
+                       costate.quiet = 0;
+                       costate.not_new = 0;
+                       costate.refresh_cache = 1;
+                       if (checkout_entry(*ce, &costate, NULL) ||
+                           lstat(old_name, st))
+                               return -1;
+               }
+               if (!cached && verify_index_match(*ce, st))
+                       return error("%s: does not match index", old_name);
+               if (cached)
+                       st_mode = (*ce)->ce_mode;
+       } else if (stat_ret < 0) {
                if (patch->is_new < 0)
-                       patch->is_new = 0;
-               if (!patch->old_mode)
-                       patch->old_mode = st_mode;
-               if ((st_mode ^ patch->old_mode) & S_IFMT)
-                       return error("%s: wrong type", old_name);
-               if (st_mode != patch->old_mode)
-                       fprintf(stderr, "warning: %s has type %o, expected %o\n",
-                               old_name, st_mode, patch->old_mode);
+                       goto is_new;
+               return error("%s: %s", old_name, strerror(errno));
        }
 
+       if (!cached)
+               st_mode = ce_mode_from_stat(*ce, st->st_mode);
+
+       if (patch->is_new < 0)
+               patch->is_new = 0;
+       if (!patch->old_mode)
+               patch->old_mode = st_mode;
+       if ((st_mode ^ patch->old_mode) & S_IFMT)
+               return error("%s: wrong type", old_name);
+       if (st_mode != patch->old_mode)
+               fprintf(stderr, "warning: %s has type %o, expected %o\n",
+                       old_name, st_mode, patch->old_mode);
+       return 0;
+
+ is_new:
+       patch->is_new = 1;
+       patch->is_delete = 0;
+       patch->old_name = NULL;
+       return 0;
+}
+
+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;
+       int status;
+
+       patch->rejected = 1; /* we will drop this after we succeed */
+
+       status = check_preimage(patch, &ce, &st);
+       if (status)
+               return status;
+       old_name = patch->old_name;
+
        if (new_name && prev_patch && 0 < prev_patch->is_delete &&
            !strcmp(prev_patch->old_name, new_name))
                /*