summaryrefslogtreecommitdiff
path: root/apply.c
diff options
context:
space:
mode:
Diffstat (limited to 'apply.c')
-rw-r--r--apply.c98
1 files changed, 62 insertions, 36 deletions
diff --git a/apply.c b/apply.c
index e485fbc6bc..3703bfc8d0 100644
--- 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;
@@ -3348,7 +3352,8 @@ static int checkout_target(struct index_state *istate,
costate.refresh_cache = 1;
costate.istate = istate;
- if (checkout_entry(ce, &costate, NULL) || lstat(ce->name, st))
+ if (checkout_entry(ce, &costate, NULL, NULL) ||
+ lstat(ce->name, st))
return error(_("cannot checkout %s"), ce->name);
return 0;
}
@@ -3467,7 +3472,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 +3489,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 +3571,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 +3603,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 +4063,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 +4098,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 +4635,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 +4773,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 +4784,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 +4797,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 +4809,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 +4823,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 +4836,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 +4958,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 },