Git fork
1#define USE_THE_REPOSITORY_VARIABLE
2
3#include "git-compat-util.h"
4#include "builtin.h"
5#include "parse-options.h"
6#include "diff.h"
7#include "environment.h"
8#include "gettext.h"
9#include "revision.h"
10#include "rerere.h"
11#include "sequencer.h"
12#include "branch.h"
13
14/*
15 * This implements the builtins revert and cherry-pick.
16 *
17 * Copyright (c) 2007 Johannes E. Schindelin
18 *
19 * Based on git-revert.sh, which is
20 *
21 * Copyright (c) 2005 Linus Torvalds
22 * Copyright (c) 2005 Junio C Hamano
23 */
24
25static const char * const revert_usage[] = {
26 N_("git revert [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] <commit>..."),
27 N_("git revert (--continue | --skip | --abort | --quit)"),
28 NULL
29};
30
31static const char * const cherry_pick_usage[] = {
32 N_("git cherry-pick [--edit] [-n] [-m <parent-number>] [-s] [-x] [--ff]\n"
33 " [-S[<keyid>]] <commit>..."),
34 N_("git cherry-pick (--continue | --skip | --abort | --quit)"),
35 NULL
36};
37
38static const char *action_name(const struct replay_opts *opts)
39{
40 return opts->action == REPLAY_REVERT ? "revert" : "cherry-pick";
41}
42
43static const char * const *revert_or_cherry_pick_usage(struct replay_opts *opts)
44{
45 return opts->action == REPLAY_REVERT ? revert_usage : cherry_pick_usage;
46}
47
48enum empty_action {
49 EMPTY_COMMIT_UNSPECIFIED = -1,
50 STOP_ON_EMPTY_COMMIT, /* output errors and stop in the middle of a cherry-pick */
51 DROP_EMPTY_COMMIT, /* skip with a notice message */
52 KEEP_EMPTY_COMMIT, /* keep recording as empty commits */
53};
54
55static int parse_opt_empty(const struct option *opt, const char *arg, int unset)
56{
57 int *opt_value = opt->value;
58
59 BUG_ON_OPT_NEG(unset);
60
61 if (!strcmp(arg, "stop"))
62 *opt_value = STOP_ON_EMPTY_COMMIT;
63 else if (!strcmp(arg, "drop"))
64 *opt_value = DROP_EMPTY_COMMIT;
65 else if (!strcmp(arg, "keep"))
66 *opt_value = KEEP_EMPTY_COMMIT;
67 else
68 return error(_("invalid value for '%s': '%s'"), "--empty", arg);
69
70 return 0;
71}
72
73static int option_parse_m(const struct option *opt,
74 const char *arg, int unset)
75{
76 struct replay_opts *replay = opt->value;
77 char *end;
78
79 if (unset) {
80 replay->mainline = 0;
81 return 0;
82 }
83
84 replay->mainline = strtol(arg, &end, 10);
85 if (*end || replay->mainline <= 0)
86 return error(_("option `%s' expects a number greater than zero"),
87 opt->long_name);
88
89 return 0;
90}
91
92LAST_ARG_MUST_BE_NULL
93static void verify_opt_compatible(const char *me, const char *base_opt, ...)
94{
95 const char *this_opt;
96 va_list ap;
97
98 va_start(ap, base_opt);
99 while ((this_opt = va_arg(ap, const char *))) {
100 if (va_arg(ap, int))
101 break;
102 }
103 va_end(ap);
104
105 if (this_opt)
106 die(_("%s: %s cannot be used with %s"), me, this_opt, base_opt);
107}
108
109static int run_sequencer(int argc, const char **argv, const char *prefix,
110 struct replay_opts *opts)
111{
112 const char * const * usage_str = revert_or_cherry_pick_usage(opts);
113 const char *me = action_name(opts);
114 const char *cleanup_arg = NULL;
115 const char sentinel_value = 0; /* value not important */
116 const char *strategy = &sentinel_value;
117 const char *gpg_sign = &sentinel_value;
118 enum empty_action empty_opt = EMPTY_COMMIT_UNSPECIFIED;
119 int cmd = 0;
120 struct option base_options[] = {
121 OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
122 OPT_CMDMODE(0, "continue", &cmd, N_("resume revert or cherry-pick sequence"), 'c'),
123 OPT_CMDMODE(0, "abort", &cmd, N_("cancel revert or cherry-pick sequence"), 'a'),
124 OPT_CMDMODE(0, "skip", &cmd, N_("skip current commit and continue"), 's'),
125 OPT_CLEANUP(&cleanup_arg),
126 OPT_BOOL('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
127 OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
128 OPT_NOOP_NOARG('r', NULL),
129 OPT_BOOL('s', "signoff", &opts->signoff, N_("add a Signed-off-by trailer")),
130 OPT_CALLBACK('m', "mainline", opts, N_("parent-number"),
131 N_("select mainline parent"), option_parse_m),
132 OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),
133 OPT_STRING(0, "strategy", &strategy, N_("strategy"), N_("merge strategy")),
134 OPT_STRVEC('X', "strategy-option", &opts->xopts, N_("option"),
135 N_("option for merge strategy")),
136 {
137 .type = OPTION_STRING,
138 .short_name = 'S',
139 .long_name = "gpg-sign",
140 .value = &gpg_sign,
141 .argh = N_("key-id"),
142 .help = N_("GPG sign commit"),
143 .flags = PARSE_OPT_OPTARG,
144 .defval = (intptr_t) "",
145 },
146 OPT_END()
147 };
148 struct option *options = base_options;
149
150 if (opts->action == REPLAY_PICK) {
151 struct option cp_extra[] = {
152 OPT_BOOL('x', NULL, &opts->record_origin, N_("append commit name")),
153 OPT_BOOL(0, "ff", &opts->allow_ff, N_("allow fast-forward")),
154 OPT_BOOL(0, "allow-empty", &opts->allow_empty, N_("preserve initially empty commits")),
155 OPT_BOOL(0, "allow-empty-message", &opts->allow_empty_message, N_("allow commits with empty messages")),
156 OPT_BOOL(0, "keep-redundant-commits", &opts->keep_redundant_commits, N_("deprecated: use --empty=keep instead")),
157 OPT_CALLBACK_F(0, "empty", &empty_opt, "(stop|drop|keep)",
158 N_("how to handle commits that become empty"),
159 PARSE_OPT_NONEG, parse_opt_empty),
160 OPT_END(),
161 };
162 options = parse_options_concat(options, cp_extra);
163 } else if (opts->action == REPLAY_REVERT) {
164 struct option cp_extra[] = {
165 OPT_BOOL(0, "reference", &opts->commit_use_reference,
166 N_("use the 'reference' format to refer to commits")),
167 OPT_END(),
168 };
169 options = parse_options_concat(options, cp_extra);
170 }
171
172 argc = parse_options(argc, argv, prefix, options, usage_str,
173 PARSE_OPT_KEEP_ARGV0 |
174 PARSE_OPT_KEEP_UNKNOWN_OPT);
175
176 prepare_repo_settings(the_repository);
177 the_repository->settings.command_requires_full_index = 0;
178
179 if (opts->action == REPLAY_PICK) {
180 opts->drop_redundant_commits = (empty_opt == DROP_EMPTY_COMMIT);
181 opts->keep_redundant_commits = opts->keep_redundant_commits || (empty_opt == KEEP_EMPTY_COMMIT);
182 }
183
184 /* implies allow_empty */
185 if (opts->keep_redundant_commits)
186 opts->allow_empty = 1;
187
188 if (cleanup_arg) {
189 opts->default_msg_cleanup = get_cleanup_mode(cleanup_arg, 1);
190 opts->explicit_cleanup = 1;
191 }
192
193 /* Check for incompatible command line arguments */
194 if (cmd) {
195 const char *this_operation;
196 if (cmd == 'q')
197 this_operation = "--quit";
198 else if (cmd == 'c')
199 this_operation = "--continue";
200 else if (cmd == 's')
201 this_operation = "--skip";
202 else {
203 assert(cmd == 'a');
204 this_operation = "--abort";
205 }
206
207 verify_opt_compatible(me, this_operation,
208 "--no-commit", opts->no_commit,
209 "--signoff", opts->signoff,
210 "--mainline", opts->mainline,
211 "--strategy", opts->strategy ? 1 : 0,
212 "--strategy-option", opts->xopts.nr ? 1 : 0,
213 "-x", opts->record_origin,
214 "--ff", opts->allow_ff,
215 "--rerere-autoupdate", opts->allow_rerere_auto == RERERE_AUTOUPDATE,
216 "--no-rerere-autoupdate", opts->allow_rerere_auto == RERERE_NOAUTOUPDATE,
217 "--keep-redundant-commits", opts->keep_redundant_commits,
218 "--empty", empty_opt != EMPTY_COMMIT_UNSPECIFIED,
219 NULL);
220 }
221
222 if (!opts->strategy && opts->default_strategy) {
223 opts->strategy = opts->default_strategy;
224 opts->default_strategy = NULL;
225 }
226
227 if (opts->allow_ff)
228 verify_opt_compatible(me, "--ff",
229 "--signoff", opts->signoff,
230 "--no-commit", opts->no_commit,
231 "-x", opts->record_origin,
232 "--edit", opts->edit > 0,
233 NULL);
234
235 if (cmd) {
236 opts->revs = NULL;
237 } else {
238 struct setup_revision_opt s_r_opt;
239 opts->revs = xmalloc(sizeof(*opts->revs));
240 repo_init_revisions(the_repository, opts->revs, NULL);
241 opts->revs->no_walk = 1;
242 opts->revs->unsorted_input = 1;
243 if (argc < 2)
244 usage_with_options(usage_str, options);
245 if (!strcmp(argv[1], "-"))
246 argv[1] = "@{-1}";
247 memset(&s_r_opt, 0, sizeof(s_r_opt));
248 s_r_opt.assume_dashdash = 1;
249 argc = setup_revisions(argc, argv, opts->revs, &s_r_opt);
250 }
251
252 if (argc > 1)
253 usage_with_options(usage_str, options);
254
255 /* These option values will be free()d */
256 if (gpg_sign != &sentinel_value) {
257 free(opts->gpg_sign);
258 opts->gpg_sign = xstrdup_or_null(gpg_sign);
259 }
260 if (strategy != &sentinel_value) {
261 free(opts->strategy);
262 opts->strategy = xstrdup_or_null(strategy);
263 }
264 free(options);
265
266 if (cmd == 'q') {
267 int ret = sequencer_remove_state(opts);
268 if (!ret)
269 remove_branch_state(the_repository, 0);
270 return ret;
271 }
272 if (cmd == 'c')
273 return sequencer_continue(the_repository, opts);
274 if (cmd == 'a')
275 return sequencer_rollback(the_repository, opts);
276 if (cmd == 's')
277 return sequencer_skip(the_repository, opts);
278 return sequencer_pick_revisions(the_repository, opts);
279}
280
281int cmd_revert(int argc,
282 const char **argv,
283 const char *prefix,
284 struct repository *repo UNUSED)
285{
286 struct replay_opts opts = REPLAY_OPTS_INIT;
287 int res;
288
289#ifndef WITH_BREAKING_CHANGES
290 warn_on_auto_comment_char = true;
291#endif /* !WITH_BREAKING_CHANGES */
292 opts.action = REPLAY_REVERT;
293 sequencer_init_config(&opts);
294 res = run_sequencer(argc, argv, prefix, &opts);
295 if (res < 0)
296 die(_("revert failed"));
297 replay_opts_release(&opts);
298 return res;
299}
300
301int cmd_cherry_pick(int argc,
302const char **argv,
303const char *prefix,
304struct repository *repo UNUSED)
305{
306 struct replay_opts opts = REPLAY_OPTS_INIT;
307 int res;
308
309#ifndef WITH_BREAKING_CHANGES
310 warn_on_auto_comment_char = true;
311#endif /* !WITH_BREAKING_CHANGES */
312 opts.action = REPLAY_PICK;
313 sequencer_init_config(&opts);
314 res = run_sequencer(argc, argv, prefix, &opts);
315 if (res < 0)
316 die(_("cherry-pick failed"));
317 replay_opts_release(&opts);
318 return res;
319}