pack-bitmap: switch hash tables to use struct object_id
[gitweb.git] / builtin / rebase.c
index 8d49e53997b3579623a284845cd49aa9b67b14a7..77deebc65c6bd7fbe6261b91cfb78c7ec3f85c2d 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (c) 2018 Pratik Karki
  */
 
+#define USE_THE_INDEX_COMPATIBILITY_MACROS
 #include "builtin.h"
 #include "run-command.h"
 #include "exec-cmd.h"
@@ -368,6 +369,7 @@ static void add_var(struct strbuf *buf, const char *name, const char *value)
 #define RESET_HEAD_HARD (1<<1)
 #define RESET_HEAD_RUN_POST_CHECKOUT_HOOK (1<<2)
 #define RESET_HEAD_REFS_ONLY (1<<3)
+#define RESET_ORIG_HEAD (1<<4)
 
 static int reset_head(struct object_id *oid, const char *action,
                      const char *switch_to_branch, unsigned flags,
@@ -377,6 +379,7 @@ static int reset_head(struct object_id *oid, const char *action,
        unsigned reset_hard = flags & RESET_HEAD_HARD;
        unsigned run_hook = flags & RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
        unsigned refs_only = flags & RESET_HEAD_REFS_ONLY;
+       unsigned update_orig_head = flags & RESET_ORIG_HEAD;
        struct object_id head_oid;
        struct tree_desc desc[2] = { { NULL }, { NULL } };
        struct lock_file lock = LOCK_INIT;
@@ -419,7 +422,7 @@ static int reset_head(struct object_id *oid, const char *action,
        if (!detach_head)
                unpack_tree_opts.reset = 1;
 
-       if (read_index_unmerged(the_repository->index) < 0) {
+       if (repo_read_index_unmerged(the_repository) < 0) {
                ret = error(_("could not read index"));
                goto leave_reset_head;
        }
@@ -453,18 +456,21 @@ static int reset_head(struct object_id *oid, const char *action,
        strbuf_addf(&msg, "%s: ", reflog_action ? reflog_action : "rebase");
        prefix_len = msg.len;
 
-       if (!get_oid("ORIG_HEAD", &oid_old_orig))
-               old_orig = &oid_old_orig;
-       if (!get_oid("HEAD", &oid_orig)) {
-               orig = &oid_orig;
-               if (!reflog_orig_head) {
-                       strbuf_addstr(&msg, "updating ORIG_HEAD");
-                       reflog_orig_head = msg.buf;
-               }
-               update_ref(reflog_orig_head, "ORIG_HEAD", orig, old_orig, 0,
-                          UPDATE_REFS_MSG_ON_ERR);
-       } else if (old_orig)
-               delete_ref(NULL, "ORIG_HEAD", old_orig, 0);
+       if (update_orig_head) {
+               if (!get_oid("ORIG_HEAD", &oid_old_orig))
+                       old_orig = &oid_old_orig;
+               if (!get_oid("HEAD", &oid_orig)) {
+                       orig = &oid_orig;
+                       if (!reflog_orig_head) {
+                               strbuf_addstr(&msg, "updating ORIG_HEAD");
+                               reflog_orig_head = msg.buf;
+                       }
+                       update_ref(reflog_orig_head, "ORIG_HEAD", orig,
+                                  old_orig, 0, UPDATE_REFS_MSG_ON_ERR);
+               } else if (old_orig)
+                       delete_ref(NULL, "ORIG_HEAD", old_orig, 0);
+       }
+
        if (!reflog_head) {
                strbuf_setlen(&msg, prefix_len);
                strbuf_addstr(&msg, "updating HEAD");
@@ -475,7 +481,7 @@ static int reset_head(struct object_id *oid, const char *action,
                                 detach_head ? REF_NO_DEREF : 0,
                                 UPDATE_REFS_MSG_ON_ERR);
        else {
-               ret = update_ref(reflog_orig_head, switch_to_branch, oid,
+               ret = update_ref(reflog_head, switch_to_branch, oid,
                                 NULL, 0, UPDATE_REFS_MSG_ON_ERR);
                if (!ret)
                        ret = create_symref("HEAD", switch_to_branch,
@@ -940,23 +946,6 @@ static int parse_opt_interactive(const struct option *opt, const char *arg,
        return 0;
 }
 
-struct opt_y {
-       struct string_list *list;
-       struct rebase_options *options;
-};
-
-static int parse_opt_y(const struct option *opt, const char *arg, int unset)
-{
-       struct opt_y *o = opt->value;
-
-       if (unset || !arg)
-               return -1;
-
-       o->options->reschedule_failed_exec = 1;
-       string_list_append(o->list, arg);
-       return 0;
-}
-
 static void NORETURN error_on_missing_default_upstream(void)
 {
        struct branch *current_branch = branch_get(NULL);
@@ -1004,6 +993,19 @@ static void set_reflog_action(struct rebase_options *options)
        strbuf_release(&buf);
 }
 
+static int check_exec_cmd(const char *cmd)
+{
+       if (strchr(cmd, '\n'))
+               return error(_("exec commands cannot contain newlines"));
+
+       /* Does the command consist purely of whitespace? */
+       if (!cmd[strspn(cmd, " \t\r\f\v")])
+               return error(_("empty exec command"));
+
+       return 0;
+}
+
+
 int cmd_rebase(int argc, const char **argv, const char *prefix)
 {
        struct rebase_options options = {
@@ -1030,6 +1032,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                ACTION_EDIT_TODO,
                ACTION_SHOW_CURRENT_PATCH,
        } action = NO_ACTION;
+       static const char *action_names[] = { N_("undefined"),
+                                             N_("continue"),
+                                             N_("skip"),
+                                             N_("abort"),
+                                             N_("quit"),
+                                             N_("edit_todo"),
+                                             N_("show_current_patch"),
+                                             NULL };
        const char *gpg_sign = NULL;
        struct string_list exec = STRING_LIST_INIT_NODUP;
        const char *rebase_merges = NULL;
@@ -1037,7 +1047,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        struct string_list strategy_options = STRING_LIST_INIT_NODUP;
        struct object_id squash_onto;
        char *squash_onto_name = NULL;
-       struct opt_y opt_y = { .list = &exec, .options = &options };
        struct option builtin_rebase_options[] = {
                OPT_STRING(0, "onto", &options.onto_name,
                           N_("revision"),
@@ -1115,9 +1124,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                OPT_STRING_LIST('x', "exec", &exec, N_("exec"),
                                N_("add exec lines after each commit of the "
                                   "editable list")),
-               { OPTION_CALLBACK, 'y', NULL, &opt_y, N_("<cmd>"),
-                       N_("same as --reschedule-failed-exec -x <cmd>"),
-                       PARSE_OPT_NONEG, parse_opt_y },
                OPT_BOOL(0, "allow-empty-message",
                         &options.allow_empty_message,
                         N_("allow rebasing commits with empty messages")),
@@ -1219,6 +1225,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                die(_("The --edit-todo action can only be used during "
                      "interactive rebase."));
 
+       if (trace2_is_enabled()) {
+               if (is_interactive(&options))
+                       trace2_cmd_mode("interactive");
+               else if (exec.nr)
+                       trace2_cmd_mode("interactive-exec");
+               else
+                       trace2_cmd_mode(action_names[action]);
+       }
+
        switch (action) {
        case ACTION_CONTINUE: {
                struct object_id head;
@@ -1233,13 +1248,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                        die(_("Cannot read HEAD"));
 
                fd = hold_locked_index(&lock_file, 0);
-               if (read_index(the_repository->index) < 0)
+               if (repo_read_index(the_repository) < 0)
                        die(_("could not read index"));
                refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL,
                              NULL);
                if (0 <= fd)
-                       update_index_if_able(the_repository->index,
-                                            &lock_file);
+                       repo_update_index_if_able(the_repository, &lock_file);
                rollback_lock_file(&lock_file);
 
                if (has_unstaged_changes(the_repository, 1)) {
@@ -1348,6 +1362,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                }
        }
 
+       for (i = 0; i < exec.nr; i++)
+               if (check_exec_cmd(exec.items[i].string))
+                       exit(1);
+
        if (!(options.flags & REBASE_NO_QUIET))
                argv_array_push(&options.git_am_opts, "-q");
 
@@ -1438,7 +1456,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        }
 
        if (options.reschedule_failed_exec && !is_interactive(&options))
-               die(_("--reschedule-failed-exec requires an interactive rebase"));
+               die(_("%s requires an interactive rebase"), "--reschedule-failed-exec");
 
        if (options.git_am_opts.argc) {
                /* all am options except -q are compatible only with --am */
@@ -1591,7 +1609,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                        get_fork_point(options.upstream_name, head);
        }
 
-       if (read_index(the_repository->index) < 0)
+       if (repo_read_index(the_repository) < 0)
                die(_("could not read index"));
 
        if (options.autostash) {
@@ -1601,7 +1619,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                fd = hold_locked_index(&lock_file, 0);
                refresh_cache(REFRESH_QUIET);
                if (0 <= fd)
-                       update_index_if_able(&the_index, &lock_file);
+                       repo_update_index_if_able(the_repository, &lock_file);
                rollback_lock_file(&lock_file);
 
                if (has_unstaged_changes(the_repository, 1) ||
@@ -1646,7 +1664,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                        putchar('\n');
 
                        if (discard_index(the_repository->index) < 0 ||
-                               read_index(the_repository->index) < 0)
+                               repo_read_index(the_repository) < 0)
                                die(_("could not read index"));
                }
        }
@@ -1764,7 +1782,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        strbuf_addf(&msg, "%s: checkout %s",
                    getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.onto_name);
        if (reset_head(&options.onto->object.oid, "checkout", NULL,
-                      RESET_HEAD_DETACH | RESET_HEAD_RUN_POST_CHECKOUT_HOOK,
+                      RESET_HEAD_DETACH | RESET_ORIG_HEAD | 
+                      RESET_HEAD_RUN_POST_CHECKOUT_HOOK,
                       NULL, msg.buf))
                die(_("Could not detach HEAD"));
        strbuf_release(&msg);
@@ -1780,8 +1799,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                strbuf_addf(&msg, "rebase finished: %s onto %s",
                        options.head_name ? options.head_name : "detached HEAD",
                        oid_to_hex(&options.onto->object.oid));
-               reset_head(NULL, "Fast-forwarded", options.head_name, 0,
-                          "HEAD", msg.buf);
+               reset_head(NULL, "Fast-forwarded", options.head_name,
+                          RESET_HEAD_REFS_ONLY, "HEAD", msg.buf);
                strbuf_release(&msg);
                ret = !!finish_rebase(&options);
                goto cleanup;