@@ -40,7 +40,7 @@ static const char * const cherry_pick_usage[] = {
40
40
};
41
41
42
42
enum replay_action { REVERT , CHERRY_PICK };
43
- enum replay_subcommand { REPLAY_NONE , REPLAY_RESET };
43
+ enum replay_subcommand { REPLAY_NONE , REPLAY_RESET , REPLAY_CONTINUE };
44
44
45
45
struct replay_opts {
46
46
enum replay_action action ;
@@ -117,14 +117,37 @@ static void verify_opt_compatible(const char *me, const char *base_opt, ...)
117
117
die (_ ("%s: %s cannot be used with %s" ), me , this_opt , base_opt );
118
118
}
119
119
120
+ static void verify_opt_mutually_compatible (const char * me , ...)
121
+ {
122
+ const char * opt1 , * opt2 ;
123
+ va_list ap ;
124
+
125
+ va_start (ap , me );
126
+ while ((opt1 = va_arg (ap , const char * ))) {
127
+ if (va_arg (ap , int ))
128
+ break ;
129
+ }
130
+ if (opt1 ) {
131
+ while ((opt2 = va_arg (ap , const char * ))) {
132
+ if (va_arg (ap , int ))
133
+ break ;
134
+ }
135
+ }
136
+
137
+ if (opt1 && opt2 )
138
+ die (_ ("%s: %s cannot be used with %s" ), me , opt1 , opt2 );
139
+ }
140
+
120
141
static void parse_args (int argc , const char * * argv , struct replay_opts * opts )
121
142
{
122
143
const char * const * usage_str = revert_or_cherry_pick_usage (opts );
123
144
const char * me = action_name (opts );
124
145
int noop ;
125
146
int reset = 0 ;
147
+ int contin = 0 ;
126
148
struct option options [] = {
127
149
OPT_BOOLEAN (0 , "reset" , & reset , "forget the current operation" ),
150
+ OPT_BOOLEAN (0 , "continue" , & contin , "continue the current operation" ),
128
151
OPT_BOOLEAN ('n' , "no-commit" , & opts -> no_commit , "don't automatically commit" ),
129
152
OPT_BOOLEAN ('e' , "edit" , & opts -> edit , "edit the commit message" ),
130
153
{ OPTION_BOOLEAN , 'r' , NULL , & noop , NULL , "no-op (backward compatibility)" ,
@@ -154,15 +177,29 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
154
177
PARSE_OPT_KEEP_ARGV0 |
155
178
PARSE_OPT_KEEP_UNKNOWN );
156
179
180
+ /* Check for incompatible subcommands */
181
+ verify_opt_mutually_compatible (me ,
182
+ "--reset" , reset ,
183
+ "--continue" , contin ,
184
+ NULL );
185
+
157
186
/* Set the subcommand */
158
187
if (reset )
159
188
opts -> subcommand = REPLAY_RESET ;
189
+ else if (contin )
190
+ opts -> subcommand = REPLAY_CONTINUE ;
160
191
else
161
192
opts -> subcommand = REPLAY_NONE ;
162
193
163
194
/* Check for incompatible command line arguments */
164
- if (opts -> subcommand == REPLAY_RESET ) {
165
- verify_opt_compatible (me , "--reset" ,
195
+ if (opts -> subcommand != REPLAY_NONE ) {
196
+ char * this_operation ;
197
+ if (opts -> subcommand == REPLAY_RESET )
198
+ this_operation = "--reset" ;
199
+ else
200
+ this_operation = "--continue" ;
201
+
202
+ verify_opt_compatible (me , this_operation ,
166
203
"--no-commit" , opts -> no_commit ,
167
204
"--signoff" , opts -> signoff ,
168
205
"--mainline" , opts -> mainline ,
@@ -668,6 +705,137 @@ static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
668
705
return 0 ;
669
706
}
670
707
708
+ static struct commit * parse_insn_line (char * start , struct replay_opts * opts )
709
+ {
710
+ unsigned char commit_sha1 [20 ];
711
+ char sha1_abbrev [40 ];
712
+ enum replay_action action ;
713
+ int insn_len = 0 ;
714
+ char * p , * q ;
715
+
716
+ if (!prefixcmp (start , "pick " )) {
717
+ action = CHERRY_PICK ;
718
+ insn_len = strlen ("pick" );
719
+ p = start + insn_len + 1 ;
720
+ } else if (!prefixcmp (start , "revert " )) {
721
+ action = REVERT ;
722
+ insn_len = strlen ("revert" );
723
+ p = start + insn_len + 1 ;
724
+ } else
725
+ return NULL ;
726
+
727
+ q = strchr (p , ' ' );
728
+ if (!q )
729
+ return NULL ;
730
+ q ++ ;
731
+
732
+ strlcpy (sha1_abbrev , p , q - p );
733
+
734
+ /*
735
+ * Verify that the action matches up with the one in
736
+ * opts; we don't support arbitrary instructions
737
+ */
738
+ if (action != opts -> action ) {
739
+ const char * action_str ;
740
+ action_str = action == REVERT ? "revert" : "cherry-pick" ;
741
+ error (_ ("Cannot %s during a %s" ), action_str , action_name (opts ));
742
+ return NULL ;
743
+ }
744
+
745
+ if (get_sha1 (sha1_abbrev , commit_sha1 ) < 0 )
746
+ return NULL ;
747
+
748
+ return lookup_commit_reference (commit_sha1 );
749
+ }
750
+
751
+ static int parse_insn_buffer (char * buf , struct commit_list * * todo_list ,
752
+ struct replay_opts * opts )
753
+ {
754
+ struct commit_list * * next = todo_list ;
755
+ struct commit * commit ;
756
+ char * p = buf ;
757
+ int i ;
758
+
759
+ for (i = 1 ; * p ; i ++ ) {
760
+ commit = parse_insn_line (p , opts );
761
+ if (!commit )
762
+ return error (_ ("Could not parse line %d." ), i );
763
+ next = commit_list_append (commit , next );
764
+ p = strchrnul (p , '\n' );
765
+ if (* p )
766
+ p ++ ;
767
+ }
768
+ if (!* todo_list )
769
+ return error (_ ("No commits parsed." ));
770
+ return 0 ;
771
+ }
772
+
773
+ static void read_populate_todo (struct commit_list * * todo_list ,
774
+ struct replay_opts * opts )
775
+ {
776
+ const char * todo_file = git_path (SEQ_TODO_FILE );
777
+ struct strbuf buf = STRBUF_INIT ;
778
+ int fd , res ;
779
+
780
+ fd = open (todo_file , O_RDONLY );
781
+ if (fd < 0 )
782
+ die_errno (_ ("Could not open %s." ), todo_file );
783
+ if (strbuf_read (& buf , fd , 0 ) < 0 ) {
784
+ close (fd );
785
+ strbuf_release (& buf );
786
+ die (_ ("Could not read %s." ), todo_file );
787
+ }
788
+ close (fd );
789
+
790
+ res = parse_insn_buffer (buf .buf , todo_list , opts );
791
+ strbuf_release (& buf );
792
+ if (res )
793
+ die (_ ("Unusable instruction sheet: %s" ), todo_file );
794
+ }
795
+
796
+ static int populate_opts_cb (const char * key , const char * value , void * data )
797
+ {
798
+ struct replay_opts * opts = data ;
799
+ int error_flag = 1 ;
800
+
801
+ if (!value )
802
+ error_flag = 0 ;
803
+ else if (!strcmp (key , "options.no-commit" ))
804
+ opts -> no_commit = git_config_bool_or_int (key , value , & error_flag );
805
+ else if (!strcmp (key , "options.edit" ))
806
+ opts -> edit = git_config_bool_or_int (key , value , & error_flag );
807
+ else if (!strcmp (key , "options.signoff" ))
808
+ opts -> signoff = git_config_bool_or_int (key , value , & error_flag );
809
+ else if (!strcmp (key , "options.record-origin" ))
810
+ opts -> record_origin = git_config_bool_or_int (key , value , & error_flag );
811
+ else if (!strcmp (key , "options.allow-ff" ))
812
+ opts -> allow_ff = git_config_bool_or_int (key , value , & error_flag );
813
+ else if (!strcmp (key , "options.mainline" ))
814
+ opts -> mainline = git_config_int (key , value );
815
+ else if (!strcmp (key , "options.strategy" ))
816
+ git_config_string (& opts -> strategy , key , value );
817
+ else if (!strcmp (key , "options.strategy-option" )) {
818
+ ALLOC_GROW (opts -> xopts , opts -> xopts_nr + 1 , opts -> xopts_alloc );
819
+ opts -> xopts [opts -> xopts_nr ++ ] = xstrdup (value );
820
+ } else
821
+ return error (_ ("Invalid key: %s" ), key );
822
+
823
+ if (!error_flag )
824
+ return error (_ ("Invalid value for %s: %s" ), key , value );
825
+
826
+ return 0 ;
827
+ }
828
+
829
+ static void read_populate_opts (struct replay_opts * * opts_ptr )
830
+ {
831
+ const char * opts_file = git_path (SEQ_OPTS_FILE );
832
+
833
+ if (!file_exists (opts_file ))
834
+ return ;
835
+ if (git_config_from_file (populate_opts_cb , opts_file , * opts_ptr ) < 0 )
836
+ die (_ ("Malformed options sheet: %s" ), opts_file );
837
+ }
838
+
671
839
static void walk_revs_populate_todo (struct commit_list * * todo_list ,
672
840
struct replay_opts * opts )
673
841
{
@@ -811,6 +979,15 @@ static int pick_revisions(struct replay_opts *opts)
811
979
if (opts -> subcommand == REPLAY_RESET ) {
812
980
remove_sequencer_state (1 );
813
981
return 0 ;
982
+ } else if (opts -> subcommand == REPLAY_CONTINUE ) {
983
+ if (!file_exists (git_path (SEQ_TODO_FILE )))
984
+ goto error ;
985
+ read_populate_opts (& opts );
986
+ read_populate_todo (& todo_list , opts );
987
+
988
+ /* Verify that the conflict has been resolved */
989
+ if (!index_differs_from ("HEAD" , 0 ))
990
+ todo_list = todo_list -> next ;
814
991
} else {
815
992
/*
816
993
* Start a new cherry-pick/ revert sequence; but
@@ -821,7 +998,8 @@ static int pick_revisions(struct replay_opts *opts)
821
998
walk_revs_populate_todo (& todo_list , opts );
822
999
if (create_seq_dir () < 0 ) {
823
1000
fatal (_ ("A cherry-pick or revert is in progress." ));
824
- advise (_ ("Use --reset to forget about it" ));
1001
+ advise (_ ("Use --continue to continue the operation" ));
1002
+ advise (_ ("or --reset to forget about it" ));
825
1003
exit (128 );
826
1004
}
827
1005
if (get_sha1 ("HEAD" , sha1 )) {
@@ -833,6 +1011,8 @@ static int pick_revisions(struct replay_opts *opts)
833
1011
save_opts (opts );
834
1012
}
835
1013
return pick_commits (todo_list , opts );
1014
+ error :
1015
+ die (_ ("No %s in progress" ), action_name (opts ));
836
1016
}
837
1017
838
1018
int cmd_revert (int argc , const char * * argv , const char * prefix )
0 commit comments