builtin / revert.con commit t3512/t3513: remove KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1 (db9476b)
   1#include "cache.h"
   2#include "config.h"
   3#include "builtin.h"
   4#include "parse-options.h"
   5#include "diff.h"
   6#include "revision.h"
   7#include "rerere.h"
   8#include "dir.h"
   9#include "sequencer.h"
  10
  11/*
  12 * This implements the builtins revert and cherry-pick.
  13 *
  14 * Copyright (c) 2007 Johannes E. Schindelin
  15 *
  16 * Based on git-revert.sh, which is
  17 *
  18 * Copyright (c) 2005 Linus Torvalds
  19 * Copyright (c) 2005 Junio C Hamano
  20 */
  21
  22static const char * const revert_usage[] = {
  23        N_("git revert [<options>] <commit-ish>..."),
  24        N_("git revert <subcommand>"),
  25        NULL
  26};
  27
  28static const char * const cherry_pick_usage[] = {
  29        N_("git cherry-pick [<options>] <commit-ish>..."),
  30        N_("git cherry-pick <subcommand>"),
  31        NULL
  32};
  33
  34static int common_config(const char *k, const char *v, void *cb)
  35{
  36        int status;
  37
  38        status = git_sequencer_config(k, v, NULL);
  39        if (status)
  40                return status;
  41
  42        return git_default_config(k, v, NULL);
  43}
  44
  45static const char *action_name(const struct replay_opts *opts)
  46{
  47        return opts->action == REPLAY_REVERT ? "revert" : "cherry-pick";
  48}
  49
  50static const char * const *revert_or_cherry_pick_usage(struct replay_opts *opts)
  51{
  52        return opts->action == REPLAY_REVERT ? revert_usage : cherry_pick_usage;
  53}
  54
  55static int option_parse_x(const struct option *opt,
  56                          const char *arg, int unset)
  57{
  58        struct replay_opts **opts_ptr = opt->value;
  59        struct replay_opts *opts = *opts_ptr;
  60
  61        if (unset)
  62                return 0;
  63
  64        ALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);
  65        opts->xopts[opts->xopts_nr++] = xstrdup(arg);
  66        return 0;
  67}
  68
  69static int option_parse_m(const struct option *opt,
  70                          const char *arg, int unset)
  71{
  72        struct replay_opts *replay = opt->value;
  73        char *end;
  74
  75        if (unset) {
  76                replay->mainline = 0;
  77                return 0;
  78        }
  79
  80        replay->mainline = strtol(arg, &end, 10);
  81        if (*end || replay->mainline <= 0)
  82                return opterror(opt, "expects a number greater than zero", 0);
  83
  84        return 0;
  85}
  86
  87LAST_ARG_MUST_BE_NULL
  88static void verify_opt_compatible(const char *me, const char *base_opt, ...)
  89{
  90        const char *this_opt;
  91        va_list ap;
  92
  93        va_start(ap, base_opt);
  94        while ((this_opt = va_arg(ap, const char *))) {
  95                if (va_arg(ap, int))
  96                        break;
  97        }
  98        va_end(ap);
  99
 100        if (this_opt)
 101                die(_("%s: %s cannot be used with %s"), me, this_opt, base_opt);
 102}
 103
 104static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 105{
 106        const char * const * usage_str = revert_or_cherry_pick_usage(opts);
 107        const char *me = action_name(opts);
 108        int cmd = 0;
 109        struct option base_options[] = {
 110                OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
 111                OPT_CMDMODE(0, "continue", &cmd, N_("resume revert or cherry-pick sequence"), 'c'),
 112                OPT_CMDMODE(0, "abort", &cmd, N_("cancel revert or cherry-pick sequence"), 'a'),
 113                OPT_BOOL('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
 114                OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
 115                OPT_NOOP_NOARG('r', NULL),
 116                OPT_BOOL('s', "signoff", &opts->signoff, N_("add Signed-off-by:")),
 117                OPT_CALLBACK('m', "mainline", opts, N_("parent-number"),
 118                             N_("select mainline parent"), option_parse_m),
 119                OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),
 120                OPT_STRING(0, "strategy", &opts->strategy, N_("strategy"), N_("merge strategy")),
 121                OPT_CALLBACK('X', "strategy-option", &opts, N_("option"),
 122                        N_("option for merge strategy"), option_parse_x),
 123                { OPTION_STRING, 'S', "gpg-sign", &opts->gpg_sign, N_("key-id"),
 124                  N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
 125                OPT_END()
 126        };
 127        struct option *options = base_options;
 128
 129        if (opts->action == REPLAY_PICK) {
 130                struct option cp_extra[] = {
 131                        OPT_BOOL('x', NULL, &opts->record_origin, N_("append commit name")),
 132                        OPT_BOOL(0, "ff", &opts->allow_ff, N_("allow fast-forward")),
 133                        OPT_BOOL(0, "allow-empty", &opts->allow_empty, N_("preserve initially empty commits")),
 134                        OPT_BOOL(0, "allow-empty-message", &opts->allow_empty_message, N_("allow commits with empty messages")),
 135                        OPT_BOOL(0, "keep-redundant-commits", &opts->keep_redundant_commits, N_("keep redundant, empty commits")),
 136                        OPT_END(),
 137                };
 138                options = parse_options_concat(options, cp_extra);
 139        }
 140
 141        argc = parse_options(argc, argv, NULL, options, usage_str,
 142                        PARSE_OPT_KEEP_ARGV0 |
 143                        PARSE_OPT_KEEP_UNKNOWN);
 144
 145        /* implies allow_empty */
 146        if (opts->keep_redundant_commits)
 147                opts->allow_empty = 1;
 148
 149        /* Check for incompatible command line arguments */
 150        if (cmd) {
 151                char *this_operation;
 152                if (cmd == 'q')
 153                        this_operation = "--quit";
 154                else if (cmd == 'c')
 155                        this_operation = "--continue";
 156                else {
 157                        assert(cmd == 'a');
 158                        this_operation = "--abort";
 159                }
 160
 161                verify_opt_compatible(me, this_operation,
 162                                "--no-commit", opts->no_commit,
 163                                "--signoff", opts->signoff,
 164                                "--mainline", opts->mainline,
 165                                "--strategy", opts->strategy ? 1 : 0,
 166                                "--strategy-option", opts->xopts ? 1 : 0,
 167                                "-x", opts->record_origin,
 168                                "--ff", opts->allow_ff,
 169                                "--rerere-autoupdate", opts->allow_rerere_auto == RERERE_AUTOUPDATE,
 170                                "--no-rerere-autoupdate", opts->allow_rerere_auto == RERERE_NOAUTOUPDATE,
 171                                NULL);
 172        }
 173
 174        if (opts->allow_ff)
 175                verify_opt_compatible(me, "--ff",
 176                                "--signoff", opts->signoff,
 177                                "--no-commit", opts->no_commit,
 178                                "-x", opts->record_origin,
 179                                "--edit", opts->edit,
 180                                NULL);
 181
 182        if (cmd) {
 183                opts->revs = NULL;
 184        } else {
 185                struct setup_revision_opt s_r_opt;
 186                opts->revs = xmalloc(sizeof(*opts->revs));
 187                init_revisions(opts->revs, NULL);
 188                opts->revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED;
 189                if (argc < 2)
 190                        usage_with_options(usage_str, options);
 191                if (!strcmp(argv[1], "-"))
 192                        argv[1] = "@{-1}";
 193                memset(&s_r_opt, 0, sizeof(s_r_opt));
 194                s_r_opt.assume_dashdash = 1;
 195                argc = setup_revisions(argc, argv, opts->revs, &s_r_opt);
 196        }
 197
 198        if (argc > 1)
 199                usage_with_options(usage_str, options);
 200
 201        /* These option values will be free()d */
 202        opts->gpg_sign = xstrdup_or_null(opts->gpg_sign);
 203        opts->strategy = xstrdup_or_null(opts->strategy);
 204
 205        if (cmd == 'q')
 206                return sequencer_remove_state(opts);
 207        if (cmd == 'c')
 208                return sequencer_continue(opts);
 209        if (cmd == 'a')
 210                return sequencer_rollback(opts);
 211        return sequencer_pick_revisions(opts);
 212}
 213
 214int cmd_revert(int argc, const char **argv, const char *prefix)
 215{
 216        struct replay_opts opts = REPLAY_OPTS_INIT;
 217        int res;
 218
 219        if (isatty(0))
 220                opts.edit = 1;
 221        opts.action = REPLAY_REVERT;
 222        git_config(common_config, NULL);
 223        res = run_sequencer(argc, argv, &opts);
 224        if (res < 0)
 225                die(_("revert failed"));
 226        return res;
 227}
 228
 229int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
 230{
 231        struct replay_opts opts = REPLAY_OPTS_INIT;
 232        int res;
 233
 234        opts.action = REPLAY_PICK;
 235        git_config(common_config, NULL);
 236        res = run_sequencer(argc, argv, &opts);
 237        if (res < 0)
 238                die(_("cherry-pick failed"));
 239        return res;
 240}