Merge branch 'bw/remote-curl-compressed-responses'
[gitweb.git] / builtin / am.c
index acfe9d3c8cd6dbd8362c17d55dc036ce6682ce8a..aa989e73901d17a35680cf14930430e5e24f6122 100644 (file)
@@ -6,7 +6,7 @@
 #include "cache.h"
 #include "config.h"
 #include "builtin.h"
-#include "exec_cmd.h"
+#include "exec-cmd.h"
 #include "parse-options.h"
 #include "dir.h"
 #include "run-command.h"
@@ -403,11 +403,11 @@ static void am_load(struct am_state *state)
        struct strbuf sb = STRBUF_INIT;
 
        if (read_state_file(&sb, state, "next", 1) < 0)
-               die("BUG: state file 'next' does not exist");
+               BUG("state file 'next' does not exist");
        state->cur = strtol(sb.buf, NULL, 10);
 
        if (read_state_file(&sb, state, "last", 1) < 0)
-               die("BUG: state file 'last' does not exist");
+               BUG("state file 'last' does not exist");
        state->last = strtol(sb.buf, NULL, 10);
 
        if (read_author_script(state) < 0)
@@ -986,7 +986,7 @@ static int split_mail(struct am_state *state, enum patch_format patch_format,
        case PATCH_FORMAT_MBOXRD:
                return split_mail_mbox(state, paths, keep_cr, 1);
        default:
-               die("BUG: invalid patch_format");
+               BUG("invalid patch_format");
        }
        return -1;
 }
@@ -1011,6 +1011,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
 
        if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
                die_errno(_("failed to create directory '%s'"), state->dir);
+       delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
 
        if (split_mail(state, patch_format, paths, keep_cr) < 0) {
                am_destroy(state);
@@ -1040,7 +1041,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
                str = "b";
                break;
        default:
-               die("BUG: invalid value for state->keep");
+               BUG("invalid value for state->keep");
        }
 
        write_state_text(state, "keep", str);
@@ -1057,11 +1058,11 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
                str = "t";
                break;
        default:
-               die("BUG: invalid value for state->scissors");
+               BUG("invalid value for state->scissors");
        }
        write_state_text(state, "scissors", str);
 
-       sq_quote_argv(&sb, state->git_apply_opts.argv, 0);
+       sq_quote_argv(&sb, state->git_apply_opts.argv);
        write_state_text(state, "apply-opt", sb.buf);
 
        if (state->rebasing)
@@ -1110,6 +1111,7 @@ static void am_next(struct am_state *state)
 
        oidclr(&state->orig_commit);
        unlink(am_path(state, "original-commit"));
+       delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
 
        if (!get_oid("HEAD", &head))
                write_state_text(state, "abort-safety", oid_to_hex(&head));
@@ -1214,7 +1216,7 @@ static int parse_mail(struct am_state *state, const char *mail)
                mi.keep_non_patch_brackets_in_subject = 1;
                break;
        default:
-               die("BUG: invalid value for state->keep");
+               BUG("invalid value for state->keep");
        }
 
        if (state->message_id)
@@ -1230,7 +1232,7 @@ static int parse_mail(struct am_state *state, const char *mail)
                mi.use_scissors = 1;
                break;
        default:
-               die("BUG: invalid value for state->scissors");
+               BUG("invalid value for state->scissors");
        }
 
        mi.input = xfopen(mail, "r");
@@ -1441,6 +1443,8 @@ static int parse_mail_rebase(struct am_state *state, const char *mail)
 
        oidcpy(&state->orig_commit, &commit_oid);
        write_state_text(state, "original-commit", oid_to_hex(&commit_oid));
+       update_ref("am", "REBASE_HEAD", &commit_oid,
+                  NULL, REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
 
        return 0;
 }
@@ -1459,7 +1463,7 @@ static int run_apply(const struct am_state *state, const char *index_file)
        int options = 0;
 
        if (init_apply_state(&apply_state, NULL))
-               die("BUG: init_apply_state() failed");
+               BUG("init_apply_state() failed");
 
        argv_array_push(&apply_opts, "apply");
        argv_array_pushv(&apply_opts, state->git_apply_opts.argv);
@@ -1485,7 +1489,7 @@ static int run_apply(const struct am_state *state, const char *index_file)
                apply_state.apply_verbosity = verbosity_silent;
 
        if (check_apply_state(&apply_state, force_apply))
-               die("BUG: check_apply_state() failed");
+               BUG("check_apply_state() failed");
 
        argv_array_push(&apply_paths, am_path(state, "patch"));
 
@@ -1538,7 +1542,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
        char *their_tree_name;
 
        if (get_oid("HEAD", &our_tree) < 0)
-               hashcpy(our_tree.hash, EMPTY_TREE_SHA1_BIN);
+               oidcpy(&our_tree, the_hash_algo->empty_tree);
 
        if (build_fake_ancestor(state, index_path))
                return error("could not build fake ancestor");
@@ -1546,7 +1550,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.hash, &the_index, index_path, 0, NULL))
+       if (write_index_as_tree(&orig_tree, &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..."));
@@ -1571,7 +1575,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(their_tree.hash, &the_index, index_path, 0, NULL))
+       if (write_index_as_tree(&their_tree, &the_index, index_path, 0, NULL))
                return error("could not write tree");
 
        say(state, stdout, _("Falling back to patching base and 3-way merge..."));
@@ -1622,7 +1626,7 @@ 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.hash, 0, NULL))
+       if (write_cache_as_tree(&tree, 0, NULL))
                die(_("git write-tree failed to write a tree"));
 
        if (!get_oid_commit("HEAD", &parent)) {
@@ -1641,8 +1645,8 @@ 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.hash, parents, commit.hash,
-                               author, state->sign_commit))
+       if (commit_tree(state->msg, state->msg_len, &tree, parents, &commit,
+                       author, state->sign_commit))
                die(_("failed to write commit object"));
 
        reflog_msg = getenv("GIT_REFLOG_ACTION");
@@ -1831,8 +1835,7 @@ static void am_run(struct am_state *state, int resume)
                        git_config_get_bool("advice.amworkdir", &advice_amworkdir);
 
                        if (advice_amworkdir)
-                               printf_ln(_("The copy of the patch that failed is found in: %s"),
-                                               am_path(state, "patch"));
+                               printf_ln(_("Use 'git am --show-current-patch' to see the failed patch"));
 
                        die_user_resolve(state);
                }
@@ -1859,7 +1862,7 @@ static void am_run(struct am_state *state, int resume)
         */
        if (!state->rebasing) {
                am_destroy(state);
-               close_all_packs();
+               close_all_packs(the_repository->objects);
                run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
        }
 }
@@ -2001,7 +2004,7 @@ static int clean_index(const struct object_id *head, const struct object_id *rem
        if (fast_forward_to(head_tree, head_tree, 1))
                return -1;
 
-       if (write_cache_as_tree(index.hash, 0, NULL))
+       if (write_cache_as_tree(&index, 0, NULL))
                return -1;
 
        index_tree = parse_tree_indirect(&index);
@@ -2039,7 +2042,7 @@ static void am_skip(struct am_state *state)
        am_rerere_clear();
 
        if (get_oid("HEAD", &head))
-               hashcpy(head.hash, EMPTY_TREE_SHA1_BIN);
+               oidcpy(&head, the_hash_algo->empty_tree);
 
        if (clean_index(&head, &head))
                die(_("failed to clean index"));
@@ -2102,11 +2105,11 @@ static void am_abort(struct am_state *state)
        curr_branch = resolve_refdup("HEAD", 0, &curr_head, NULL);
        has_curr_head = curr_branch && !is_null_oid(&curr_head);
        if (!has_curr_head)
-               hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN);
+               oidcpy(&curr_head, the_hash_algo->empty_tree);
 
        has_orig_head = !get_oid("ORIG_HEAD", &orig_head);
        if (!has_orig_head)
-               hashcpy(orig_head.hash, EMPTY_TREE_SHA1_BIN);
+               oidcpy(&orig_head, the_hash_algo->empty_tree);
 
        clean_index(&curr_head, &orig_head);
 
@@ -2121,6 +2124,34 @@ static void am_abort(struct am_state *state)
        am_destroy(state);
 }
 
+static int show_patch(struct am_state *state)
+{
+       struct strbuf sb = STRBUF_INIT;
+       const char *patch_path;
+       int len;
+
+       if (!is_null_oid(&state->orig_commit)) {
+               const char *av[4] = { "show", NULL, "--", NULL };
+               char *new_oid_str;
+               int ret;
+
+               av[1] = new_oid_str = xstrdup(oid_to_hex(&state->orig_commit));
+               ret = run_command_v_opt(av, RUN_GIT_CMD);
+               free(new_oid_str);
+               return ret;
+       }
+
+       patch_path = am_path(state, msgnum(state));
+       len = strbuf_read_file(&sb, patch_path, 0);
+       if (len < 0)
+               die_errno(_("failed to read '%s'"), patch_path);
+
+       setup_pager();
+       write_in_full(1, sb.buf, sb.len);
+       strbuf_release(&sb);
+       return 0;
+}
+
 /**
  * parse_options() callback that validates and sets opt->value to the
  * PATCH_FORMAT_* enum value corresponding to `arg`.
@@ -2149,7 +2180,9 @@ enum resume_mode {
        RESUME_APPLY,
        RESUME_RESOLVED,
        RESUME_SKIP,
-       RESUME_ABORT
+       RESUME_ABORT,
+       RESUME_QUIT,
+       RESUME_SHOW_PATCH
 };
 
 static int git_am_config(const char *k, const char *v, void *cb)
@@ -2171,6 +2204,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
        int patch_format = PATCH_FORMAT_UNKNOWN;
        enum resume_mode resume = RESUME_FALSE;
        int in_progress;
+       int ret = 0;
 
        const char * const usage[] = {
                N_("git am [<options>] [(<mbox> | <Maildir>)...]"),
@@ -2249,6 +2283,12 @@ int cmd_am(int argc, const char **argv, const char *prefix)
                OPT_CMDMODE(0, "abort", &resume,
                        N_("restore the original branch and abort the patching operation."),
                        RESUME_ABORT),
+               OPT_CMDMODE(0, "quit", &resume,
+                       N_("abort the patching operation but keep HEAD where it is."),
+                       RESUME_QUIT),
+               OPT_CMDMODE(0, "show-current-patch", &resume,
+                       N_("show the patch being applied."),
+                       RESUME_SHOW_PATCH),
                OPT_BOOL(0, "committer-date-is-author-date",
                        &state.committer_date_is_author_date,
                        N_("lie about committer date")),
@@ -2317,7 +2357,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
                 * stray directories.
                 */
                if (file_exists(state.dir) && !state.rebasing) {
-                       if (resume == RESUME_ABORT) {
+                       if (resume == RESUME_ABORT || resume == RESUME_QUIT) {
                                am_destroy(&state);
                                am_state_release(&state);
                                return 0;
@@ -2359,11 +2399,18 @@ int cmd_am(int argc, const char **argv, const char *prefix)
        case RESUME_ABORT:
                am_abort(&state);
                break;
+       case RESUME_QUIT:
+               am_rerere_clear();
+               am_destroy(&state);
+               break;
+       case RESUME_SHOW_PATCH:
+               ret = show_patch(&state);
+               break;
        default:
-               die("BUG: invalid resume value");
+               BUG("invalid resume value");
        }
 
        am_state_release(&state);
 
-       return 0;
+       return ret;
 }