@@ -40,7 +40,7 @@ static const char * const cherry_pick_usage[] = {
4040};
4141
4242enum replay_action { REVERT , CHERRY_PICK };
43- enum replay_subcommand { REPLAY_NONE , REPLAY_RESET };
43+ enum replay_subcommand { REPLAY_NONE , REPLAY_RESET , REPLAY_CONTINUE };
4444
4545struct replay_opts {
4646 enum replay_action action ;
@@ -117,14 +117,37 @@ static void verify_opt_compatible(const char *me, const char *base_opt, ...)
117117 die (_ ("%s: %s cannot be used with %s" ), me , this_opt , base_opt );
118118}
119119
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+
120141static void parse_args (int argc , const char * * argv , struct replay_opts * opts )
121142{
122143 const char * const * usage_str = revert_or_cherry_pick_usage (opts );
123144 const char * me = action_name (opts );
124145 int noop ;
125146 int reset = 0 ;
147+ int contin = 0 ;
126148 struct option options [] = {
127149 OPT_BOOLEAN (0 , "reset" , & reset , "forget the current operation" ),
150+ OPT_BOOLEAN (0 , "continue" , & contin , "continue the current operation" ),
128151 OPT_BOOLEAN ('n' , "no-commit" , & opts -> no_commit , "don't automatically commit" ),
129152 OPT_BOOLEAN ('e' , "edit" , & opts -> edit , "edit the commit message" ),
130153 { 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)
154177 PARSE_OPT_KEEP_ARGV0 |
155178 PARSE_OPT_KEEP_UNKNOWN );
156179
180+ /* Check for incompatible subcommands */
181+ verify_opt_mutually_compatible (me ,
182+ "--reset" , reset ,
183+ "--continue" , contin ,
184+ NULL );
185+
157186 /* Set the subcommand */
158187 if (reset )
159188 opts -> subcommand = REPLAY_RESET ;
189+ else if (contin )
190+ opts -> subcommand = REPLAY_CONTINUE ;
160191 else
161192 opts -> subcommand = REPLAY_NONE ;
162193
163194 /* 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 ,
166203 "--no-commit" , opts -> no_commit ,
167204 "--signoff" , opts -> signoff ,
168205 "--mainline" , opts -> mainline ,
@@ -668,6 +705,137 @@ static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
668705 return 0 ;
669706}
670707
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+
671839static void walk_revs_populate_todo (struct commit_list * * todo_list ,
672840 struct replay_opts * opts )
673841{
@@ -811,6 +979,15 @@ static int pick_revisions(struct replay_opts *opts)
811979 if (opts -> subcommand == REPLAY_RESET ) {
812980 remove_sequencer_state (1 );
813981 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 ;
814991 } else {
815992 /*
816993 * Start a new cherry-pick/ revert sequence; but
@@ -821,7 +998,8 @@ static int pick_revisions(struct replay_opts *opts)
821998 walk_revs_populate_todo (& todo_list , opts );
822999 if (create_seq_dir () < 0 ) {
8231000 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" ));
8251003 exit (128 );
8261004 }
8271005 if (get_sha1 ("HEAD" , sha1 )) {
@@ -833,6 +1011,8 @@ static int pick_revisions(struct replay_opts *opts)
8331011 save_opts (opts );
8341012 }
8351013 return pick_commits (todo_list , opts );
1014+ error :
1015+ die (_ ("No %s in progress" ), action_name (opts ));
8361016}
8371017
8381018int cmd_revert (int argc , const char * * argv , const char * prefix )
0 commit comments