470
return 1;
471
}
472
473
-static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
473
+enum todo_command {
474
+ TODO_PICK = 0,
475
+ TODO_REVERT
476
+};
477
+
478
+static const char *todo_command_strings[] = {
479
+ "pick",
480
+ "revert"
481
+};
482
+
483
+static const char *command_to_string(const enum todo_command command)
484
+{
485
+ if (command < ARRAY_SIZE(todo_command_strings))
486
+ return todo_command_strings[command];
487
+ die("Unknown command: %d", command);
488
+}
489
+
490
+
491
+static int do_pick_commit(enum todo_command command, struct commit *commit,
492
+ struct replay_opts *opts)
493
{
494
unsigned char head[20];
495
struct commit *base, *next, *parent;
548
return fast_forward_to(commit->object.oid.hash, head, unborn, opts);
549
550
if (parent && parse_commit(parent) < 0)
532
- /* TRANSLATORS: The first %s will be "revert" or
533
- "cherry-pick", the second %s a SHA1 */
551
+ /* TRANSLATORS: The first %s will be a "todo" command like
552
+ "revert" or "pick", the second %s a SHA1. */
553
return error(_("%s: cannot parse parent commit %s"),
535
- action_name(opts), oid_to_hex(&parent->object.oid));
554
+ command_to_string(command),
555
+ oid_to_hex(&parent->object.oid));
556
557
if (get_message(commit, &msg) != 0)
558
return error(_("Cannot get commit message for %s"),
565
* reverse of it if we are revert.
566
*/
567
548
- if (opts->action == REPLAY_REVERT) {
568
+ if (command == TODO_REVERT) {
569
base = commit;
570
base_label = msg.label;
571
next = parent;
606
}
607
}
608
589
- if (!opts->strategy || !strcmp(opts->strategy, "recursive") || opts->action == REPLAY_REVERT) {
609
+ if (!opts->strategy || !strcmp(opts->strategy, "recursive") || command == TODO_REVERT) {
610
res = do_recursive_merge(base, next, base_label, next_label,
611
head, &msgbuf, opts);
612
if (res < 0)
633
* However, if the merge did not even start, then we don't want to
634
* write it at all.
635
*/
616
- if (opts->action == REPLAY_PICK && !opts->no_commit && (res == 0 || res == 1) &&
636
+ if (command == TODO_PICK && !opts->no_commit && (res == 0 || res == 1) &&
637
update_ref(NULL, "CHERRY_PICK_HEAD", commit->object.oid.hash, NULL,
638
REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))
639
res = -1;
620
- if (opts->action == REPLAY_REVERT && ((opts->no_commit && res == 0) || res == 1) &&
640
+ if (command == TODO_REVERT && ((opts->no_commit && res == 0) || res == 1) &&
641
update_ref(NULL, "REVERT_HEAD", commit->object.oid.hash, NULL,
642
REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))
643
res = -1;
644
645
if (res) {
626
- error(opts->action == REPLAY_REVERT
646
+ error(command == TODO_REVERT
647
? _("could not revert %s... %s")
648
: _("could not apply %s... %s"),
649
short_commit_name(commit), msg.subject);
704
return 0;
705
}
706
687
-static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
688
- struct replay_opts *opts)
707
+struct todo_item {
708
+ enum todo_command command;
709
+ struct commit *commit;
710
+ size_t offset_in_buf;
711
+};
712
+
713
+struct todo_list {
714
+ struct strbuf buf;
715
+ struct todo_item *items;
716
+ int nr, alloc, current;
717
+};
718
+
719
+#define TODO_LIST_INIT { STRBUF_INIT }
720
+
721
+static void todo_list_release(struct todo_list *todo_list)
722
{
690
- struct commit_list *cur = NULL;
691
- const char *sha1_abbrev = NULL;
692
- const char *action_str = opts->action == REPLAY_REVERT ? "revert" : "pick";
693
- const char *subject;
694
- int subject_len;
723
+ strbuf_release(&todo_list->buf);
724
+ free(todo_list->items);
725
+ todo_list->items = NULL;
726
+ todo_list->nr = todo_list->alloc = 0;
727
+}
728
696
- for (cur = todo_list; cur; cur = cur->next) {
697
- const char *commit_buffer = get_commit_buffer(cur->item, NULL);
698
- sha1_abbrev = find_unique_abbrev(cur->item->object.oid.hash, DEFAULT_ABBREV);
699
- subject_len = find_commit_subject(commit_buffer, &subject);
700
- strbuf_addf(buf, "%s %s %.*s\n", action_str, sha1_abbrev,
701
- subject_len, subject);
702
- unuse_commit_buffer(cur->item, commit_buffer);
703
- }
704
- return 0;
729
+static struct todo_item *append_new_todo(struct todo_list *todo_list)
730
+{
731
+ ALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc);
732
+ return todo_list->items + todo_list->nr++;
733
}
734
707
-static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)
735
+static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
736
{
737
unsigned char commit_sha1[20];
710
- enum replay_action action;
738
char *end_of_object_name;
712
- int saved, status, padding;
713
-
714
- if (starts_with(bol, "pick")) {
715
- action = REPLAY_PICK;
716
- bol += strlen("pick");
717
- } else if (starts_with(bol, "revert")) {
718
- action = REPLAY_REVERT;
719
- bol += strlen("revert");
720
- } else
721
- return NULL;
739
+ int i, saved, status, padding;
740
+
741
+ for (i = 0; i < ARRAY_SIZE(todo_command_strings); i++)
742
+ if (skip_prefix(bol, todo_command_strings[i], &bol)) {
743
+ item->command = i;
744
+ break;
745
+ }
746
+ if (i >= ARRAY_SIZE(todo_command_strings))
747
+ return -1;
748
749
/* Eat up extra spaces/ tabs before object name */
750
padding = strspn(bol, " \t");
751
if (!padding)
726
- return NULL;
752
+ return -1;
753
bol += padding;
754
729
- end_of_object_name = bol + strcspn(bol, " \t\n");
755
+ end_of_object_name = (char *) bol + strcspn(bol, " \t\n");
756
saved = *end_of_object_name;
757
*end_of_object_name = '\0';
758
status = get_sha1(bol, commit_sha1);
759
*end_of_object_name = saved;
760
735
- /*
736
- * Verify that the action matches up with the one in
737
- * opts; we don't support arbitrary instructions
738
- */
739
- if (action != opts->action) {
740
- if (action == REPLAY_REVERT)
741
- error((opts->action == REPLAY_REVERT)
742
- ? _("Cannot revert during another revert.")
743
- : _("Cannot revert during a cherry-pick."));
744
- else
745
- error((opts->action == REPLAY_REVERT)
746
- ? _("Cannot cherry-pick during a revert.")
747
- : _("Cannot cherry-pick during another cherry-pick."));
748
- return NULL;
749
- }
750
-
761
if (status < 0)
752
- return NULL;
762
+ return -1;
763
754
- return lookup_commit_reference(commit_sha1);
764
+ item->commit = lookup_commit_reference(commit_sha1);
765
+ return !item->commit;
766
}
767
757
-static int parse_insn_buffer(char *buf, struct commit_list **todo_list,
758
- struct replay_opts *opts)
768
+static int parse_insn_buffer(char *buf, struct todo_list *todo_list)
769
{
760
- struct commit_list **next = todo_list;
761
- struct commit *commit;
762
- char *p = buf;
763
- int i;
770
+ struct todo_item *item;
771
+ char *p = buf, *next_p;
772
+ int i, res = 0;
773
765
- for (i = 1; *p; i++) {
774
+ for (i = 1; *p; i++, p = next_p) {
775
char *eol = strchrnul(p, '\n');
767
- commit = parse_insn_line(p, eol, opts);
768
- if (!commit)
769
- return error(_("Could not parse line %d."), i);
770
- next = commit_list_append(commit, next);
771
- p = *eol ? eol + 1 : eol;
776
+
777
+ next_p = *eol ? eol + 1 /* skip LF */ : eol;
778
+
779
+ item = append_new_todo(todo_list);
780
+ item->offset_in_buf = p - todo_list->buf.buf;
781
+ if (parse_insn_line(item, p, eol)) {
782
+ res = error(_("Invalid line %d: %.*s"),
783
+ i, (int)(eol - p), p);
784
+ item->command = -1;
785
+ }
786
}
773
- if (!*todo_list)
787
+ if (!todo_list->nr)
788
return error(_("No commits parsed."));
775
- return 0;
789
+ return res;
790
}
791
778
-static int read_populate_todo(struct commit_list **todo_list,
792
+static int read_populate_todo(struct todo_list *todo_list,
793
struct replay_opts *opts)
794
{
795
const char *todo_file = get_todo_path(opts);
782
- struct strbuf buf = STRBUF_INIT;
796
int fd, res;
797
798
+ strbuf_reset(&todo_list->buf);
799
fd = open(todo_file, O_RDONLY);
800
if (fd < 0)
801
return error_errno(_("Could not open %s"), todo_file);
788
- if (strbuf_read(&buf, fd, 0) < 0) {
802
+ if (strbuf_read(&todo_list->buf, fd, 0) < 0) {
803
close(fd);
790
- strbuf_release(&buf);
804
return error(_("Could not read %s."), todo_file);
805
}
806
close(fd);
807
795
- res = parse_insn_buffer(buf.buf, todo_list, opts);
796
- strbuf_release(&buf);
808
+ res = parse_insn_buffer(todo_list->buf.buf, todo_list);
809
+ if (!res) {
810
+ enum todo_command valid =
811
+ opts->action == REPLAY_PICK ? TODO_PICK : TODO_REVERT;
812
+ int i;
813
+
814
+ for (i = 0; i < todo_list->nr; i++)
815
+ if (valid == todo_list->items[i].command)
816
+ continue;
817
+ else if (valid == TODO_PICK)
818
+ return error(_("Cannot cherry-pick during a revert."));
819
+ else
820
+ return error(_("Cannot revert during a cherry-pick."));
821
+ }
822
+
823
if (res)
824
return error(_("Unusable instruction sheet: %s"), todo_file);
825
return 0;
886
return 0;
887
}
888
863
-static int walk_revs_populate_todo(struct commit_list **todo_list,
889
+static int walk_revs_populate_todo(struct todo_list *todo_list,
890
struct replay_opts *opts)
891
{
892
+ enum todo_command command = opts->action == REPLAY_PICK ?
893
+ TODO_PICK : TODO_REVERT;
894
+ const char *command_string = todo_command_strings[command];
895
struct commit *commit;
867
- struct commit_list **next;
896
897
if (prepare_revs(opts))
898
return -1;
899
872
- next = todo_list;
873
- while ((commit = get_revision(opts->revs)))
874
- next = commit_list_append(commit, next);
900
+ while ((commit = get_revision(opts->revs))) {
901
+ struct todo_item *item = append_new_todo(todo_list);
902
+ const char *commit_buffer = get_commit_buffer(commit, NULL);
903
+ const char *subject;
904
+ int subject_len;
905
+
906
+ item->command = command;
907
+ item->commit = commit;
908
+ item->offset_in_buf = todo_list->buf.len;
909
+ subject_len = find_commit_subject(commit_buffer, &subject);
910
+ strbuf_addf(&todo_list->buf, "%s %s %.*s\n", command_string,
911
+ short_commit_name(commit), subject_len, subject);
912
+ unuse_commit_buffer(commit, commit_buffer);
913
+ }
914
return 0;
915
}
916
1018
return -1;
1019
}
1020
982
-static int save_todo(struct commit_list *todo_list, struct replay_opts *opts)
1021
+static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
1022
{
1023
static struct lock_file todo_lock;
985
- struct strbuf buf = STRBUF_INIT;
986
- int fd;
1024
+ const char *todo_path = get_todo_path(opts);
1025
+ int next = todo_list->current, offset, fd;
1026
988
- fd = hold_lock_file_for_update(&todo_lock, git_path_todo_file(), 0);
1027
+ fd = hold_lock_file_for_update(&todo_lock, todo_path, 0);
1028
if (fd < 0)
990
- return error_errno(_("Could not lock '%s'"),
991
- git_path_todo_file());
992
- if (format_todo(&buf, todo_list, opts) < 0) {
993
- strbuf_release(&buf);
994
- return error(_("Could not format %s."), git_path_todo_file());
995
- }
996
- if (write_in_full(fd, buf.buf, buf.len) < 0) {
997
- strbuf_release(&buf);
998
- return error_errno(_("Could not write to %s"),
999
- git_path_todo_file());
1000
- }
1001
- if (commit_lock_file(&todo_lock) < 0) {
1002
- strbuf_release(&buf);
1003
- return error(_("Error wrapping up %s."), git_path_todo_file());
1004
- }
1005
- strbuf_release(&buf);
1029
+ return error_errno(_("Could not lock '%s'"), todo_path);
1030
+ offset = next < todo_list->nr ?
1031
+ todo_list->items[next].offset_in_buf : todo_list->buf.len;
1032
+ if (write_in_full(fd, todo_list->buf.buf + offset,
1033
+ todo_list->buf.len - offset) < 0)
1034
+ return error_errno(_("Could not write to '%s'"), todo_path);
1035
+ if (commit_lock_file(&todo_lock) < 0)
1036
+ return error(_("Error wrapping up %s."), todo_path);
1037
return 0;
1038
}
1039
1072
return res;
1073
}
1074
1044
-static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)
1075
+static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
1076
{
1046
- struct commit_list *cur;
1077
int res;
1078
1079
setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
1083
if (read_and_refresh_cache(opts))
1084
return -1;
1085
1056
- for (cur = todo_list; cur; cur = cur->next) {
1057
- if (save_todo(cur, opts))
1086
+ while (todo_list->current < todo_list->nr) {
1087
+ struct todo_item *item = todo_list->items + todo_list->current;
1088
+ if (save_todo(todo_list, opts))
1089
return -1;
1059
- res = do_pick_commit(cur->item, opts);
1090
+ res = do_pick_commit(item->command, item->commit, opts);
1091
+ todo_list->current++;
1092
if (res)
1093
return res;
1094
}
1113
1114
static int sequencer_continue(struct replay_opts *opts)
1115
{
1084
- struct commit_list *todo_list = NULL;
1116
+ struct todo_list todo_list = TODO_LIST_INIT;
1117
+ int res;
1118
1119
if (!file_exists(get_todo_path(opts)))
1120
return continue_single_pick();
1088
- if (read_populate_opts(opts) ||
1089
- read_populate_todo(&todo_list, opts))
1121
+ if (read_populate_opts(opts))
1122
return -1;
1123
+ if ((res = read_populate_todo(&todo_list, opts)))
1124
+ goto release_todo_list;
1125
1126
/* Verify that the conflict has been resolved */
1127
if (file_exists(git_path_cherry_pick_head()) ||
1128
file_exists(git_path_revert_head())) {
1095
- int ret = continue_single_pick();
1096
- if (ret)
1097
- return ret;
1129
+ res = continue_single_pick();
1130
+ if (res)
1131
+ goto release_todo_list;
1132
}
1099
- if (index_differs_from("HEAD", 0))
1100
- return error_dirty_index(opts);
1101
- todo_list = todo_list->next;
1102
- return pick_commits(todo_list, opts);
1133
+ if (index_differs_from("HEAD", 0)) {
1134
+ res = error_dirty_index(opts);
1135
+ goto release_todo_list;
1136
+ }
1137
+ todo_list.current++;
1138
+ res = pick_commits(&todo_list, opts);
1139
+release_todo_list:
1140
+ todo_list_release(&todo_list);
1141
+ return res;
1142
}
1143
1144
static int single_pick(struct commit *cmit, struct replay_opts *opts)
1145
{
1146
setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
1108
- return do_pick_commit(cmit, opts);
1147
+ return do_pick_commit(opts->action == REPLAY_PICK ?
1148
+ TODO_PICK : TODO_REVERT, cmit, opts);
1149
}
1150
1151
int sequencer_pick_revisions(struct replay_opts *opts)
1152
{
1113
- struct commit_list *todo_list = NULL;
1153
+ struct todo_list todo_list = TODO_LIST_INIT;
1154
unsigned char sha1[20];
1115
- int i;
1155
+ int i, res;
1156
1157
if (opts->subcommand == REPLAY_NONE)
1158
assert(opts->revs);
1227
return -1;
1228
if (save_opts(opts))
1229
return -1;
1190
- return pick_commits(todo_list, opts);
1230
+ res = pick_commits(&todo_list, opts);
1231
+ todo_list_release(&todo_list);
1232
+ return res;
1233
}
1234
1235
void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag)