sequencer: factor code out of revert builtin

Expose the cherry-picking machinery through a public sequencer_pick_revisions() (renamed from pick_revisions() in builtin/revert.c), so that cherry-picking and reverting are special cases of a general sequencer operation. The cherry-pick builtin is now a thin wrapper that does command-line argument parsing before calling into sequencer_pick_revisions(). In the future, we can write a new "foo" builtin that calls into the sequencer like: memset(&opts, 0, sizeof(opts)); opts.action = REPLAY_FOO; opts.revisions = xmalloc(sizeof(*opts.revs)); parse_args_populate_opts(argc, argv, &opts); init_revisions(opts.revs); sequencer_pick_revisions(&opts); This patch does not intend to make any functional changes. Check with: $ git blame -s -C HEAD^..HEAD -- sequencer.c | grep -C3 '^[^^]' Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com> Reviewed-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Ramkumar Ramachandra committed Jan 11, 2012 at 23:45 UTC 043a4492b3b7da6496617201c369cff6ab7c26f2
3 files changed +956 -947
builtin/revert.c
+2 -946
@@ -1,18 +1,9 @@
1 #include "cache.h"
2 #include "builtin.h"
3 -#include "object.h"
4 -#include "commit.h"
5 -#include "tag.h"
6 -#include "run-command.h"
7 -#include "exec_cmd.h"
8 -#include "utf8.h"
3 #include "parse-options.h"
10 -#include "cache-tree.h"
4 #include "diff.h"
5 #include "revision.h"
6 #include "rerere.h"
14 -#include "merge-recursive.h"
15 -#include "refs.h"
7 #include "dir.h"
8 #include "sequencer.h"
9
@@ -39,50 +30,11 @@ static const char * const cherry_pick_usage[] = {
30 NULL
31 };
32
42 -enum replay_action {
43 - REPLAY_REVERT,
44 - REPLAY_PICK
45 -};
46 -
47 -enum replay_subcommand {
48 - REPLAY_NONE,
49 - REPLAY_REMOVE_STATE,
50 - REPLAY_CONTINUE,
51 - REPLAY_ROLLBACK
52 -};
53 -
54 -struct replay_opts {
55 - enum replay_action action;
56 - enum replay_subcommand subcommand;
57 -
58 - /* Boolean options */
59 - int edit;
60 - int record_origin;
61 - int no_commit;
62 - int signoff;
63 - int allow_ff;
64 - int allow_rerere_auto;
65 -
66 - int mainline;
67 -
68 - /* Merge strategy */
69 - const char *strategy;
70 - const char **xopts;
71 - size_t xopts_nr, xopts_alloc;
72 -
73 - /* Only used by REPLAY_NONE */
74 - struct rev_info *revs;
75 -};
76 -
77 -#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
78 -
33 static const char *action_name(const struct replay_opts *opts)
34 {
35 return opts->action == REPLAY_REVERT ? "revert" : "cherry-pick";
36 }
37
84 -static char *get_encoding(const char *message);
85 -
38 static const char * const *revert_or_cherry_pick_usage(struct replay_opts *opts)
39 {
40 return opts->action == REPLAY_REVERT ? revert_usage : cherry_pick_usage;
@@ -241,902 +193,6 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
193 usage_with_options(usage_str, options);
194 }
195
244 -struct commit_message {
245 - char *parent_label;
246 - const char *label;
247 - const char *subject;
248 - char *reencoded_message;
249 - const char *message;
250 -};
251 -
252 -static int get_message(struct commit *commit, struct commit_message *out)
253 -{
254 - const char *encoding;
255 - const char *abbrev, *subject;
256 - int abbrev_len, subject_len;
257 - char *q;
258 -
259 - if (!commit->buffer)
260 - return -1;
261 - encoding = get_encoding(commit->buffer);
262 - if (!encoding)
263 - encoding = "UTF-8";
264 - if (!git_commit_encoding)
265 - git_commit_encoding = "UTF-8";
266 -
267 - out->reencoded_message = NULL;
268 - out->message = commit->buffer;
269 - if (strcmp(encoding, git_commit_encoding))
270 - out->reencoded_message = reencode_string(commit->buffer,
271 - git_commit_encoding, encoding);
272 - if (out->reencoded_message)
273 - out->message = out->reencoded_message;
274 -
275 - abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
276 - abbrev_len = strlen(abbrev);
277 -
278 - subject_len = find_commit_subject(out->message, &subject);
279 -
280 - out->parent_label = xmalloc(strlen("parent of ") + abbrev_len +
281 - strlen("... ") + subject_len + 1);
282 - q = out->parent_label;
283 - q = mempcpy(q, "parent of ", strlen("parent of "));
284 - out->label = q;
285 - q = mempcpy(q, abbrev, abbrev_len);
286 - q = mempcpy(q, "... ", strlen("... "));
287 - out->subject = q;
288 - q = mempcpy(q, subject, subject_len);
289 - *q = '\0';
290 - return 0;
291 -}
292 -
293 -static void free_message(struct commit_message *msg)
294 -{
295 - free(msg->parent_label);
296 - free(msg->reencoded_message);
297 -}
298 -
299 -static char *get_encoding(const char *message)
300 -{
301 - const char *p = message, *eol;
302 -
303 - while (*p && *p != '\n') {
304 - for (eol = p + 1; *eol && *eol != '\n'; eol++)
305 - ; /* do nothing */
306 - if (!prefixcmp(p, "encoding ")) {
307 - char *result = xmalloc(eol - 8 - p);
308 - strlcpy(result, p + 9, eol - 8 - p);
309 - return result;
310 - }
311 - p = eol;
312 - if (*p == '\n')
313 - p++;
314 - }
315 - return NULL;
316 -}
317 -
318 -static void write_cherry_pick_head(struct commit *commit, const char *pseudoref)
319 -{
320 - const char *filename;
321 - int fd;
322 - struct strbuf buf = STRBUF_INIT;
323 -
324 - strbuf_addf(&buf, "%s\n", sha1_to_hex(commit->object.sha1));
325 -
326 - filename = git_path("%s", pseudoref);
327 - fd = open(filename, O_WRONLY | O_CREAT, 0666);
328 - if (fd < 0)
329 - die_errno(_("Could not open '%s' for writing"), filename);
330 - if (write_in_full(fd, buf.buf, buf.len) != buf.len || close(fd))
331 - die_errno(_("Could not write to '%s'"), filename);
332 - strbuf_release(&buf);
333 -}
334 -
335 -static void print_advice(int show_hint)
336 -{
337 - char *msg = getenv("GIT_CHERRY_PICK_HELP");
338 -
339 - if (msg) {
340 - fprintf(stderr, "%s\n", msg);
341 - /*
342 - * A conflict has occured but the porcelain
343 - * (typically rebase --interactive) wants to take care
344 - * of the commit itself so remove CHERRY_PICK_HEAD
345 - */
346 - unlink(git_path("CHERRY_PICK_HEAD"));
347 - return;
348 - }
349 -
350 - if (show_hint) {
351 - advise("after resolving the conflicts, mark the corrected paths");
352 - advise("with 'git add <paths>' or 'git rm <paths>'");
353 - advise("and commit the result with 'git commit'");
354 - }
355 -}
356 -
357 -static void write_message(struct strbuf *msgbuf, const char *filename)
358 -{
359 - static struct lock_file msg_file;
360 -
361 - int msg_fd = hold_lock_file_for_update(&msg_file, filename,
362 - LOCK_DIE_ON_ERROR);
363 - if (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)
364 - die_errno(_("Could not write to %s"), filename);
365 - strbuf_release(msgbuf);
366 - if (commit_lock_file(&msg_file) < 0)
367 - die(_("Error wrapping up %s"), filename);
368 -}
369 -
370 -static struct tree *empty_tree(void)
371 -{
372 - return lookup_tree((const unsigned char *)EMPTY_TREE_SHA1_BIN);
373 -}
374 -
375 -static int error_dirty_index(struct replay_opts *opts)
376 -{
377 - if (read_cache_unmerged())
378 - return error_resolve_conflict(action_name(opts));
379 -
380 - /* Different translation strings for cherry-pick and revert */
381 - if (opts->action == REPLAY_PICK)
382 - error(_("Your local changes would be overwritten by cherry-pick."));
383 - else
384 - error(_("Your local changes would be overwritten by revert."));
385 -
386 - if (advice_commit_before_merge)
387 - advise(_("Commit your changes or stash them to proceed."));
388 - return -1;
389 -}
390 -
391 -static int fast_forward_to(const unsigned char *to, const unsigned char *from)
392 -{
393 - struct ref_lock *ref_lock;
394 -
395 - read_cache();
396 - if (checkout_fast_forward(from, to))
397 - exit(1); /* the callee should have complained already */
398 - ref_lock = lock_any_ref_for_update("HEAD", from, 0);
399 - return write_ref_sha1(ref_lock, to, "cherry-pick");
400 -}
401 -
402 -static int do_recursive_merge(struct commit *base, struct commit *next,
403 - const char *base_label, const char *next_label,
404 - unsigned char *head, struct strbuf *msgbuf,
405 - struct replay_opts *opts)
406 -{
407 - struct merge_options o;
408 - struct tree *result, *next_tree, *base_tree, *head_tree;
409 - int clean, index_fd;
410 - const char **xopt;
411 - static struct lock_file index_lock;
412 -
413 - index_fd = hold_locked_index(&index_lock, 1);
414 -
415 - read_cache();
416 -
417 - init_merge_options(&o);
418 - o.ancestor = base ? base_label : "(empty tree)";
419 - o.branch1 = "HEAD";
420 - o.branch2 = next ? next_label : "(empty tree)";
421 -
422 - head_tree = parse_tree_indirect(head);
423 - next_tree = next ? next->tree : empty_tree();
424 - base_tree = base ? base->tree : empty_tree();
425 -
426 - for (xopt = opts->xopts; xopt != opts->xopts + opts->xopts_nr; xopt++)
427 - parse_merge_opt(&o, *xopt);
428 -
429 - clean = merge_trees(&o,
430 - head_tree,
431 - next_tree, base_tree, &result);
432 -
433 - if (active_cache_changed &&
434 - (write_cache(index_fd, active_cache, active_nr) ||
435 - commit_locked_index(&index_lock)))
436 - /* TRANSLATORS: %s will be "revert" or "cherry-pick" */
437 - die(_("%s: Unable to write new index file"), action_name(opts));
438 - rollback_lock_file(&index_lock);
439 -
440 - if (!clean) {
441 - int i;
442 - strbuf_addstr(msgbuf, "\nConflicts:\n\n");
443 - for (i = 0; i < active_nr;) {
444 - struct cache_entry *ce = active_cache[i++];
445 - if (ce_stage(ce)) {
446 - strbuf_addch(msgbuf, '\t');
447 - strbuf_addstr(msgbuf, ce->name);
448 - strbuf_addch(msgbuf, '\n');
449 - while (i < active_nr && !strcmp(ce->name,
450 - active_cache[i]->name))
451 - i++;
452 - }
453 - }
454 - }
455 -
456 - return !clean;
457 -}
458 -
459 -/*
460 - * If we are cherry-pick, and if the merge did not result in
461 - * hand-editing, we will hit this commit and inherit the original
462 - * author date and name.
463 - * If we are revert, or if our cherry-pick results in a hand merge,
464 - * we had better say that the current user is responsible for that.
465 - */
466 -static int run_git_commit(const char *defmsg, struct replay_opts *opts)
467 -{
468 - /* 6 is max possible length of our args array including NULL */
469 - const char *args[6];
470 - int i = 0;
471 -
472 - args[i++] = "commit";
473 - args[i++] = "-n";
474 - if (opts->signoff)
475 - args[i++] = "-s";
476 - if (!opts->edit) {
477 - args[i++] = "-F";
478 - args[i++] = defmsg;
479 - }
480 - args[i] = NULL;
481 -
482 - return run_command_v_opt(args, RUN_GIT_CMD);
483 -}
484 -
485 -static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
486 -{
487 - unsigned char head[20];
488 - struct commit *base, *next, *parent;
489 - const char *base_label, *next_label;
490 - struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
491 - char *defmsg = NULL;
492 - struct strbuf msgbuf = STRBUF_INIT;
493 - int res;
494 -
495 - if (opts->no_commit) {
496 - /*
497 - * We do not intend to commit immediately. We just want to
498 - * merge the differences in, so let's compute the tree
499 - * that represents the "current" state for merge-recursive
500 - * to work on.
501 - */
502 - if (write_cache_as_tree(head, 0, NULL))
503 - die (_("Your index file is unmerged."));
504 - } else {
505 - if (get_sha1("HEAD", head))
506 - return error(_("You do not have a valid HEAD"));
507 - if (index_differs_from("HEAD", 0))
508 - return error_dirty_index(opts);
509 - }
510 - discard_cache();
511 -
512 - if (!commit->parents) {
513 - parent = NULL;
514 - }
515 - else if (commit->parents->next) {
516 - /* Reverting or cherry-picking a merge commit */
517 - int cnt;
518 - struct commit_list *p;
519 -
520 - if (!opts->mainline)
521 - return error(_("Commit %s is a merge but no -m option was given."),
522 - sha1_to_hex(commit->object.sha1));
523 -
524 - for (cnt = 1, p = commit->parents;
525 - cnt != opts->mainline && p;
526 - cnt++)
527 - p = p->next;
528 - if (cnt != opts->mainline || !p)
529 - return error(_("Commit %s does not have parent %d"),
530 - sha1_to_hex(commit->object.sha1), opts->mainline);
531 - parent = p->item;
532 - } else if (0 < opts->mainline)
533 - return error(_("Mainline was specified but commit %s is not a merge."),
534 - sha1_to_hex(commit->object.sha1));
535 - else
536 - parent = commit->parents->item;
537 -
538 - if (opts->allow_ff && parent && !hashcmp(parent->object.sha1, head))
539 - return fast_forward_to(commit->object.sha1, head);
540 -
541 - if (parent && parse_commit(parent) < 0)
542 - /* TRANSLATORS: The first %s will be "revert" or
543 - "cherry-pick", the second %s a SHA1 */
544 - return error(_("%s: cannot parse parent commit %s"),
545 - action_name(opts), sha1_to_hex(parent->object.sha1));
546 -
547 - if (get_message(commit, &msg) != 0)
548 - return error(_("Cannot get commit message for %s"),
549 - sha1_to_hex(commit->object.sha1));
550 -
551 - /*
552 - * "commit" is an existing commit. We would want to apply
553 - * the difference it introduces since its first parent "prev"
554 - * on top of the current HEAD if we are cherry-pick. Or the
555 - * reverse of it if we are revert.
556 - */
557 -
558 - defmsg = git_pathdup("MERGE_MSG");
559 -
560 - if (opts->action == REPLAY_REVERT) {
561 - base = commit;
562 - base_label = msg.label;
563 - next = parent;
564 - next_label = msg.parent_label;
565 - strbuf_addstr(&msgbuf, "Revert \"");
566 - strbuf_addstr(&msgbuf, msg.subject);
567 - strbuf_addstr(&msgbuf, "\"\n\nThis reverts commit ");
568 - strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
569 -
570 - if (commit->parents && commit->parents->next) {
571 - strbuf_addstr(&msgbuf, ", reversing\nchanges made to ");
572 - strbuf_addstr(&msgbuf, sha1_to_hex(parent->object.sha1));
573 - }
574 - strbuf_addstr(&msgbuf, ".\n");
575 - } else {
576 - const char *p;
577 -
578 - base = parent;
579 - base_label = msg.parent_label;
580 - next = commit;
581 - next_label = msg.label;
582 -
583 - /*
584 - * Append the commit log message to msgbuf; it starts
585 - * after the tree, parent, author, committer
586 - * information followed by "\n\n".
587 - */
588 - p = strstr(msg.message, "\n\n");
589 - if (p) {
590 - p += 2;
591 - strbuf_addstr(&msgbuf, p);
592 - }
593 -
594 - if (opts->record_origin) {
595 - strbuf_addstr(&msgbuf, "(cherry picked from commit ");
596 - strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
597 - strbuf_addstr(&msgbuf, ")\n");
598 - }
599 - }
600 -
601 - if (!opts->strategy || !strcmp(opts->strategy, "recursive") || opts->action == REPLAY_REVERT) {
602 - res = do_recursive_merge(base, next, base_label, next_label,
603 - head, &msgbuf, opts);
604 - write_message(&msgbuf, defmsg);
605 - } else {
606 - struct commit_list *common = NULL;
607 - struct commit_list *remotes = NULL;
608 -
609 - write_message(&msgbuf, defmsg);
610 -
611 - commit_list_insert(base, &common);
612 - commit_list_insert(next, &remotes);
613 - res = try_merge_command(opts->strategy, opts->xopts_nr, opts->xopts,
614 - common, sha1_to_hex(head), remotes);
615 - free_commit_list(common);
616 - free_commit_list(remotes);
617 - }
618 -
619 - /*
620 - * If the merge was clean or if it failed due to conflict, we write
621 - * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.
622 - * However, if the merge did not even start, then we don't want to
623 - * write it at all.
624 - */
625 - if (opts->action == REPLAY_PICK && !opts->no_commit && (res == 0 || res == 1))
626 - write_cherry_pick_head(commit, "CHERRY_PICK_HEAD");
627 - if (opts->action == REPLAY_REVERT && ((opts->no_commit && res == 0) || res == 1))
628 - write_cherry_pick_head(commit, "REVERT_HEAD");
629 -
630 - if (res) {
631 - error(opts->action == REPLAY_REVERT
632 - ? _("could not revert %s... %s")
633 - : _("could not apply %s... %s"),
634 - find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV),
635 - msg.subject);
636 - print_advice(res == 1);
637 - rerere(opts->allow_rerere_auto);
638 - } else {
639 - if (!opts->no_commit)
640 - res = run_git_commit(defmsg, opts);
641 - }
642 -
643 - free_message(&msg);
644 - free(defmsg);
645 -
646 - return res;
647 -}
648 -
649 -static void prepare_revs(struct replay_opts *opts)
650 -{
651 - if (opts->action != REPLAY_REVERT)
652 - opts->revs->reverse ^= 1;
653 -
654 - if (prepare_revision_walk(opts->revs))
655 - die(_("revision walk setup failed"));
656 -
657 - if (!opts->revs->commits)
658 - die(_("empty commit set passed"));
659 -}
660 -
661 -static void read_and_refresh_cache(struct replay_opts *opts)
662 -{
663 - static struct lock_file index_lock;
664 - int index_fd = hold_locked_index(&index_lock, 0);
665 - if (read_index_preload(&the_index, NULL) < 0)
666 - die(_("git %s: failed to read the index"), action_name(opts));
667 - refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);
668 - if (the_index.cache_changed) {
669 - if (write_index(&the_index, index_fd) ||
670 - commit_locked_index(&index_lock))
671 - die(_("git %s: failed to refresh the index"), action_name(opts));
672 - }
673 - rollback_lock_file(&index_lock);
674 -}
675 -
676 -/*
677 - * Append a commit to the end of the commit_list.
678 - *
679 - * next starts by pointing to the variable that holds the head of an
680 - * empty commit_list, and is updated to point to the "next" field of
681 - * the last item on the list as new commits are appended.
682 - *
683 - * Usage example:
684 - *
685 - * struct commit_list *list;
686 - * struct commit_list **next = &list;
687 - *
688 - * next = commit_list_append(c1, next);
689 - * next = commit_list_append(c2, next);
690 - * assert(commit_list_count(list) == 2);
691 - * return list;
692 - */
693 -static struct commit_list **commit_list_append(struct commit *commit,
694 - struct commit_list **next)
695 -{
696 - struct commit_list *new = xmalloc(sizeof(struct commit_list));
697 - new->item = commit;
698 - *next = new;
699 - new->next = NULL;
700 - return &new->next;
701 -}
702 -
703 -static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
704 - struct replay_opts *opts)
705 -{
706 - struct commit_list *cur = NULL;
707 - const char *sha1_abbrev = NULL;
708 - const char *action_str = opts->action == REPLAY_REVERT ? "revert" : "pick";
709 - const char *subject;
710 - int subject_len;
711 -
712 - for (cur = todo_list; cur; cur = cur->next) {
713 - sha1_abbrev = find_unique_abbrev(cur->item->object.sha1, DEFAULT_ABBREV);
714 - subject_len = find_commit_subject(cur->item->buffer, &subject);
715 - strbuf_addf(buf, "%s %s %.*s\n", action_str, sha1_abbrev,
716 - subject_len, subject);
717 - }
718 - return 0;
719 -}
720 -
721 -static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)
722 -{
723 - unsigned char commit_sha1[20];
724 - enum replay_action action;
725 - char *end_of_object_name;
726 - int saved, status, padding;
727 -
728 - if (!prefixcmp(bol, "pick")) {
729 - action = REPLAY_PICK;
730 - bol += strlen("pick");
731 - } else if (!prefixcmp(bol, "revert")) {
732 - action = REPLAY_REVERT;
733 - bol += strlen("revert");
734 - } else
735 - return NULL;
736 -
737 - /* Eat up extra spaces/ tabs before object name */
738 - padding = strspn(bol, " \t");
739 - if (!padding)
740 - return NULL;
741 - bol += padding;
742 -
743 - end_of_object_name = bol + strcspn(bol, " \t\n");
744 - saved = *end_of_object_name;
745 - *end_of_object_name = '\0';
746 - status = get_sha1(bol, commit_sha1);
747 - *end_of_object_name = saved;
748 -
749 - /*
750 - * Verify that the action matches up with the one in
751 - * opts; we don't support arbitrary instructions
752 - */
753 - if (action != opts->action) {
754 - const char *action_str;
755 - action_str = action == REPLAY_REVERT ? "revert" : "cherry-pick";
756 - error(_("Cannot %s during a %s"), action_str, action_name(opts));
757 - return NULL;
758 - }
759 -
760 - if (status < 0)
761 - return NULL;
762 -
763 - return lookup_commit_reference(commit_sha1);
764 -}
765 -
766 -static int parse_insn_buffer(char *buf, struct commit_list **todo_list,
767 - struct replay_opts *opts)
768 -{
769 - struct commit_list **next = todo_list;
770 - struct commit *commit;
771 - char *p = buf;
772 - int i;
773 -
774 - for (i = 1; *p; i++) {
775 - char *eol = strchrnul(p, '\n');
776 - commit = parse_insn_line(p, eol, opts);
777 - if (!commit)
778 - return error(_("Could not parse line %d."), i);
779 - next = commit_list_append(commit, next);
780 - p = *eol ? eol + 1 : eol;
781 - }
782 - if (!*todo_list)
783 - return error(_("No commits parsed."));
784 - return 0;
785 -}
786 -
787 -static void read_populate_todo(struct commit_list **todo_list,
788 - struct replay_opts *opts)
789 -{
790 - const char *todo_file = git_path(SEQ_TODO_FILE);
791 - struct strbuf buf = STRBUF_INIT;
792 - int fd, res;
793 -
794 - fd = open(todo_file, O_RDONLY);
795 - if (fd < 0)
796 - die_errno(_("Could not open %s"), todo_file);
797 - if (strbuf_read(&buf, fd, 0) < 0) {
798 - close(fd);
799 - strbuf_release(&buf);
800 - die(_("Could not read %s."), todo_file);
801 - }
802 - close(fd);
803 -
804 - res = parse_insn_buffer(buf.buf, todo_list, opts);
805 - strbuf_release(&buf);
806 - if (res)
807 - die(_("Unusable instruction sheet: %s"), todo_file);
808 -}
809 -
810 -static int populate_opts_cb(const char *key, const char *value, void *data)
811 -{
812 - struct replay_opts *opts = data;
813 - int error_flag = 1;
814 -
815 - if (!value)
816 - error_flag = 0;
817 - else if (!strcmp(key, "options.no-commit"))
818 - opts->no_commit = git_config_bool_or_int(key, value, &error_flag);
819 - else if (!strcmp(key, "options.edit"))
820 - opts->edit = git_config_bool_or_int(key, value, &error_flag);
821 - else if (!strcmp(key, "options.signoff"))
822 - opts->signoff = git_config_bool_or_int(key, value, &error_flag);
823 - else if (!strcmp(key, "options.record-origin"))
824 - opts->record_origin = git_config_bool_or_int(key, value, &error_flag);
825 - else if (!strcmp(key, "options.allow-ff"))
826 - opts->allow_ff = git_config_bool_or_int(key, value, &error_flag);
827 - else if (!strcmp(key, "options.mainline"))
828 - opts->mainline = git_config_int(key, value);
829 - else if (!strcmp(key, "options.strategy"))
830 - git_config_string(&opts->strategy, key, value);
831 - else if (!strcmp(key, "options.strategy-option")) {
832 - ALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);
833 - opts->xopts[opts->xopts_nr++] = xstrdup(value);
834 - } else
835 - return error(_("Invalid key: %s"), key);
836 -
837 - if (!error_flag)
838 - return error(_("Invalid value for %s: %s"), key, value);
839 -
840 - return 0;
841 -}
842 -
843 -static void read_populate_opts(struct replay_opts **opts_ptr)
844 -{
845 - const char *opts_file = git_path(SEQ_OPTS_FILE);
846 -
847 - if (!file_exists(opts_file))
848 - return;
849 - if (git_config_from_file(populate_opts_cb, opts_file, *opts_ptr) < 0)
850 - die(_("Malformed options sheet: %s"), opts_file);
851 -}
852 -
853 -static void walk_revs_populate_todo(struct commit_list **todo_list,
854 - struct replay_opts *opts)
855 -{
856 - struct commit *commit;
857 - struct commit_list **next;
858 -
859 - prepare_revs(opts);
860 -
861 - next = todo_list;
862 - while ((commit = get_revision(opts->revs)))
863 - next = commit_list_append(commit, next);
864 -}
865 -
866 -static int create_seq_dir(void)
867 -{
868 - const char *seq_dir = git_path(SEQ_DIR);
869 -
870 - if (file_exists(seq_dir)) {
871 - error(_("a cherry-pick or revert is already in progress"));
872 - advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
873 - return -1;
874 - }
875 - else if (mkdir(seq_dir, 0777) < 0)
876 - die_errno(_("Could not create sequencer directory %s"), seq_dir);
877 - return 0;
878 -}
879 -
880 -static void save_head(const char *head)
881 -{
882 - const char *head_file = git_path(SEQ_HEAD_FILE);
883 - static struct lock_file head_lock;
884 - struct strbuf buf = STRBUF_INIT;
885 - int fd;
886 -
887 - fd = hold_lock_file_for_update(&head_lock, head_file, LOCK_DIE_ON_ERROR);
888 - strbuf_addf(&buf, "%s\n", head);
889 - if (write_in_full(fd, buf.buf, buf.len) < 0)
890 - die_errno(_("Could not write to %s"), head_file);
891 - if (commit_lock_file(&head_lock) < 0)
892 - die(_("Error wrapping up %s."), head_file);
893 -}
894 -
895 -static int reset_for_rollback(const unsigned char *sha1)
896 -{
897 - const char *argv[4]; /* reset --merge <arg> + NULL */
898 - argv[0] = "reset";
899 - argv[1] = "--merge";
900 - argv[2] = sha1_to_hex(sha1);
901 - argv[3] = NULL;
902 - return run_command_v_opt(argv, RUN_GIT_CMD);
903 -}
904 -
905 -static int rollback_single_pick(void)
906 -{
907 - unsigned char head_sha1[20];
908 -
909 - if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
910 - !file_exists(git_path("REVERT_HEAD")))
911 - return error(_("no cherry-pick or revert in progress"));
912 - if (read_ref_full("HEAD", head_sha1, 0, NULL))
913 - return error(_("cannot resolve HEAD"));
914 - if (is_null_sha1(head_sha1))
915 - return error(_("cannot abort from a branch yet to be born"));
916 - return reset_for_rollback(head_sha1);
917 -}
918 -
919 -static int sequencer_rollback(struct replay_opts *opts)
920 -{
921 - const char *filename;
922 - FILE *f;
923 - unsigned char sha1[20];
924 - struct strbuf buf = STRBUF_INIT;
925 -
926 - filename = git_path(SEQ_HEAD_FILE);
927 - f = fopen(filename, "r");
928 - if (!f && errno == ENOENT) {
929 - /*
930 - * There is no multiple-cherry-pick in progress.
931 - * If CHERRY_PICK_HEAD or REVERT_HEAD indicates
932 - * a single-cherry-pick in progress, abort that.
933 - */
934 - return rollback_single_pick();
935 - }
936 - if (!f)
937 - return error(_("cannot open %s: %s"), filename,
938 - strerror(errno));
939 - if (strbuf_getline(&buf, f, '\n')) {
940 - error(_("cannot read %s: %s"), filename, ferror(f) ?
941 - strerror(errno) : _("unexpected end of file"));
942 - fclose(f);
943 - goto fail;
944 - }
945 - fclose(f);
946 - if (get_sha1_hex(buf.buf, sha1) || buf.buf[40] != '\0') {
947 - error(_("stored pre-cherry-pick HEAD file '%s' is corrupt"),
948 - filename);
949 - goto fail;
950 - }
951 - if (reset_for_rollback(sha1))
952 - goto fail;
953 - remove_sequencer_state();
954 - strbuf_release(&buf);
955 - return 0;
956 -fail:
957 - strbuf_release(&buf);
958 - return -1;
959 -}
960 -
961 -static void save_todo(struct commit_list *todo_list, struct replay_opts *opts)
962 -{
963 - const char *todo_file = git_path(SEQ_TODO_FILE);
964 - static struct lock_file todo_lock;
965 - struct strbuf buf = STRBUF_INIT;
966 - int fd;
967 -
968 - fd = hold_lock_file_for_update(&todo_lock, todo_file, LOCK_DIE_ON_ERROR);
969 - if (format_todo(&buf, todo_list, opts) < 0)
970 - die(_("Could not format %s."), todo_file);
971 - if (write_in_full(fd, buf.buf, buf.len) < 0) {
972 - strbuf_release(&buf);
973 - die_errno(_("Could not write to %s"), todo_file);
974 - }
975 - if (commit_lock_file(&todo_lock) < 0) {
976 - strbuf_release(&buf);
977 - die(_("Error wrapping up %s."), todo_file);
978 - }
979 - strbuf_release(&buf);
980 -}
981 -
982 -static void save_opts(struct replay_opts *opts)
983 -{
984 - const char *opts_file = git_path(SEQ_OPTS_FILE);
985 -
986 - if (opts->no_commit)
987 - git_config_set_in_file(opts_file, "options.no-commit", "true");
988 - if (opts->edit)
989 - git_config_set_in_file(opts_file, "options.edit", "true");
990 - if (opts->signoff)
991 - git_config_set_in_file(opts_file, "options.signoff", "true");
992 - if (opts->record_origin)
993 - git_config_set_in_file(opts_file, "options.record-origin", "true");
994 - if (opts->allow_ff)
995 - git_config_set_in_file(opts_file, "options.allow-ff", "true");
996 - if (opts->mainline) {
997 - struct strbuf buf = STRBUF_INIT;
998 - strbuf_addf(&buf, "%d", opts->mainline);
999 - git_config_set_in_file(opts_file, "options.mainline", buf.buf);
1000 - strbuf_release(&buf);
1001 - }
1002 - if (opts->strategy)
1003 - git_config_set_in_file(opts_file, "options.strategy", opts->strategy);
1004 - if (opts->xopts) {
1005 - int i;
1006 - for (i = 0; i < opts->xopts_nr; i++)
1007 - git_config_set_multivar_in_file(opts_file,
1008 - "options.strategy-option",
1009 - opts->xopts[i], "^$", 0);
1010 - }
1011 -}
1012 -
1013 -static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)
1014 -{
1015 - struct commit_list *cur;
1016 - int res;
1017 -
1018 - setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
1019 - if (opts->allow_ff)
1020 - assert(!(opts->signoff || opts->no_commit ||
1021 - opts->record_origin || opts->edit));
1022 - read_and_refresh_cache(opts);
1023 -
1024 - for (cur = todo_list; cur; cur = cur->next) {
1025 - save_todo(cur, opts);
1026 - res = do_pick_commit(cur->item, opts);
1027 - if (res)
1028 - return res;
1029 - }
1030 -
1031 - /*
1032 - * Sequence of picks finished successfully; cleanup by
1033 - * removing the .git/sequencer directory
1034 - */
1035 - remove_sequencer_state();
1036 - return 0;
1037 -}
1038 -
1039 -static int continue_single_pick(void)
1040 -{
1041 - const char *argv[] = { "commit", NULL };
1042 -
1043 - if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
1044 - !file_exists(git_path("REVERT_HEAD")))
1045 - return error(_("no cherry-pick or revert in progress"));
1046 - return run_command_v_opt(argv, RUN_GIT_CMD);
1047 -}
1048 -
1049 -static int sequencer_continue(struct replay_opts *opts)
1050 -{
1051 - struct commit_list *todo_list = NULL;
1052 -
1053 - if (!file_exists(git_path(SEQ_TODO_FILE)))
1054 - return continue_single_pick();
1055 - read_populate_opts(&opts);
1056 - read_populate_todo(&todo_list, opts);
1057 -
1058 - /* Verify that the conflict has been resolved */
1059 - if (file_exists(git_path("CHERRY_PICK_HEAD")) ||
1060 - file_exists(git_path("REVERT_HEAD"))) {
1061 - int ret = continue_single_pick();
1062 - if (ret)
1063 - return ret;
1064 - }
1065 - if (index_differs_from("HEAD", 0))
1066 - return error_dirty_index(opts);
1067 - todo_list = todo_list->next;
1068 - return pick_commits(todo_list, opts);
1069 -}
1070 -
1071 -static int single_pick(struct commit *cmit, struct replay_opts *opts)
1072 -{
1073 - setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
1074 - return do_pick_commit(cmit, opts);
1075 -}
1076 -
1077 -static int pick_revisions(struct replay_opts *opts)
1078 -{
1079 - struct commit_list *todo_list = NULL;
1080 - unsigned char sha1[20];
1081 -
1082 - if (opts->subcommand == REPLAY_NONE)
1083 - assert(opts->revs);
1084 -
1085 - read_and_refresh_cache(opts);
1086 -
1087 - /*
1088 - * Decide what to do depending on the arguments; a fresh
1089 - * cherry-pick should be handled differently from an existing
1090 - * one that is being continued
1091 - */
1092 - if (opts->subcommand == REPLAY_REMOVE_STATE) {
1093 - remove_sequencer_state();
1094 - return 0;
1095 - }
1096 - if (opts->subcommand == REPLAY_ROLLBACK)
1097 - return sequencer_rollback(opts);
1098 - if (opts->subcommand == REPLAY_CONTINUE)
1099 - return sequencer_continue(opts);
1100 -
1101 - /*
1102 - * If we were called as "git cherry-pick <commit>", just
1103 - * cherry-pick/revert it, set CHERRY_PICK_HEAD /
1104 - * REVERT_HEAD, and don't touch the sequencer state.
1105 - * This means it is possible to cherry-pick in the middle
1106 - * of a cherry-pick sequence.
1107 - */
1108 - if (opts->revs->cmdline.nr == 1 &&
1109 - opts->revs->cmdline.rev->whence == REV_CMD_REV &&
1110 - opts->revs->no_walk &&
1111 - !opts->revs->cmdline.rev->flags) {
1112 - struct commit *cmit;
1113 - if (prepare_revision_walk(opts->revs))
1114 - die(_("revision walk setup failed"));
1115 - cmit = get_revision(opts->revs);
1116 - if (!cmit || get_revision(opts->revs))
1117 - die("BUG: expected exactly one commit from walk");
1118 - return single_pick(cmit, opts);
1119 - }
1120 -
1121 - /*
1122 - * Start a new cherry-pick/ revert sequence; but
1123 - * first, make sure that an existing one isn't in
1124 - * progress
1125 - */
1126 -
1127 - walk_revs_populate_todo(&todo_list, opts);
1128 - if (create_seq_dir() < 0)
1129 - return -1;
1130 - if (get_sha1("HEAD", sha1)) {
1131 - if (opts->action == REPLAY_REVERT)
1132 - return error(_("Can't revert as initial commit"));
1133 - return error(_("Can't cherry-pick into empty head"));
1134 - }
1135 - save_head(sha1_to_hex(sha1));
1136 - save_opts(opts);
1137 - return pick_commits(todo_list, opts);
1138 -}
1139 -
196 int cmd_revert(int argc, const char **argv, const char *prefix)
197 {
198 struct replay_opts opts;
@@ -1148,7 +204,7 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
204 opts.action = REPLAY_REVERT;
205 git_config(git_default_config, NULL);
206 parse_args(argc, argv, &opts);
1151 - res = pick_revisions(&opts);
207 + res = sequencer_pick_revisions(&opts);
208 if (res < 0)
209 die(_("revert failed"));
210 return res;
@@ -1163,7 +219,7 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
219 opts.action = REPLAY_PICK;
220 git_config(git_default_config, NULL);
221 parse_args(argc, argv, &opts);
1166 - res = pick_revisions(&opts);
222 + res = sequencer_pick_revisions(&opts);
223 if (res < 0)
224 die(_("cherry-pick failed"));
225 return res;
sequencer.c
+917 -1
@@ -1,7 +1,20 @@
1 #include "cache.h"
2 #include "sequencer.h"
3 -#include "strbuf.h"
3 #include "dir.h"
4 +#include "object.h"
5 +#include "commit.h"
6 +#include "tag.h"
7 +#include "run-command.h"
8 +#include "exec_cmd.h"
9 +#include "utf8.h"
10 +#include "cache-tree.h"
11 +#include "diff.h"
12 +#include "revision.h"
13 +#include "rerere.h"
14 +#include "merge-recursive.h"
15 +#include "refs.h"
16 +
17 +#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
18
19 void remove_sequencer_state(void)
20 {
@@ -11,3 +24,906 @@ void remove_sequencer_state(void)
24 remove_dir_recursively(&seq_dir, 0);
25 strbuf_release(&seq_dir);
26 }
27 +
28 +static const char *action_name(const struct replay_opts *opts)
29 +{
30 + return opts->action == REPLAY_REVERT ? "revert" : "cherry-pick";
31 +}
32 +
33 +static char *get_encoding(const char *message);
34 +
35 +struct commit_message {
36 + char *parent_label;
37 + const char *label;
38 + const char *subject;
39 + char *reencoded_message;
40 + const char *message;
41 +};
42 +
43 +static int get_message(struct commit *commit, struct commit_message *out)
44 +{
45 + const char *encoding;
46 + const char *abbrev, *subject;
47 + int abbrev_len, subject_len;
48 + char *q;
49 +
50 + if (!commit->buffer)
51 + return -1;
52 + encoding = get_encoding(commit->buffer);
53 + if (!encoding)
54 + encoding = "UTF-8";
55 + if (!git_commit_encoding)
56 + git_commit_encoding = "UTF-8";
57 +
58 + out->reencoded_message = NULL;
59 + out->message = commit->buffer;
60 + if (strcmp(encoding, git_commit_encoding))
61 + out->reencoded_message = reencode_string(commit->buffer,
62 + git_commit_encoding, encoding);
63 + if (out->reencoded_message)
64 + out->message = out->reencoded_message;
65 +
66 + abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
67 + abbrev_len = strlen(abbrev);
68 +
69 + subject_len = find_commit_subject(out->message, &subject);
70 +
71 + out->parent_label = xmalloc(strlen("parent of ") + abbrev_len +
72 + strlen("... ") + subject_len + 1);
73 + q = out->parent_label;
74 + q = mempcpy(q, "parent of ", strlen("parent of "));
75 + out->label = q;
76 + q = mempcpy(q, abbrev, abbrev_len);
77 + q = mempcpy(q, "... ", strlen("... "));
78 + out->subject = q;
79 + q = mempcpy(q, subject, subject_len);
80 + *q = '\0';
81 + return 0;
82 +}
83 +
84 +static void free_message(struct commit_message *msg)
85 +{
86 + free(msg->parent_label);
87 + free(msg->reencoded_message);
88 +}
89 +
90 +static char *get_encoding(const char *message)
91 +{
92 + const char *p = message, *eol;
93 +
94 + while (*p && *p != '\n') {
95 + for (eol = p + 1; *eol && *eol != '\n'; eol++)
96 + ; /* do nothing */
97 + if (!prefixcmp(p, "encoding ")) {
98 + char *result = xmalloc(eol - 8 - p);
99 + strlcpy(result, p + 9, eol - 8 - p);
100 + return result;
101 + }
102 + p = eol;
103 + if (*p == '\n')
104 + p++;
105 + }
106 + return NULL;
107 +}
108 +
109 +static void write_cherry_pick_head(struct commit *commit, const char *pseudoref)
110 +{
111 + const char *filename;
112 + int fd;
113 + struct strbuf buf = STRBUF_INIT;
114 +
115 + strbuf_addf(&buf, "%s\n", sha1_to_hex(commit->object.sha1));
116 +
117 + filename = git_path("%s", pseudoref);
118 + fd = open(filename, O_WRONLY | O_CREAT, 0666);
119 + if (fd < 0)
120 + die_errno(_("Could not open '%s' for writing"), filename);
121 + if (write_in_full(fd, buf.buf, buf.len) != buf.len || close(fd))
122 + die_errno(_("Could not write to '%s'"), filename);
123 + strbuf_release(&buf);
124 +}
125 +
126 +static void print_advice(int show_hint)
127 +{
128 + char *msg = getenv("GIT_CHERRY_PICK_HELP");
129 +
130 + if (msg) {
131 + fprintf(stderr, "%s\n", msg);
132 + /*
133 + * A conflict has occured but the porcelain
134 + * (typically rebase --interactive) wants to take care
135 + * of the commit itself so remove CHERRY_PICK_HEAD
136 + */
137 + unlink(git_path("CHERRY_PICK_HEAD"));
138 + return;
139 + }
140 +
141 + if (show_hint) {
142 + advise("after resolving the conflicts, mark the corrected paths");
143 + advise("with 'git add <paths>' or 'git rm <paths>'");
144 + advise("and commit the result with 'git commit'");
145 + }
146 +}
147 +
148 +static void write_message(struct strbuf *msgbuf, const char *filename)
149 +{
150 + static struct lock_file msg_file;
151 +
152 + int msg_fd = hold_lock_file_for_update(&msg_file, filename,
153 + LOCK_DIE_ON_ERROR);
154 + if (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)
155 + die_errno(_("Could not write to %s"), filename);
156 + strbuf_release(msgbuf);
157 + if (commit_lock_file(&msg_file) < 0)
158 + die(_("Error wrapping up %s"), filename);
159 +}
160 +
161 +static struct tree *empty_tree(void)
162 +{
163 + return lookup_tree((const unsigned char *)EMPTY_TREE_SHA1_BIN);
164 +}
165 +
166 +static int error_dirty_index(struct replay_opts *opts)
167 +{
168 + if (read_cache_unmerged())
169 + return error_resolve_conflict(action_name(opts));
170 +
171 + /* Different translation strings for cherry-pick and revert */
172 + if (opts->action == REPLAY_PICK)
173 + error(_("Your local changes would be overwritten by cherry-pick."));
174 + else
175 + error(_("Your local changes would be overwritten by revert."));
176 +
177 + if (advice_commit_before_merge)
178 + advise(_("Commit your changes or stash them to proceed."));
179 + return -1;
180 +}
181 +
182 +static int fast_forward_to(const unsigned char *to, const unsigned char *from)
183 +{
184 + struct ref_lock *ref_lock;
185 +
186 + read_cache();
187 + if (checkout_fast_forward(from, to))
188 + exit(1); /* the callee should have complained already */
189 + ref_lock = lock_any_ref_for_update("HEAD", from, 0);
190 + return write_ref_sha1(ref_lock, to, "cherry-pick");
191 +}
192 +
193 +static int do_recursive_merge(struct commit *base, struct commit *next,
194 + const char *base_label, const char *next_label,
195 + unsigned char *head, struct strbuf *msgbuf,
196 + struct replay_opts *opts)
197 +{
198 + struct merge_options o;
199 + struct tree *result, *next_tree, *base_tree, *head_tree;
200 + int clean, index_fd;
201 + const char **xopt;
202 + static struct lock_file index_lock;
203 +
204 + index_fd = hold_locked_index(&index_lock, 1);
205 +
206 + read_cache();
207 +
208 + init_merge_options(&o);
209 + o.ancestor = base ? base_label : "(empty tree)";
210 + o.branch1 = "HEAD";
211 + o.branch2 = next ? next_label : "(empty tree)";
212 +
213 + head_tree = parse_tree_indirect(head);
214 + next_tree = next ? next->tree : empty_tree();
215 + base_tree = base ? base->tree : empty_tree();
216 +
217 + for (xopt = opts->xopts; xopt != opts->xopts + opts->xopts_nr; xopt++)
218 + parse_merge_opt(&o, *xopt);
219 +
220 + clean = merge_trees(&o,
221 + head_tree,
222 + next_tree, base_tree, &result);
223 +
224 + if (active_cache_changed &&
225 + (write_cache(index_fd, active_cache, active_nr) ||
226 + commit_locked_index(&index_lock)))
227 + /* TRANSLATORS: %s will be "revert" or "cherry-pick" */
228 + die(_("%s: Unable to write new index file"), action_name(opts));
229 + rollback_lock_file(&index_lock);
230 +
231 + if (!clean) {
232 + int i;
233 + strbuf_addstr(msgbuf, "\nConflicts:\n\n");
234 + for (i = 0; i < active_nr;) {
235 + struct cache_entry *ce = active_cache[i++];
236 + if (ce_stage(ce)) {
237 + strbuf_addch(msgbuf, '\t');
238 + strbuf_addstr(msgbuf, ce->name);
239 + strbuf_addch(msgbuf, '\n');
240 + while (i < active_nr && !strcmp(ce->name,
241 + active_cache[i]->name))
242 + i++;
243 + }
244 + }
245 + }
246 +
247 + return !clean;
248 +}
249 +
250 +/*
251 + * If we are cherry-pick, and if the merge did not result in
252 + * hand-editing, we will hit this commit and inherit the original
253 + * author date and name.
254 + * If we are revert, or if our cherry-pick results in a hand merge,
255 + * we had better say that the current user is responsible for that.
256 + */
257 +static int run_git_commit(const char *defmsg, struct replay_opts *opts)
258 +{
259 + /* 6 is max possible length of our args array including NULL */
260 + const char *args[6];
261 + int i = 0;
262 +
263 + args[i++] = "commit";
264 + args[i++] = "-n";
265 + if (opts->signoff)
266 + args[i++] = "-s";
267 + if (!opts->edit) {
268 + args[i++] = "-F";
269 + args[i++] = defmsg;
270 + }
271 + args[i] = NULL;
272 +
273 + return run_command_v_opt(args, RUN_GIT_CMD);
274 +}
275 +
276 +static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
277 +{
278 + unsigned char head[20];
279 + struct commit *base, *next, *parent;
280 + const char *base_label, *next_label;
281 + struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
282 + char *defmsg = NULL;
283 + struct strbuf msgbuf = STRBUF_INIT;
284 + int res;
285 +
286 + if (opts->no_commit) {
287 + /*
288 + * We do not intend to commit immediately. We just want to
289 + * merge the differences in, so let's compute the tree
290 + * that represents the "current" state for merge-recursive
291 + * to work on.
292 + */
293 + if (write_cache_as_tree(head, 0, NULL))
294 + die (_("Your index file is unmerged."));
295 + } else {
296 + if (get_sha1("HEAD", head))
297 + return error(_("You do not have a valid HEAD"));
298 + if (index_differs_from("HEAD", 0))
299 + return error_dirty_index(opts);
300 + }
301 + discard_cache();
302 +
303 + if (!commit->parents) {
304 + parent = NULL;
305 + }
306 + else if (commit->parents->next) {
307 + /* Reverting or cherry-picking a merge commit */
308 + int cnt;
309 + struct commit_list *p;
310 +
311 + if (!opts->mainline)
312 + return error(_("Commit %s is a merge but no -m option was given."),
313 + sha1_to_hex(commit->object.sha1));
314 +
315 + for (cnt = 1, p = commit->parents;
316 + cnt != opts->mainline && p;
317 + cnt++)
318 + p = p->next;
319 + if (cnt != opts->mainline || !p)
320 + return error(_("Commit %s does not have parent %d"),
321 + sha1_to_hex(commit->object.sha1), opts->mainline);
322 + parent = p->item;
323 + } else if (0 < opts->mainline)
324 + return error(_("Mainline was specified but commit %s is not a merge."),
325 + sha1_to_hex(commit->object.sha1));
326 + else
327 + parent = commit->parents->item;
328 +
329 + if (opts->allow_ff && parent && !hashcmp(parent->object.sha1, head))
330 + return fast_forward_to(commit->object.sha1, head);
331 +
332 + if (parent && parse_commit(parent) < 0)
333 + /* TRANSLATORS: The first %s will be "revert" or
334 + "cherry-pick", the second %s a SHA1 */
335 + return error(_("%s: cannot parse parent commit %s"),
336 + action_name(opts), sha1_to_hex(parent->object.sha1));
337 +
338 + if (get_message(commit, &msg) != 0)
339 + return error(_("Cannot get commit message for %s"),
340 + sha1_to_hex(commit->object.sha1));
341 +
342 + /*
343 + * "commit" is an existing commit. We would want to apply
344 + * the difference it introduces since its first parent "prev"
345 + * on top of the current HEAD if we are cherry-pick. Or the
346 + * reverse of it if we are revert.
347 + */
348 +
349 + defmsg = git_pathdup("MERGE_MSG");
350 +
351 + if (opts->action == REPLAY_REVERT) {
352 + base = commit;
353 + base_label = msg.label;
354 + next = parent;
355 + next_label = msg.parent_label;
356 + strbuf_addstr(&msgbuf, "Revert \"");
357 + strbuf_addstr(&msgbuf, msg.subject);
358 + strbuf_addstr(&msgbuf, "\"\n\nThis reverts commit ");
359 + strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
360 +
361 + if (commit->parents && commit->parents->next) {
362 + strbuf_addstr(&msgbuf, ", reversing\nchanges made to ");
363 + strbuf_addstr(&msgbuf, sha1_to_hex(parent->object.sha1));
364 + }
365 + strbuf_addstr(&msgbuf, ".\n");
366 + } else {
367 + const char *p;
368 +
369 + base = parent;
370 + base_label = msg.parent_label;
371 + next = commit;
372 + next_label = msg.label;
373 +
374 + /*
375 + * Append the commit log message to msgbuf; it starts
376 + * after the tree, parent, author, committer
377 + * information followed by "\n\n".
378 + */
379 + p = strstr(msg.message, "\n\n");
380 + if (p) {
381 + p += 2;
382 + strbuf_addstr(&msgbuf, p);
383 + }
384 +
385 + if (opts->record_origin) {
386 + strbuf_addstr(&msgbuf, "(cherry picked from commit ");
387 + strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
388 + strbuf_addstr(&msgbuf, ")\n");
389 + }
390 + }
391 +
392 + if (!opts->strategy || !strcmp(opts->strategy, "recursive") || opts->action == REPLAY_REVERT) {
393 + res = do_recursive_merge(base, next, base_label, next_label,
394 + head, &msgbuf, opts);
395 + write_message(&msgbuf, defmsg);
396 + } else {
397 + struct commit_list *common = NULL;
398 + struct commit_list *remotes = NULL;
399 +
400 + write_message(&msgbuf, defmsg);
401 +
402 + commit_list_insert(base, &common);
403 + commit_list_insert(next, &remotes);
404 + res = try_merge_command(opts->strategy, opts->xopts_nr, opts->xopts,
405 + common, sha1_to_hex(head), remotes);
406 + free_commit_list(common);
407 + free_commit_list(remotes);
408 + }
409 +
410 + /*
411 + * If the merge was clean or if it failed due to conflict, we write
412 + * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.
413 + * However, if the merge did not even start, then we don't want to
414 + * write it at all.
415 + */
416 + if (opts->action == REPLAY_PICK && !opts->no_commit && (res == 0 || res == 1))
417 + write_cherry_pick_head(commit, "CHERRY_PICK_HEAD");
418 + if (opts->action == REPLAY_REVERT && ((opts->no_commit && res == 0) || res == 1))
419 + write_cherry_pick_head(commit, "REVERT_HEAD");
420 +
421 + if (res) {
422 + error(opts->action == REPLAY_REVERT
423 + ? _("could not revert %s... %s")
424 + : _("could not apply %s... %s"),
425 + find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV),
426 + msg.subject);
427 + print_advice(res == 1);
428 + rerere(opts->allow_rerere_auto);
429 + } else {
430 + if (!opts->no_commit)
431 + res = run_git_commit(defmsg, opts);
432 + }
433 +
434 + free_message(&msg);
435 + free(defmsg);
436 +
437 + return res;
438 +}
439 +
440 +static void prepare_revs(struct replay_opts *opts)
441 +{
442 + if (opts->action != REPLAY_REVERT)
443 + opts->revs->reverse ^= 1;
444 +
445 + if (prepare_revision_walk(opts->revs))
446 + die(_("revision walk setup failed"));
447 +
448 + if (!opts->revs->commits)
449 + die(_("empty commit set passed"));
450 +}
451 +
452 +static void read_and_refresh_cache(struct replay_opts *opts)
453 +{
454 + static struct lock_file index_lock;
455 + int index_fd = hold_locked_index(&index_lock, 0);
456 + if (read_index_preload(&the_index, NULL) < 0)
457 + die(_("git %s: failed to read the index"), action_name(opts));
458 + refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);
459 + if (the_index.cache_changed) {
460 + if (write_index(&the_index, index_fd) ||
461 + commit_locked_index(&index_lock))
462 + die(_("git %s: failed to refresh the index"), action_name(opts));
463 + }
464 + rollback_lock_file(&index_lock);
465 +}
466 +
467 +/*
468 + * Append a commit to the end of the commit_list.
469 + *
470 + * next starts by pointing to the variable that holds the head of an
471 + * empty commit_list, and is updated to point to the "next" field of
472 + * the last item on the list as new commits are appended.
473 + *
474 + * Usage example:
475 + *
476 + * struct commit_list *list;
477 + * struct commit_list **next = &list;
478 + *
479 + * next = commit_list_append(c1, next);
480 + * next = commit_list_append(c2, next);
481 + * assert(commit_list_count(list) == 2);
482 + * return list;
483 + */
484 +static struct commit_list **commit_list_append(struct commit *commit,
485 + struct commit_list **next)
486 +{
487 + struct commit_list *new = xmalloc(sizeof(struct commit_list));
488 + new->item = commit;
489 + *next = new;
490 + new->next = NULL;
491 + return &new->next;
492 +}
493 +
494 +static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
495 + struct replay_opts *opts)
496 +{
497 + struct commit_list *cur = NULL;
498 + const char *sha1_abbrev = NULL;
499 + const char *action_str = opts->action == REPLAY_REVERT ? "revert" : "pick";
500 + const char *subject;
501 + int subject_len;
502 +
503 + for (cur = todo_list; cur; cur = cur->next) {
504 + sha1_abbrev = find_unique_abbrev(cur->item->object.sha1, DEFAULT_ABBREV);
505 + subject_len = find_commit_subject(cur->item->buffer, &subject);
506 + strbuf_addf(buf, "%s %s %.*s\n", action_str, sha1_abbrev,
507 + subject_len, subject);
508 + }
509 + return 0;
510 +}
511 +
512 +static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)
513 +{
514 + unsigned char commit_sha1[20];
515 + enum replay_action action;
516 + char *end_of_object_name;
517 + int saved, status, padding;
518 +
519 + if (!prefixcmp(bol, "pick")) {
520 + action = REPLAY_PICK;
521 + bol += strlen("pick");
522 + } else if (!prefixcmp(bol, "revert")) {
523 + action = REPLAY_REVERT;
524 + bol += strlen("revert");
525 + } else
526 + return NULL;
527 +
528 + /* Eat up extra spaces/ tabs before object name */
529 + padding = strspn(bol, " \t");
530 + if (!padding)
531 + return NULL;
532 + bol += padding;
533 +
534 + end_of_object_name = bol + strcspn(bol, " \t\n");
535 + saved = *end_of_object_name;
536 + *end_of_object_name = '\0';
537 + status = get_sha1(bol, commit_sha1);
538 + *end_of_object_name = saved;
539 +
540 + /*
541 + * Verify that the action matches up with the one in
542 + * opts; we don't support arbitrary instructions
543 + */
544 + if (action != opts->action) {
545 + const char *action_str;
546 + action_str = action == REPLAY_REVERT ? "revert" : "cherry-pick";
547 + error(_("Cannot %s during a %s"), action_str, action_name(opts));
548 + return NULL;
549 + }
550 +
551 + if (status < 0)
552 + return NULL;
553 +
554 + return lookup_commit_reference(commit_sha1);
555 +}
556 +
557 +static int parse_insn_buffer(char *buf, struct commit_list **todo_list,
558 + struct replay_opts *opts)
559 +{
560 + struct commit_list **next = todo_list;
561 + struct commit *commit;
562 + char *p = buf;
563 + int i;
564 +
565 + for (i = 1; *p; i++) {
566 + char *eol = strchrnul(p, '\n');
567 + commit = parse_insn_line(p, eol, opts);
568 + if (!commit)
569 + return error(_("Could not parse line %d."), i);
570 + next = commit_list_append(commit, next);
571 + p = *eol ? eol + 1 : eol;
572 + }
573 + if (!*todo_list)
574 + return error(_("No commits parsed."));
575 + return 0;
576 +}
577 +
578 +static void read_populate_todo(struct commit_list **todo_list,
579 + struct replay_opts *opts)
580 +{
581 + const char *todo_file = git_path(SEQ_TODO_FILE);
582 + struct strbuf buf = STRBUF_INIT;
583 + int fd, res;
584 +
585 + fd = open(todo_file, O_RDONLY);
586 + if (fd < 0)
587 + die_errno(_("Could not open %s"), todo_file);
588 + if (strbuf_read(&buf, fd, 0) < 0) {
589 + close(fd);
590 + strbuf_release(&buf);
591 + die(_("Could not read %s."), todo_file);
592 + }
593 + close(fd);
594 +
595 + res = parse_insn_buffer(buf.buf, todo_list, opts);
596 + strbuf_release(&buf);
597 + if (res)
598 + die(_("Unusable instruction sheet: %s"), todo_file);
599 +}
600 +
601 +static int populate_opts_cb(const char *key, const char *value, void *data)
602 +{
603 + struct replay_opts *opts = data;
604 + int error_flag = 1;
605 +
606 + if (!value)
607 + error_flag = 0;
608 + else if (!strcmp(key, "options.no-commit"))
609 + opts->no_commit = git_config_bool_or_int(key, value, &error_flag);
610 + else if (!strcmp(key, "options.edit"))
611 + opts->edit = git_config_bool_or_int(key, value, &error_flag);
612 + else if (!strcmp(key, "options.signoff"))
613 + opts->signoff = git_config_bool_or_int(key, value, &error_flag);
614 + else if (!strcmp(key, "options.record-origin"))
615 + opts->record_origin = git_config_bool_or_int(key, value, &error_flag);
616 + else if (!strcmp(key, "options.allow-ff"))
617 + opts->allow_ff = git_config_bool_or_int(key, value, &error_flag);
618 + else if (!strcmp(key, "options.mainline"))
619 + opts->mainline = git_config_int(key, value);
620 + else if (!strcmp(key, "options.strategy"))
621 + git_config_string(&opts->strategy, key, value);
622 + else if (!strcmp(key, "options.strategy-option")) {
623 + ALLOC_GROW(opts->xopts, opts->xopts_nr + 1, opts->xopts_alloc);
624 + opts->xopts[opts->xopts_nr++] = xstrdup(value);
625 + } else
626 + return error(_("Invalid key: %s"), key);
627 +
628 + if (!error_flag)
629 + return error(_("Invalid value for %s: %s"), key, value);
630 +
631 + return 0;
632 +}
633 +
634 +static void read_populate_opts(struct replay_opts **opts_ptr)
635 +{
636 + const char *opts_file = git_path(SEQ_OPTS_FILE);
637 +
638 + if (!file_exists(opts_file))
639 + return;
640 + if (git_config_from_file(populate_opts_cb, opts_file, *opts_ptr) < 0)
641 + die(_("Malformed options sheet: %s"), opts_file);
642 +}
643 +
644 +static void walk_revs_populate_todo(struct commit_list **todo_list,
645 + struct replay_opts *opts)
646 +{
647 + struct commit *commit;
648 + struct commit_list **next;
649 +
650 + prepare_revs(opts);
651 +
652 + next = todo_list;
653 + while ((commit = get_revision(opts->revs)))
654 + next = commit_list_append(commit, next);
655 +}
656 +
657 +static int create_seq_dir(void)
658 +{
659 + const char *seq_dir = git_path(SEQ_DIR);
660 +
661 + if (file_exists(seq_dir)) {
662 + error(_("a cherry-pick or revert is already in progress"));
663 + advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
664 + return -1;
665 + }
666 + else if (mkdir(seq_dir, 0777) < 0)
667 + die_errno(_("Could not create sequencer directory %s"), seq_dir);
668 + return 0;
669 +}
670 +
671 +static void save_head(const char *head)
672 +{
673 + const char *head_file = git_path(SEQ_HEAD_FILE);
674 + static struct lock_file head_lock;
675 + struct strbuf buf = STRBUF_INIT;
676 + int fd;
677 +
678 + fd = hold_lock_file_for_update(&head_lock, head_file, LOCK_DIE_ON_ERROR);
679 + strbuf_addf(&buf, "%s\n", head);
680 + if (write_in_full(fd, buf.buf, buf.len) < 0)
681 + die_errno(_("Could not write to %s"), head_file);
682 + if (commit_lock_file(&head_lock) < 0)
683 + die(_("Error wrapping up %s."), head_file);
684 +}
685 +
686 +static int reset_for_rollback(const unsigned char *sha1)
687 +{
688 + const char *argv[4]; /* reset --merge <arg> + NULL */
689 + argv[0] = "reset";
690 + argv[1] = "--merge";
691 + argv[2] = sha1_to_hex(sha1);
692 + argv[3] = NULL;
693 + return run_command_v_opt(argv, RUN_GIT_CMD);
694 +}
695 +
696 +static int rollback_single_pick(void)
697 +{
698 + unsigned char head_sha1[20];
699 +
700 + if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
701 + !file_exists(git_path("REVERT_HEAD")))
702 + return error(_("no cherry-pick or revert in progress"));
703 + if (read_ref_full("HEAD", head_sha1, 0, NULL))
704 + return error(_("cannot resolve HEAD"));
705 + if (is_null_sha1(head_sha1))
706 + return error(_("cannot abort from a branch yet to be born"));
707 + return reset_for_rollback(head_sha1);
708 +}
709 +
710 +static int sequencer_rollback(struct replay_opts *opts)
711 +{
712 + const char *filename;
713 + FILE *f;
714 + unsigned char sha1[20];
715 + struct strbuf buf = STRBUF_INIT;
716 +
717 + filename = git_path(SEQ_HEAD_FILE);
718 + f = fopen(filename, "r");
719 + if (!f && errno == ENOENT) {
720 + /*
721 + * There is no multiple-cherry-pick in progress.
722 + * If CHERRY_PICK_HEAD or REVERT_HEAD indicates
723 + * a single-cherry-pick in progress, abort that.
724 + */
725 + return rollback_single_pick();
726 + }
727 + if (!f)
728 + return error(_("cannot open %s: %s"), filename,
729 + strerror(errno));
730 + if (strbuf_getline(&buf, f, '\n')) {
731 + error(_("cannot read %s: %s"), filename, ferror(f) ?
732 + strerror(errno) : _("unexpected end of file"));
733 + fclose(f);
734 + goto fail;
735 + }
736 + fclose(f);
737 + if (get_sha1_hex(buf.buf, sha1) || buf.buf[40] != '\0') {
738 + error(_("stored pre-cherry-pick HEAD file '%s' is corrupt"),
739 + filename);
740 + goto fail;
741 + }
742 + if (reset_for_rollback(sha1))
743 + goto fail;
744 + remove_sequencer_state();
745 + strbuf_release(&buf);
746 + return 0;
747 +fail:
748 + strbuf_release(&buf);
749 + return -1;
750 +}
751 +
752 +static void save_todo(struct commit_list *todo_list, struct replay_opts *opts)
753 +{
754 + const char *todo_file = git_path(SEQ_TODO_FILE);
755 + static struct lock_file todo_lock;
756 + struct strbuf buf = STRBUF_INIT;
757 + int fd;
758 +
759 + fd = hold_lock_file_for_update(&todo_lock, todo_file, LOCK_DIE_ON_ERROR);
760 + if (format_todo(&buf, todo_list, opts) < 0)
761 + die(_("Could not format %s."), todo_file);
762 + if (write_in_full(fd, buf.buf, buf.len) < 0) {
763 + strbuf_release(&buf);
764 + die_errno(_("Could not write to %s"), todo_file);
765 + }
766 + if (commit_lock_file(&todo_lock) < 0) {
767 + strbuf_release(&buf);
768 + die(_("Error wrapping up %s."), todo_file);
769 + }
770 + strbuf_release(&buf);
771 +}
772 +
773 +static void save_opts(struct replay_opts *opts)
774 +{
775 + const char *opts_file = git_path(SEQ_OPTS_FILE);
776 +
777 + if (opts->no_commit)
778 + git_config_set_in_file(opts_file, "options.no-commit", "true");
779 + if (opts->edit)
780 + git_config_set_in_file(opts_file, "options.edit", "true");
781 + if (opts->signoff)
782 + git_config_set_in_file(opts_file, "options.signoff", "true");
783 + if (opts->record_origin)
784 + git_config_set_in_file(opts_file, "options.record-origin", "true");
785 + if (opts->allow_ff)
786 + git_config_set_in_file(opts_file, "options.allow-ff", "true");
787 + if (opts->mainline) {
788 + struct strbuf buf = STRBUF_INIT;
789 + strbuf_addf(&buf, "%d", opts->mainline);
790 + git_config_set_in_file(opts_file, "options.mainline", buf.buf);
791 + strbuf_release(&buf);
792 + }
793 + if (opts->strategy)
794 + git_config_set_in_file(opts_file, "options.strategy", opts->strategy);
795 + if (opts->xopts) {
796 + int i;
797 + for (i = 0; i < opts->xopts_nr; i++)
798 + git_config_set_multivar_in_file(opts_file,
799 + "options.strategy-option",
800 + opts->xopts[i], "^$", 0);
801 + }
802 +}
803 +
804 +static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)
805 +{
806 + struct commit_list *cur;
807 + int res;
808 +
809 + setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
810 + if (opts->allow_ff)
811 + assert(!(opts->signoff || opts->no_commit ||
812 + opts->record_origin || opts->edit));
813 + read_and_refresh_cache(opts);
814 +
815 + for (cur = todo_list; cur; cur = cur->next) {
816 + save_todo(cur, opts);
817 + res = do_pick_commit(cur->item, opts);
818 + if (res)
819 + return res;
820 + }
821 +
822 + /*
823 + * Sequence of picks finished successfully; cleanup by
824 + * removing the .git/sequencer directory
825 + */
826 + remove_sequencer_state();
827 + return 0;
828 +}
829 +
830 +static int continue_single_pick(void)
831 +{
832 + const char *argv[] = { "commit", NULL };
833 +
834 + if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
835 + !file_exists(git_path("REVERT_HEAD")))
836 + return error(_("no cherry-pick or revert in progress"));
837 + return run_command_v_opt(argv, RUN_GIT_CMD);
838 +}
839 +
840 +static int sequencer_continue(struct replay_opts *opts)
841 +{
842 + struct commit_list *todo_list = NULL;
843 +
844 + if (!file_exists(git_path(SEQ_TODO_FILE)))
845 + return continue_single_pick();
846 + read_populate_opts(&opts);
847 + read_populate_todo(&todo_list, opts);
848 +
849 + /* Verify that the conflict has been resolved */
850 + if (file_exists(git_path("CHERRY_PICK_HEAD")) ||
851 + file_exists(git_path("REVERT_HEAD"))) {
852 + int ret = continue_single_pick();
853 + if (ret)
854 + return ret;
855 + }
856 + if (index_differs_from("HEAD", 0))
857 + return error_dirty_index(opts);
858 + todo_list = todo_list->next;
859 + return pick_commits(todo_list, opts);
860 +}
861 +
862 +static int single_pick(struct commit *cmit, struct replay_opts *opts)
863 +{
864 + setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
865 + return do_pick_commit(cmit, opts);
866 +}
867 +
868 +int sequencer_pick_revisions(struct replay_opts *opts)
869 +{
870 + struct commit_list *todo_list = NULL;
871 + unsigned char sha1[20];
872 +
873 + if (opts->subcommand == REPLAY_NONE)
874 + assert(opts->revs);
875 +
876 + read_and_refresh_cache(opts);
877 +
878 + /*
879 + * Decide what to do depending on the arguments; a fresh
880 + * cherry-pick should be handled differently from an existing
881 + * one that is being continued
882 + */
883 + if (opts->subcommand == REPLAY_REMOVE_STATE) {
884 + remove_sequencer_state();
885 + return 0;
886 + }
887 + if (opts->subcommand == REPLAY_ROLLBACK)
888 + return sequencer_rollback(opts);
889 + if (opts->subcommand == REPLAY_CONTINUE)
890 + return sequencer_continue(opts);
891 +
892 + /*
893 + * If we were called as "git cherry-pick <commit>", just
894 + * cherry-pick/revert it, set CHERRY_PICK_HEAD /
895 + * REVERT_HEAD, and don't touch the sequencer state.
896 + * This means it is possible to cherry-pick in the middle
897 + * of a cherry-pick sequence.
898 + */
899 + if (opts->revs->cmdline.nr == 1 &&
900 + opts->revs->cmdline.rev->whence == REV_CMD_REV &&
901 + opts->revs->no_walk &&
902 + !opts->revs->cmdline.rev->flags) {
903 + struct commit *cmit;
904 + if (prepare_revision_walk(opts->revs))
905 + die(_("revision walk setup failed"));
906 + cmit = get_revision(opts->revs);
907 + if (!cmit || get_revision(opts->revs))
908 + die("BUG: expected exactly one commit from walk");
909 + return single_pick(cmit, opts);
910 + }
911 +
912 + /*
913 + * Start a new cherry-pick/ revert sequence; but
914 + * first, make sure that an existing one isn't in
915 + * progress
916 + */
917 +
918 + walk_revs_populate_todo(&todo_list, opts);
919 + if (create_seq_dir() < 0)
920 + return -1;
921 + if (get_sha1("HEAD", sha1)) {
922 + if (opts->action == REPLAY_REVERT)
923 + return error(_("Can't revert as initial commit"));
924 + return error(_("Can't cherry-pick into empty head"));
925 + }
926 + save_head(sha1_to_hex(sha1));
927 + save_opts(opts);
928 + return pick_commits(todo_list, opts);
929 +}
sequencer.h
+37
@@ -6,7 +6,44 @@
6 #define SEQ_TODO_FILE "sequencer/todo"
7 #define SEQ_OPTS_FILE "sequencer/opts"
8
9 +enum replay_action {
10 + REPLAY_REVERT,
11 + REPLAY_PICK
12 +};
13 +
14 +enum replay_subcommand {
15 + REPLAY_NONE,
16 + REPLAY_REMOVE_STATE,
17 + REPLAY_CONTINUE,
18 + REPLAY_ROLLBACK
19 +};
20 +
21 +struct replay_opts {
22 + enum replay_action action;
23 + enum replay_subcommand subcommand;
24 +
25 + /* Boolean options */
26 + int edit;
27 + int record_origin;
28 + int no_commit;
29 + int signoff;
30 + int allow_ff;
31 + int allow_rerere_auto;
32 +
33 + int mainline;
34 +
35 + /* Merge strategy */
36 + const char *strategy;
37 + const char **xopts;
38 + size_t xopts_nr, xopts_alloc;
39 +
40 + /* Only used by REPLAY_NONE */
41 + struct rev_info *revs;
42 +};
43 +
44 /* Removes SEQ_DIR. */
45 extern void remove_sequencer_state(void);
46
47 +int sequencer_pick_revisions(struct replay_opts *opts);
48 +
49 #endif