Merge branch 'ab/replace-graft-with-replace-advice'
[gitweb.git] / apply.c
diff --git a/apply.c b/apply.c
index e485fbc6bc11efc6daefe78cbe949a65560ff4fa..01793d612620246b14fa57f6ce3ed6c33df65d0f 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -223,8 +223,8 @@ struct patch {
        struct fragment *fragments;
        char *result;
        size_t resultsize;
-       char old_sha1_prefix[41];
-       char new_sha1_prefix[41];
+       char old_oid_prefix[GIT_MAX_HEXSZ + 1];
+       char new_oid_prefix[GIT_MAX_HEXSZ + 1];
        struct patch *next;
 
        /* three-way fallback result */
@@ -1093,13 +1093,14 @@ static int gitdiff_index(struct apply_state *state,
         */
        const char *ptr, *eol;
        int len;
+       const unsigned hexsz = the_hash_algo->hexsz;
 
        ptr = strchr(line, '.');
-       if (!ptr || ptr[1] != '.' || 40 < ptr - line)
+       if (!ptr || ptr[1] != '.' || hexsz < ptr - line)
                return 0;
        len = ptr - line;
-       memcpy(patch->old_sha1_prefix, line, len);
-       patch->old_sha1_prefix[len] = 0;
+       memcpy(patch->old_oid_prefix, line, len);
+       patch->old_oid_prefix[len] = 0;
 
        line = ptr + 2;
        ptr = strchr(line, ' ');
@@ -1109,10 +1110,10 @@ static int gitdiff_index(struct apply_state *state,
                ptr = eol;
        len = ptr - line;
 
-       if (40 < len)
+       if (hexsz < len)
                return 0;
-       memcpy(patch->new_sha1_prefix, line, len);
-       patch->new_sha1_prefix[len] = 0;
+       memcpy(patch->new_oid_prefix, line, len);
+       patch->new_oid_prefix[len] = 0;
        if (*ptr == ' ')
                return gitdiff_oldmode(state, ptr + 1, patch);
        return 0;
@@ -1747,7 +1748,7 @@ static int parse_fragment(struct apply_state *state,
        }
        if (oldlines || newlines)
                return -1;
-       if (!deleted && !added)
+       if (!patch->recount && !deleted && !added)
                return -1;
 
        fragment->leading = leading;
@@ -2131,10 +2132,12 @@ static int parse_chunk(struct apply_state *state, char *buffer, unsigned long si
 
        if (!use_patch(state, patch))
                patch->ws_rule = 0;
+       else if (patch->new_name)
+               patch->ws_rule = whitespace_rule(state->repo->index,
+                                                patch->new_name);
        else
-               patch->ws_rule = whitespace_rule(patch->new_name
-                                                ? patch->new_name
-                                                : patch->old_name);
+               patch->ws_rule = whitespace_rule(state->repo->index,
+                                                patch->old_name);
 
        patchsize = parse_single_patch(state,
                                       buffer + offset + hdrsize,
@@ -2204,7 +2207,7 @@ static void reverse_patches(struct patch *p)
                SWAP(p->new_mode, p->old_mode);
                SWAP(p->is_new, p->is_delete);
                SWAP(p->lines_added, p->lines_deleted);
-               SWAP(p->old_sha1_prefix, p->new_sha1_prefix);
+               SWAP(p->old_oid_prefix, p->new_oid_prefix);
 
                for (; frag; frag = frag->next) {
                        SWAP(frag->newpos, frag->oldpos);
@@ -3142,15 +3145,16 @@ static int apply_binary(struct apply_state *state,
 {
        const char *name = patch->old_name ? patch->old_name : patch->new_name;
        struct object_id oid;
+       const unsigned hexsz = the_hash_algo->hexsz;
 
        /*
         * For safety, we require patch index line to contain
-        * full 40-byte textual SHA1 for old and new, at least for now.
+        * full hex textual object ID for old and new, at least for now.
         */
-       if (strlen(patch->old_sha1_prefix) != 40 ||
-           strlen(patch->new_sha1_prefix) != 40 ||
-           get_oid_hex(patch->old_sha1_prefix, &oid) ||
-           get_oid_hex(patch->new_sha1_prefix, &oid))
+       if (strlen(patch->old_oid_prefix) != hexsz ||
+           strlen(patch->new_oid_prefix) != hexsz ||
+           get_oid_hex(patch->old_oid_prefix, &oid) ||
+           get_oid_hex(patch->new_oid_prefix, &oid))
                return error(_("cannot apply binary patch to '%s' "
                               "without full index line"), name);
 
@@ -3160,7 +3164,7 @@ static int apply_binary(struct apply_state *state,
                 * applies to.
                 */
                hash_object_file(img->buf, img->len, blob_type, &oid);
-               if (strcmp(oid_to_hex(&oid), patch->old_sha1_prefix))
+               if (strcmp(oid_to_hex(&oid), patch->old_oid_prefix))
                        return error(_("the patch applies to '%s' (%s), "
                                       "which does not match the "
                                       "current contents."),
@@ -3173,7 +3177,7 @@ static int apply_binary(struct apply_state *state,
                                       "'%s' but it is not empty"), name);
        }
 
-       get_oid_hex(patch->new_sha1_prefix, &oid);
+       get_oid_hex(patch->new_oid_prefix, &oid);
        if (is_null_oid(&oid)) {
                clear_image(img);
                return 0; /* deletion patch */
@@ -3189,7 +3193,7 @@ static int apply_binary(struct apply_state *state,
                if (!result)
                        return error(_("the necessary postimage %s for "
                                       "'%s' cannot be read"),
-                                    patch->new_sha1_prefix, name);
+                                    patch->new_oid_prefix, name);
                clear_image(img);
                img->buf = result;
                img->len = size;
@@ -3205,9 +3209,9 @@ static int apply_binary(struct apply_state *state,
 
                /* verify that the result matches */
                hash_object_file(img->buf, img->len, blob_type, &oid);
-               if (strcmp(oid_to_hex(&oid), patch->new_sha1_prefix))
+               if (strcmp(oid_to_hex(&oid), patch->new_oid_prefix))
                        return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"),
-                               name, patch->new_sha1_prefix, oid_to_hex(&oid));
+                               name, patch->new_oid_prefix, oid_to_hex(&oid));
        }
 
        return 0;
@@ -3467,7 +3471,8 @@ static int load_preimage(struct apply_state *state,
        return 0;
 }
 
-static int three_way_merge(struct image *image,
+static int three_way_merge(struct apply_state *state,
+                          struct image *image,
                           char *path,
                           const struct object_id *base,
                           const struct object_id *ours,
@@ -3483,7 +3488,9 @@ static int three_way_merge(struct image *image,
        status = ll_merge(&result, path,
                          &base_file, "base",
                          &our_file, "ours",
-                         &their_file, "theirs", NULL);
+                         &their_file, "theirs",
+                         state->repo->index,
+                         NULL);
        free(base_file.ptr);
        free(our_file.ptr);
        free(their_file.ptr);
@@ -3563,7 +3570,7 @@ static int try_threeway(struct apply_state *state,
        /* Preimage the patch was prepared for */
        if (patch->is_new)
                write_object_file("", 0, blob_type, &pre_oid);
-       else if (get_oid(patch->old_sha1_prefix, &pre_oid) ||
+       else if (get_oid(patch->old_oid_prefix, &pre_oid) ||
                 read_blob_object(&buf, &pre_oid, patch->old_mode))
                return error(_("repository lacks the necessary blob to fall back on 3-way merge."));
 
@@ -3595,7 +3602,7 @@ static int try_threeway(struct apply_state *state,
        clear_image(&tmp_image);
 
        /* in-core three-way merge between post and our using pre as base */
-       status = three_way_merge(image, patch->new_name,
+       status = three_way_merge(state, image, patch->new_name,
                                 &pre_oid, &our_oid, &post_oid);
        if (status < 0) {
                if (state->apply_verbosity > verbosity_silent)
@@ -4055,13 +4062,13 @@ static int preimage_oid_in_gitlink_patch(struct patch *p, struct object_id *oid)
            starts_with(++preimage, heading) &&
            /* does it record full SHA-1? */
            !get_oid_hex(preimage + sizeof(heading) - 1, oid) &&
-           preimage[sizeof(heading) + GIT_SHA1_HEXSZ - 1] == '\n' &&
+           preimage[sizeof(heading) + the_hash_algo->hexsz - 1] == '\n' &&
            /* does the abbreviated name on the index line agree with it? */
-           starts_with(preimage + sizeof(heading) - 1, p->old_sha1_prefix))
+           starts_with(preimage + sizeof(heading) - 1, p->old_oid_prefix))
                return 0; /* it all looks fine */
 
        /* we may have full object name on the index line */
-       return get_oid_hex(p->old_sha1_prefix, oid);
+       return get_oid_hex(p->old_oid_prefix, oid);
 }
 
 /* Build an index that contains just the files needed for a 3way merge */
@@ -4090,7 +4097,7 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
                        else
                                return error(_("sha1 information is lacking or "
                                               "useless for submodule %s"), name);
-               } else if (!get_oid_blob(patch->old_sha1_prefix, &oid)) {
+               } else if (!get_oid_blob(patch->old_oid_prefix, &oid)) {
                        ; /* ok */
                } else if (!patch->lines_added && !patch->lines_deleted) {
                        /* mode-only change: update the current */
@@ -4627,7 +4634,7 @@ static int write_out_results(struct apply_state *state, struct patch *list)
                }
                string_list_clear(&cpath, 0);
 
-               rerere(0);
+               repo_rerere(state->repo, 0);
        }
 
        return errs;
@@ -4765,6 +4772,9 @@ static int apply_option_parse_exclude(const struct option *opt,
                                      const char *arg, int unset)
 {
        struct apply_state *state = opt->value;
+
+       BUG_ON_OPT_NEG(unset);
+
        add_name_limit(state, arg, 1);
        return 0;
 }
@@ -4773,6 +4783,9 @@ static int apply_option_parse_include(const struct option *opt,
                                      const char *arg, int unset)
 {
        struct apply_state *state = opt->value;
+
+       BUG_ON_OPT_NEG(unset);
+
        add_name_limit(state, arg, 0);
        state->has_include = 1;
        return 0;
@@ -4783,6 +4796,9 @@ static int apply_option_parse_p(const struct option *opt,
                                int unset)
 {
        struct apply_state *state = opt->value;
+
+       BUG_ON_OPT_NEG(unset);
+
        state->p_value = atoi(arg);
        state->p_value_known = 1;
        return 0;
@@ -4792,6 +4808,9 @@ static int apply_option_parse_space_change(const struct option *opt,
                                           const char *arg, int unset)
 {
        struct apply_state *state = opt->value;
+
+       BUG_ON_OPT_ARG(arg);
+
        if (unset)
                state->ws_ignore_action = ignore_ws_none;
        else
@@ -4803,9 +4822,12 @@ static int apply_option_parse_whitespace(const struct option *opt,
                                         const char *arg, int unset)
 {
        struct apply_state *state = opt->value;
+
+       BUG_ON_OPT_NEG(unset);
+
        state->whitespace_option = arg;
        if (parse_whitespace_option(state, arg))
-               exit(1);
+               return -1;
        return 0;
 }
 
@@ -4813,6 +4835,9 @@ static int apply_option_parse_directory(const struct option *opt,
                                        const char *arg, int unset)
 {
        struct apply_state *state = opt->value;
+
+       BUG_ON_OPT_NEG(unset);
+
        strbuf_reset(&state->root);
        strbuf_addstr(&state->root, arg);
        strbuf_complete(&state->root, '/');
@@ -4932,10 +4957,10 @@ int apply_parse_options(int argc, const char **argv,
        struct option builtin_apply_options[] = {
                { OPTION_CALLBACK, 0, "exclude", state, N_("path"),
                        N_("don't apply changes matching the given path"),
-                       0, apply_option_parse_exclude },
+                       PARSE_OPT_NONEG, apply_option_parse_exclude },
                { OPTION_CALLBACK, 0, "include", state, N_("path"),
                        N_("apply changes matching the given path"),
-                       0, apply_option_parse_include },
+                       PARSE_OPT_NONEG, apply_option_parse_include },
                { OPTION_CALLBACK, 'p', NULL, state, N_("num"),
                        N_("remove <num> leading slashes from traditional diff paths"),
                        0, apply_option_parse_p },