From: Junio C Hamano Date: Sun, 18 Nov 2018 09:23:56 +0000 (+0900) Subject: Merge branch 'js/apply-recount-allow-noop' X-Git-Tag: v2.20.0-rc0~15 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/bda53f4185b8f7d2197176fe83afcb8d5f47368b?ds=inline;hp=-c Merge branch 'js/apply-recount-allow-noop' When editing a patch in a "git add -i" session, a hunk could be made to no-op. The "git apply" program used to reject a patch with such a no-op hunk to catch user mistakes, but it is now updated to explicitly allow a no-op hunk in an edited patch. * js/apply-recount-allow-noop: apply --recount: allow "no-op hunks" --- bda53f4185b8f7d2197176fe83afcb8d5f47368b diff --combined apply.c index 3746310cef,5fb8ecf22c..01793d6126 --- a/apply.c +++ b/apply.c @@@ -223,8 -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,14 -1093,13 +1093,14 @@@ static int gitdiff_index(struct apply_s */ 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, ' '); @@@ -1110,10 -1109,10 +1110,10 @@@ 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; @@@ -1748,7 -1747,7 +1748,7 @@@ static int parse_fragment(struct apply_ } if (oldlines || newlines) return -1; - if (!deleted && !added) + if (!patch->recount && !deleted && !added) return -1; fragment->leading = leading; @@@ -2132,12 -2131,10 +2132,12 @@@ static int parse_chunk(struct apply_sta 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, @@@ -2207,7 -2204,7 +2207,7 @@@ static void reverse_patches(struct patc 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); @@@ -3145,16 -3142,15 +3145,16 @@@ static int apply_binary(struct apply_st { 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); @@@ -3164,7 -3160,7 +3164,7 @@@ * 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."), @@@ -3177,7 -3173,7 +3177,7 @@@ "'%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 */ @@@ -3193,7 -3189,7 +3193,7 @@@ 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; @@@ -3209,9 -3205,9 +3209,9 @@@ /* 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; @@@ -3471,8 -3467,7 +3471,8 @@@ static int load_preimage(struct apply_s 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, @@@ -3488,9 -3483,7 +3488,9 @@@ 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); @@@ -3570,7 -3563,7 +3570,7 @@@ static int try_threeway(struct apply_st /* 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.")); @@@ -3602,7 -3595,7 +3602,7 @@@ 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) @@@ -4062,13 -4055,13 +4062,13 @@@ static int preimage_oid_in_gitlink_patc 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 */ @@@ -4097,7 -4090,7 +4097,7 @@@ static int build_fake_ancestor(struct a 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 */ @@@ -4634,7 -4627,7 +4634,7 @@@ static int write_out_results(struct app } string_list_clear(&cpath, 0); - rerere(0); + repo_rerere(state->repo, 0); } return errs; @@@ -4772,9 -4765,6 +4772,9 @@@ static int apply_option_parse_exclude(c const char *arg, int unset) { struct apply_state *state = opt->value; + + BUG_ON_OPT_NEG(unset); + add_name_limit(state, arg, 1); return 0; } @@@ -4783,9 -4773,6 +4783,9 @@@ static int apply_option_parse_include(c 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; @@@ -4796,9 -4783,6 +4796,9 @@@ static int apply_option_parse_p(const s 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; @@@ -4808,9 -4792,6 +4808,9 @@@ static int apply_option_parse_space_cha 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 @@@ -4822,12 -4803,9 +4822,12 @@@ static int apply_option_parse_whitespac 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; } @@@ -4835,9 -4813,6 +4835,9 @@@ static int apply_option_parse_directory 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, '/'); @@@ -4957,10 -4932,10 +4957,10 @@@ int apply_parse_options(int argc, cons 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 leading slashes from traditional diff paths"), 0, apply_option_parse_p },