diff options
Diffstat (limited to 'builtin/am.c')
-rw-r--r-- | builtin/am.c | 426 |
1 files changed, 210 insertions, 216 deletions
diff --git a/builtin/am.c b/builtin/am.c index d003939bc5..6981f42ce9 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -28,6 +28,8 @@ #include "rerere.h" #include "prompt.h" #include "mailinfo.h" +#include "apply.h" +#include "string-list.h" /** * Returns 1 if the file is empty or does not exist, 0 otherwise. @@ -70,7 +72,8 @@ enum patch_format { PATCH_FORMAT_MBOX, PATCH_FORMAT_STGIT, PATCH_FORMAT_STGIT_SERIES, - PATCH_FORMAT_HG + PATCH_FORMAT_HG, + PATCH_FORMAT_MBOXRD }; enum keep_type { @@ -107,7 +110,7 @@ struct am_state { size_t msg_len; /* when --rebasing, records the original commit the patch came from */ - unsigned char orig_commit[GIT_SHA1_RAWSZ]; + struct object_id orig_commit; /* number of digits in patch filename */ int prec; @@ -183,22 +186,22 @@ static inline const char *am_path(const struct am_state *state, const char *path /** * For convenience to call write_file() */ -static int write_state_text(const struct am_state *state, - const char *name, const char *string) +static void write_state_text(const struct am_state *state, + const char *name, const char *string) { - return write_file(am_path(state, name), "%s", string); + write_file(am_path(state, name), "%s", string); } -static int write_state_count(const struct am_state *state, - const char *name, int value) +static void write_state_count(const struct am_state *state, + const char *name, int value) { - return write_file(am_path(state, name), "%d", value); + write_file(am_path(state, name), "%d", value); } -static int write_state_bool(const struct am_state *state, - const char *name, int value) +static void write_state_bool(const struct am_state *state, + const char *name, int value) { - return write_state_text(state, name, value ? "t" : "f"); + write_state_text(state, name, value ? "t" : "f"); } /** @@ -257,38 +260,29 @@ static int read_state_file(struct strbuf *sb, const struct am_state *state, } /** - * Reads a KEY=VALUE shell variable assignment from `fp`, returning the VALUE - * as a newly-allocated string. VALUE must be a quoted string, and the KEY must - * match `key`. Returns NULL on failure. - * - * This is used by read_author_script() to read the GIT_AUTHOR_* variables from - * the author-script. + * Take a series of KEY='VALUE' lines where VALUE part is + * sq-quoted, and append <KEY, VALUE> at the end of the string list */ -static char *read_shell_var(FILE *fp, const char *key) +static int parse_key_value_squoted(char *buf, struct string_list *list) { - struct strbuf sb = STRBUF_INIT; - const char *str; - - if (strbuf_getline_lf(&sb, fp)) - goto fail; - - if (!skip_prefix(sb.buf, key, &str)) - goto fail; - - if (!skip_prefix(str, "=", &str)) - goto fail; - - strbuf_remove(&sb, 0, str - sb.buf); - - str = sq_dequote(sb.buf); - if (!str) - goto fail; - - return strbuf_detach(&sb, NULL); - -fail: - strbuf_release(&sb); - return NULL; + while (*buf) { + struct string_list_item *item; + char *np; + char *cp = strchr(buf, '='); + if (!cp) + return -1; + np = strchrnul(cp, '\n'); + *cp++ = '\0'; + item = string_list_append(list, buf); + + buf = np + (*np == '\n'); + *np = '\0'; + cp = sq_dequote(cp); + if (!cp) + return -1; + item->util = xstrdup(cp); + } + return 0; } /** @@ -310,44 +304,39 @@ fail: static int read_author_script(struct am_state *state) { const char *filename = am_path(state, "author-script"); - FILE *fp; + struct strbuf buf = STRBUF_INIT; + struct string_list kv = STRING_LIST_INIT_DUP; + int retval = -1; /* assume failure */ + int fd; assert(!state->author_name); assert(!state->author_email); assert(!state->author_date); - fp = fopen(filename, "r"); - if (!fp) { + fd = open(filename, O_RDONLY); + if (fd < 0) { if (errno == ENOENT) return 0; die_errno(_("could not open '%s' for reading"), filename); } + strbuf_read(&buf, fd, 0); + close(fd); + if (parse_key_value_squoted(buf.buf, &kv)) + goto finish; - state->author_name = read_shell_var(fp, "GIT_AUTHOR_NAME"); - if (!state->author_name) { - fclose(fp); - return -1; - } - - state->author_email = read_shell_var(fp, "GIT_AUTHOR_EMAIL"); - if (!state->author_email) { - fclose(fp); - return -1; - } - - state->author_date = read_shell_var(fp, "GIT_AUTHOR_DATE"); - if (!state->author_date) { - fclose(fp); - return -1; - } - - if (fgetc(fp) != EOF) { - fclose(fp); - return -1; - } - - fclose(fp); - return 0; + if (kv.nr != 3 || + strcmp(kv.items[0].string, "GIT_AUTHOR_NAME") || + strcmp(kv.items[1].string, "GIT_AUTHOR_EMAIL") || + strcmp(kv.items[2].string, "GIT_AUTHOR_DATE")) + goto finish; + state->author_name = kv.items[0].util; + state->author_email = kv.items[1].util; + state->author_date = kv.items[2].util; + retval = 0; +finish: + string_list_clear(&kv, !!retval); + strbuf_release(&buf); + return retval; } /** @@ -402,13 +391,8 @@ static int read_commit_msg(struct am_state *state) */ static void write_commit_msg(const struct am_state *state) { - int fd; const char *filename = am_path(state, "final-commit"); - - fd = xopen(filename, O_WRONLY | O_CREAT, 0666); - if (write_in_full(fd, state->msg, state->msg_len) < 0) - die_errno(_("could not write to %s"), filename); - close(fd); + write_file_buf(filename, state->msg, state->msg_len); } /** @@ -432,8 +416,8 @@ static void am_load(struct am_state *state) read_commit_msg(state); if (read_state_file(&sb, state, "original-commit", 1) < 0) - hashclr(state->orig_commit); - else if (get_sha1_hex(sb.buf, state->orig_commit) < 0) + oidclr(&state->orig_commit); + else if (get_oid_hex(sb.buf, &state->orig_commit) < 0) die(_("could not parse %s"), am_path(state, "original-commit")); read_state_file(&sb, state, "threeway", 1); @@ -559,14 +543,14 @@ static int copy_notes_for_rebase(const struct am_state *state) fp = xfopen(am_path(state, "rewritten"), "r"); while (!strbuf_getline_lf(&sb, fp)) { - unsigned char from_obj[GIT_SHA1_RAWSZ], to_obj[GIT_SHA1_RAWSZ]; + struct object_id from_obj, to_obj; if (sb.len != GIT_SHA1_HEXSZ * 2 + 1) { ret = error(invalid_line, sb.buf); goto finish; } - if (get_sha1_hex(sb.buf, from_obj)) { + if (get_oid_hex(sb.buf, &from_obj)) { ret = error(invalid_line, sb.buf); goto finish; } @@ -576,14 +560,14 @@ static int copy_notes_for_rebase(const struct am_state *state) goto finish; } - if (get_sha1_hex(sb.buf + GIT_SHA1_HEXSZ + 1, to_obj)) { + if (get_oid_hex(sb.buf + GIT_SHA1_HEXSZ + 1, &to_obj)) { ret = error(invalid_line, sb.buf); goto finish; } - if (copy_note_for_rewrite(c, from_obj, to_obj)) + if (copy_note_for_rewrite(c, from_obj.hash, to_obj.hash)) ret = error(_("Failed to copy notes from '%s' to '%s'"), - sha1_to_hex(from_obj), sha1_to_hex(to_obj)); + oid_to_hex(&from_obj), oid_to_hex(&to_obj)); } finish: @@ -712,7 +696,8 @@ done: * Splits out individual email patches from `paths`, where each path is either * a mbox file or a Maildir. Returns 0 on success, -1 on failure. */ -static int split_mail_mbox(struct am_state *state, const char **paths, int keep_cr) +static int split_mail_mbox(struct am_state *state, const char **paths, + int keep_cr, int mboxrd) { struct child_process cp = CHILD_PROCESS_INIT; struct strbuf last = STRBUF_INIT; @@ -724,6 +709,8 @@ static int split_mail_mbox(struct am_state *state, const char **paths, int keep_ argv_array_push(&cp.args, "-b"); if (keep_cr) argv_array_push(&cp.args, "--keep-cr"); + if (mboxrd) + argv_array_push(&cp.args, "--mboxrd"); argv_array_push(&cp.args, "--"); argv_array_pushv(&cp.args, paths); @@ -769,15 +756,15 @@ static int split_mail_conv(mail_conv_fn fn, struct am_state *state, in = fopen(*paths, "r"); if (!in) - return error(_("could not open '%s' for reading: %s"), - *paths, strerror(errno)); + return error_errno(_("could not open '%s' for reading"), + *paths); mail = mkpath("%s/%0*d", state->dir, state->prec, i + 1); out = fopen(mail, "w"); if (!out) - return error(_("could not open '%s' for writing: %s"), - mail, strerror(errno)); + return error_errno(_("could not open '%s' for writing"), + mail); ret = fn(out, in, keep_cr); @@ -857,8 +844,7 @@ static int split_mail_stgit_series(struct am_state *state, const char **paths, fp = fopen(*paths, "r"); if (!fp) - return error(_("could not open '%s' for reading: %s"), *paths, - strerror(errno)); + return error_errno(_("could not open '%s' for reading"), *paths); while (!strbuf_getline_lf(&sb, fp)) { if (*sb.buf == '#') @@ -966,13 +952,15 @@ static int split_mail(struct am_state *state, enum patch_format patch_format, switch (patch_format) { case PATCH_FORMAT_MBOX: - return split_mail_mbox(state, paths, keep_cr); + return split_mail_mbox(state, paths, keep_cr, 0); case PATCH_FORMAT_STGIT: return split_mail_conv(stgit_patch_to_mail, state, paths, keep_cr); case PATCH_FORMAT_STGIT_SERIES: return split_mail_stgit_series(state, paths, keep_cr); case PATCH_FORMAT_HG: return split_mail_conv(hg_patch_to_mail, state, paths, keep_cr); + case PATCH_FORMAT_MBOXRD: + return split_mail_mbox(state, paths, keep_cr, 1); default: die("BUG: invalid patch_format"); } @@ -985,7 +973,7 @@ static int split_mail(struct am_state *state, enum patch_format patch_format, static void am_setup(struct am_state *state, enum patch_format patch_format, const char **paths, int keep_cr) { - unsigned char curr_head[GIT_SHA1_RAWSZ]; + struct object_id curr_head; const char *str; struct strbuf sb = STRBUF_INIT; @@ -1053,10 +1041,10 @@ static void am_setup(struct am_state *state, enum patch_format patch_format, else write_state_text(state, "applying", ""); - if (!get_sha1("HEAD", curr_head)) { - write_state_text(state, "abort-safety", sha1_to_hex(curr_head)); + if (!get_oid("HEAD", &curr_head)) { + write_state_text(state, "abort-safety", oid_to_hex(&curr_head)); if (!state->rebasing) - update_ref("am", "ORIG_HEAD", curr_head, NULL, 0, + update_ref_oid("am", "ORIG_HEAD", &curr_head, NULL, 0, UPDATE_REFS_DIE_ON_ERR); } else { write_state_text(state, "abort-safety", ""); @@ -1081,7 +1069,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format, */ static void am_next(struct am_state *state) { - unsigned char head[GIT_SHA1_RAWSZ]; + struct object_id head; free(state->author_name); state->author_name = NULL; @@ -1099,11 +1087,11 @@ static void am_next(struct am_state *state) unlink(am_path(state, "author-script")); unlink(am_path(state, "final-commit")); - hashclr(state->orig_commit); + oidclr(&state->orig_commit); unlink(am_path(state, "original-commit")); - if (!get_sha1("HEAD", head)) - write_state_text(state, "abort-safety", sha1_to_hex(head)); + if (!get_oid("HEAD", &head)) + write_state_text(state, "abort-safety", oid_to_hex(&head)); else write_state_text(state, "abort-safety", ""); @@ -1145,17 +1133,17 @@ static void refresh_and_write_cache(void) */ static int index_has_changes(struct strbuf *sb) { - unsigned char head[GIT_SHA1_RAWSZ]; + struct object_id head; int i; - if (!get_sha1_tree("HEAD", head)) { + if (!get_sha1_tree("HEAD", head.hash)) { struct diff_options opt; diff_setup(&opt); DIFF_OPT_SET(&opt, EXIT_WITH_STATUS); if (!sb) DIFF_OPT_SET(&opt, QUICK); - do_diff_cache(head, &opt); + do_diff_cache(head.hash, &opt); diffcore_std(&opt); for (i = 0; sb && i < diff_queued_diff.nr; i++) { if (i) @@ -1362,7 +1350,7 @@ finish: * Sets commit_id to the commit hash where the mail was generated from. * Returns 0 on success, -1 on failure. */ -static int get_mail_commit_sha1(unsigned char *commit_id, const char *mail) +static int get_mail_commit_oid(struct object_id *commit_id, const char *mail) { struct strbuf sb = STRBUF_INIT; FILE *fp = xfopen(mail, "r"); @@ -1374,7 +1362,7 @@ static int get_mail_commit_sha1(unsigned char *commit_id, const char *mail) if (!skip_prefix(sb.buf, "From ", &x)) return -1; - if (get_sha1_hex(x, commit_id) < 0) + if (get_oid_hex(x, commit_id) < 0) return -1; strbuf_release(&sb); @@ -1464,12 +1452,12 @@ static void write_commit_patch(const struct am_state *state, struct commit *comm static void write_index_patch(const struct am_state *state) { struct tree *tree; - unsigned char head[GIT_SHA1_RAWSZ]; + struct object_id head; struct rev_info rev_info; FILE *fp; - if (!get_sha1_tree("HEAD", head)) - tree = lookup_tree(head); + if (!get_sha1_tree("HEAD", head.hash)) + tree = lookup_tree(head.hash); else tree = lookup_tree(EMPTY_TREE_SHA1_BIN); @@ -1499,19 +1487,19 @@ static void write_index_patch(const struct am_state *state) static int parse_mail_rebase(struct am_state *state, const char *mail) { struct commit *commit; - unsigned char commit_sha1[GIT_SHA1_RAWSZ]; + struct object_id commit_oid; - if (get_mail_commit_sha1(commit_sha1, mail) < 0) + if (get_mail_commit_oid(&commit_oid, mail) < 0) die(_("could not parse %s"), mail); - commit = lookup_commit_or_die(commit_sha1, mail); + commit = lookup_commit_or_die(commit_oid.hash, mail); get_commit_info(state, commit); write_commit_patch(state, commit); - hashcpy(state->orig_commit, commit_sha1); - write_state_text(state, "original-commit", sha1_to_hex(commit_sha1)); + oidcpy(&state->orig_commit, &commit_oid); + write_state_text(state, "original-commit", oid_to_hex(&commit_oid)); return 0; } @@ -1522,39 +1510,59 @@ static int parse_mail_rebase(struct am_state *state, const char *mail) */ static int run_apply(const struct am_state *state, const char *index_file) { - struct child_process cp = CHILD_PROCESS_INIT; - - cp.git_cmd = 1; - - if (index_file) - argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s", index_file); + struct argv_array apply_paths = ARGV_ARRAY_INIT; + struct argv_array apply_opts = ARGV_ARRAY_INIT; + struct apply_state apply_state; + int res, opts_left; + static struct lock_file lock_file; + int force_apply = 0; + int options = 0; + + if (init_apply_state(&apply_state, NULL, &lock_file)) + die("BUG: init_apply_state() failed"); + + argv_array_push(&apply_opts, "apply"); + argv_array_pushv(&apply_opts, state->git_apply_opts.argv); + + opts_left = apply_parse_options(apply_opts.argc, apply_opts.argv, + &apply_state, &force_apply, &options, + NULL); + + if (opts_left != 0) + die("unknown option passed through to git apply"); + + if (index_file) { + apply_state.index_file = index_file; + apply_state.cached = 1; + } else + apply_state.check_index = 1; /* * If we are allowed to fall back on 3-way merge, don't give false * errors during the initial attempt. */ - if (state->threeway && !index_file) { - cp.no_stdout = 1; - cp.no_stderr = 1; - } + if (state->threeway && !index_file) + apply_state.apply_verbosity = verbosity_silent; - argv_array_push(&cp.args, "apply"); + if (check_apply_state(&apply_state, force_apply)) + die("BUG: check_apply_state() failed"); - argv_array_pushv(&cp.args, state->git_apply_opts.argv); + argv_array_push(&apply_paths, am_path(state, "patch")); - if (index_file) - argv_array_push(&cp.args, "--cached"); - else - argv_array_push(&cp.args, "--index"); + res = apply_all_patches(&apply_state, apply_paths.argc, apply_paths.argv, options); - argv_array_push(&cp.args, am_path(state, "patch")); + argv_array_clear(&apply_paths); + argv_array_clear(&apply_opts); + clear_apply_state(&apply_state); - if (run_command(&cp)) - return -1; + if (res) + return res; - /* Reload index as git-apply will have modified it. */ - discard_cache(); - read_cache_from(index_file ? index_file : get_index_file()); + if (index_file) { + /* Reload index as apply_all_patches() will have modified it. */ + discard_cache(); + read_cache_from(index_file); + } return 0; } @@ -1579,47 +1587,18 @@ static int build_fake_ancestor(const struct am_state *state, const char *index_f } /** - * Do the three-way merge using fake ancestor, his tree constructed - * from the fake ancestor and the postimage of the patch, and our - * state. - */ -static int run_fallback_merge_recursive(const struct am_state *state, - unsigned char *orig_tree, - unsigned char *our_tree, - unsigned char *his_tree) -{ - struct child_process cp = CHILD_PROCESS_INIT; - int status; - - cp.git_cmd = 1; - - argv_array_pushf(&cp.env_array, "GITHEAD_%s=%.*s", - sha1_to_hex(his_tree), linelen(state->msg), state->msg); - if (state->quiet) - argv_array_push(&cp.env_array, "GIT_MERGE_VERBOSITY=0"); - - argv_array_push(&cp.args, "merge-recursive"); - argv_array_push(&cp.args, sha1_to_hex(orig_tree)); - argv_array_push(&cp.args, "--"); - argv_array_push(&cp.args, sha1_to_hex(our_tree)); - argv_array_push(&cp.args, sha1_to_hex(his_tree)); - - status = run_command(&cp) ? (-1) : 0; - discard_cache(); - read_cache(); - return status; -} - -/** * Attempt a threeway merge, using index_path as the temporary index. */ static int fall_back_threeway(const struct am_state *state, const char *index_path) { - unsigned char orig_tree[GIT_SHA1_RAWSZ], his_tree[GIT_SHA1_RAWSZ], - our_tree[GIT_SHA1_RAWSZ]; + struct object_id orig_tree, their_tree, our_tree; + const struct object_id *bases[1] = { &orig_tree }; + struct merge_options o; + struct commit *result; + char *their_tree_name; - if (get_sha1("HEAD", our_tree) < 0) - hashcpy(our_tree, EMPTY_TREE_SHA1_BIN); + if (get_oid("HEAD", &our_tree) < 0) + hashcpy(our_tree.hash, EMPTY_TREE_SHA1_BIN); if (build_fake_ancestor(state, index_path)) return error("could not build fake ancestor"); @@ -1627,7 +1606,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa discard_cache(); read_cache_from(index_path); - if (write_index_as_tree(orig_tree, &the_index, index_path, 0, NULL)) + if (write_index_as_tree(orig_tree.hash, &the_index, index_path, 0, NULL)) return error(_("Repository lacks necessary blobs to fall back on 3-way merge.")); say(state, stdout, _("Using index info to reconstruct a base tree...")); @@ -1643,7 +1622,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa init_revisions(&rev_info, NULL); rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS; diff_opt_parse(&rev_info.diffopt, &diff_filter_str, 1, rev_info.prefix); - add_pending_sha1(&rev_info, "HEAD", our_tree, 0); + add_pending_sha1(&rev_info, "HEAD", our_tree.hash, 0); diff_setup_done(&rev_info.diffopt); run_diff_index(&rev_info, 1); } @@ -1652,7 +1631,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa return error(_("Did you hand edit your patch?\n" "It does not apply to blobs recorded in its index.")); - if (write_index_as_tree(his_tree, &the_index, index_path, 0, NULL)) + if (write_index_as_tree(their_tree.hash, &the_index, index_path, 0, NULL)) return error("could not write tree"); say(state, stdout, _("Falling back to patching base and 3-way merge...")); @@ -1662,17 +1641,28 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa /* * This is not so wrong. Depending on which base we picked, orig_tree - * may be wildly different from ours, but his_tree has the same set of + * may be wildly different from ours, but their_tree has the same set of * wildly different changes in parts the patch did not touch, so * recursive ends up canceling them, saying that we reverted all those * changes. */ - if (run_fallback_merge_recursive(state, orig_tree, our_tree, his_tree)) { + init_merge_options(&o); + + o.branch1 = "HEAD"; + their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg); + o.branch2 = their_tree_name; + + if (state->quiet) + o.verbosity = 0; + + if (merge_recursive_generic(&o, &our_tree, &their_tree, 1, bases, &result)) { rerere(state->allow_rerere_autoupdate); + free(their_tree_name); return error(_("Failed to merge in the changes.")); } + free(their_tree_name); return 0; } @@ -1683,9 +1673,8 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa */ static void do_commit(const struct am_state *state) { - unsigned char tree[GIT_SHA1_RAWSZ], parent[GIT_SHA1_RAWSZ], - commit[GIT_SHA1_RAWSZ]; - unsigned char *ptr; + struct object_id tree, parent, commit; + const struct object_id *old_oid; struct commit_list *parents = NULL; const char *reflog_msg, *author; struct strbuf sb = STRBUF_INIT; @@ -1693,14 +1682,14 @@ static void do_commit(const struct am_state *state) if (run_hook_le(NULL, "pre-applypatch", NULL)) exit(1); - if (write_cache_as_tree(tree, 0, NULL)) + if (write_cache_as_tree(tree.hash, 0, NULL)) die(_("git write-tree failed to write a tree")); - if (!get_sha1_commit("HEAD", parent)) { - ptr = parent; - commit_list_insert(lookup_commit(parent), &parents); + if (!get_sha1_commit("HEAD", parent.hash)) { + old_oid = &parent; + commit_list_insert(lookup_commit(parent.hash), &parents); } else { - ptr = NULL; + old_oid = NULL; say(state, stderr, _("applying to an empty history")); } @@ -1712,7 +1701,7 @@ static void do_commit(const struct am_state *state) setenv("GIT_COMMITTER_DATE", state->ignore_date ? "" : state->author_date, 1); - if (commit_tree(state->msg, state->msg_len, tree, parents, commit, + if (commit_tree(state->msg, state->msg_len, tree.hash, parents, commit.hash, author, state->sign_commit)) die(_("failed to write commit object")); @@ -1723,14 +1712,15 @@ static void do_commit(const struct am_state *state) strbuf_addf(&sb, "%s: %.*s", reflog_msg, linelen(state->msg), state->msg); - update_ref(sb.buf, "HEAD", commit, ptr, 0, UPDATE_REFS_DIE_ON_ERR); + update_ref_oid(sb.buf, "HEAD", &commit, old_oid, 0, + UPDATE_REFS_DIE_ON_ERR); if (state->rebasing) { FILE *fp = xfopen(am_path(state, "rewritten"), "a"); - assert(!is_null_sha1(state->orig_commit)); - fprintf(fp, "%s ", sha1_to_hex(state->orig_commit)); - fprintf(fp, "%s\n", sha1_to_hex(commit)); + assert(!is_null_oid(&state->orig_commit)); + fprintf(fp, "%s ", oid_to_hex(&state->orig_commit)); + fprintf(fp, "%s\n", oid_to_hex(&commit)); fclose(fp); } @@ -1840,6 +1830,8 @@ static void am_run(struct am_state *state, int resume) const char *mail = am_path(state, msgnum(state)); int apply_status; + reset_ident_date(); + if (!file_exists(mail)) goto next; @@ -2049,30 +2041,30 @@ static int merge_tree(struct tree *tree) * Clean the index without touching entries that are not modified between * `head` and `remote`. */ -static int clean_index(const unsigned char *head, const unsigned char *remote) +static int clean_index(const struct object_id *head, const struct object_id *remote) { struct tree *head_tree, *remote_tree, *index_tree; - unsigned char index[GIT_SHA1_RAWSZ]; + struct object_id index; - head_tree = parse_tree_indirect(head); + head_tree = parse_tree_indirect(head->hash); if (!head_tree) - return error(_("Could not parse object '%s'."), sha1_to_hex(head)); + return error(_("Could not parse object '%s'."), oid_to_hex(head)); - remote_tree = parse_tree_indirect(remote); + remote_tree = parse_tree_indirect(remote->hash); if (!remote_tree) - return error(_("Could not parse object '%s'."), sha1_to_hex(remote)); + return error(_("Could not parse object '%s'."), oid_to_hex(remote)); read_cache_unmerged(); if (fast_forward_to(head_tree, head_tree, 1)) return -1; - if (write_cache_as_tree(index, 0, NULL)) + if (write_cache_as_tree(index.hash, 0, NULL)) return -1; - index_tree = parse_tree_indirect(index); + index_tree = parse_tree_indirect(index.hash); if (!index_tree) - return error(_("Could not parse object '%s'."), sha1_to_hex(index)); + return error(_("Could not parse object '%s'."), oid_to_hex(&index)); if (fast_forward_to(index_tree, remote_tree, 0)) return -1; @@ -2100,14 +2092,14 @@ static void am_rerere_clear(void) */ static void am_skip(struct am_state *state) { - unsigned char head[GIT_SHA1_RAWSZ]; + struct object_id head; am_rerere_clear(); - if (get_sha1("HEAD", head)) - hashcpy(head, EMPTY_TREE_SHA1_BIN); + if (get_oid("HEAD", &head)) + hashcpy(head.hash, EMPTY_TREE_SHA1_BIN); - if (clean_index(head, head)) + if (clean_index(&head, &head)) die(_("failed to clean index")); am_next(state); @@ -2125,21 +2117,21 @@ static void am_skip(struct am_state *state) static int safe_to_abort(const struct am_state *state) { struct strbuf sb = STRBUF_INIT; - unsigned char abort_safety[GIT_SHA1_RAWSZ], head[GIT_SHA1_RAWSZ]; + struct object_id abort_safety, head; if (file_exists(am_path(state, "dirtyindex"))) return 0; if (read_state_file(&sb, state, "abort-safety", 1) > 0) { - if (get_sha1_hex(sb.buf, abort_safety)) + if (get_oid_hex(sb.buf, &abort_safety)) die(_("could not parse %s"), am_path(state, "abort_safety")); } else - hashclr(abort_safety); + oidclr(&abort_safety); - if (get_sha1("HEAD", head)) - hashclr(head); + if (get_oid("HEAD", &head)) + oidclr(&head); - if (!hashcmp(head, abort_safety)) + if (!oidcmp(&head, &abort_safety)) return 1; error(_("You seem to have moved HEAD since the last 'am' failure.\n" @@ -2153,7 +2145,7 @@ static int safe_to_abort(const struct am_state *state) */ static void am_abort(struct am_state *state) { - unsigned char curr_head[GIT_SHA1_RAWSZ], orig_head[GIT_SHA1_RAWSZ]; + struct object_id curr_head, orig_head; int has_curr_head, has_orig_head; char *curr_branch; @@ -2164,20 +2156,20 @@ static void am_abort(struct am_state *state) am_rerere_clear(); - curr_branch = resolve_refdup("HEAD", 0, curr_head, NULL); - has_curr_head = !is_null_sha1(curr_head); + curr_branch = resolve_refdup("HEAD", 0, curr_head.hash, NULL); + has_curr_head = !is_null_oid(&curr_head); if (!has_curr_head) - hashcpy(curr_head, EMPTY_TREE_SHA1_BIN); + hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN); - has_orig_head = !get_sha1("ORIG_HEAD", orig_head); + has_orig_head = !get_oid("ORIG_HEAD", &orig_head); if (!has_orig_head) - hashcpy(orig_head, EMPTY_TREE_SHA1_BIN); + hashcpy(orig_head.hash, EMPTY_TREE_SHA1_BIN); - clean_index(curr_head, orig_head); + clean_index(&curr_head, &orig_head); if (has_orig_head) - update_ref("am --abort", "HEAD", orig_head, - has_curr_head ? curr_head : NULL, 0, + update_ref_oid("am --abort", "HEAD", &orig_head, + has_curr_head ? &curr_head : NULL, 0, UPDATE_REFS_DIE_ON_ERR); else if (curr_branch) delete_ref(curr_branch, NULL, REF_NODEREF); @@ -2202,6 +2194,8 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int *opt_value = PATCH_FORMAT_STGIT_SERIES; else if (!strcmp(arg, "hg")) *opt_value = PATCH_FORMAT_HG; + else if (!strcmp(arg, "mboxrd")) + *opt_value = PATCH_FORMAT_MBOXRD; else return error(_("Invalid value for --patch-format: %s"), arg); return 0; @@ -2236,7 +2230,7 @@ int cmd_am(int argc, const char **argv, const char *prefix) int in_progress; const char * const usage[] = { - N_("git am [<options>] [(<mbox>|<Maildir>)...]"), + N_("git am [<options>] [(<mbox> | <Maildir>)...]"), N_("git am [<options>] (--continue | --skip | --abort)"), NULL }; |