@@ -2654,15 +2654,41 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
26542654 return 0 ;
26552655}
26562656
2657- static int create_seq_dir (void )
2657+ static int create_seq_dir (struct repository * r )
26582658{
2659- if (file_exists (git_path_seq_dir ())) {
2660- error (_ ("a cherry-pick or revert is already in progress" ));
2661- advise (_ ("try \"git cherry-pick (--continue | --quit | --abort)\"" ));
2659+ enum replay_action action ;
2660+ const char * in_progress_error = NULL ;
2661+ const char * in_progress_advice = NULL ;
2662+ unsigned int advise_skip = file_exists (git_path_revert_head (r )) ||
2663+ file_exists (git_path_cherry_pick_head (r ));
2664+
2665+ if (!sequencer_get_last_command (r , & action )) {
2666+ switch (action ) {
2667+ case REPLAY_REVERT :
2668+ in_progress_error = _ ("revert is already in progress" );
2669+ in_progress_advice =
2670+ _ ("try \"git revert (--continue | %s--abort | --quit)\"" );
2671+ break ;
2672+ case REPLAY_PICK :
2673+ in_progress_error = _ ("cherry-pick is already in progress" );
2674+ in_progress_advice =
2675+ _ ("try \"git cherry-pick (--continue | %s--abort | --quit)\"" );
2676+ break ;
2677+ default :
2678+ BUG ("unexpected action in create_seq_dir" );
2679+ }
2680+ }
2681+ if (in_progress_error ) {
2682+ error ("%s" , in_progress_error );
2683+ if (advice_sequencer_in_use )
2684+ advise (in_progress_advice ,
2685+ advise_skip ? "--skip | " : "" );
26622686 return -1 ;
2663- } else if (mkdir (git_path_seq_dir (), 0777 ) < 0 )
2687+ }
2688+ if (mkdir (git_path_seq_dir (), 0777 ) < 0 )
26642689 return error_errno (_ ("could not create sequencer directory '%s'" ),
26652690 git_path_seq_dir ());
2691+
26662692 return 0 ;
26672693}
26682694
@@ -2713,15 +2739,20 @@ static int rollback_is_safe(void)
27132739 return oideq (& actual_head , & expected_head );
27142740}
27152741
2716- static int reset_for_rollback (const struct object_id * oid )
2742+ static int reset_merge (const struct object_id * oid )
27172743{
2718- const char * argv [4 ]; /* reset --merge <arg> + NULL */
2744+ int ret ;
2745+ struct argv_array argv = ARGV_ARRAY_INIT ;
27192746
2720- argv [0 ] = "reset" ;
2721- argv [1 ] = "--merge" ;
2722- argv [2 ] = oid_to_hex (oid );
2723- argv [3 ] = NULL ;
2724- return run_command_v_opt (argv , RUN_GIT_CMD );
2747+ argv_array_pushl (& argv , "reset" , "--merge" , NULL );
2748+
2749+ if (!is_null_oid (oid ))
2750+ argv_array_push (& argv , oid_to_hex (oid ));
2751+
2752+ ret = run_command_v_opt (argv .argv , RUN_GIT_CMD );
2753+ argv_array_clear (& argv );
2754+
2755+ return ret ;
27252756}
27262757
27272758static int rollback_single_pick (struct repository * r )
@@ -2735,7 +2766,16 @@ static int rollback_single_pick(struct repository *r)
27352766 return error (_ ("cannot resolve HEAD" ));
27362767 if (is_null_oid (& head_oid ))
27372768 return error (_ ("cannot abort from a branch yet to be born" ));
2738- return reset_for_rollback (& head_oid );
2769+ return reset_merge (& head_oid );
2770+ }
2771+
2772+ static int skip_single_pick (void )
2773+ {
2774+ struct object_id head ;
2775+
2776+ if (read_ref_full ("HEAD" , 0 , & head , NULL ))
2777+ return error (_ ("cannot resolve HEAD" ));
2778+ return reset_merge (& head );
27392779}
27402780
27412781int sequencer_rollback (struct repository * r , struct replay_opts * opts )
@@ -2778,7 +2818,7 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
27782818 warning (_ ("You seem to have moved HEAD. "
27792819 "Not rewinding, check your HEAD!" ));
27802820 } else
2781- if (reset_for_rollback (& oid ))
2821+ if (reset_merge (& oid ))
27822822 goto fail ;
27832823 strbuf_release (& buf );
27842824 return sequencer_remove_state (opts );
@@ -2787,6 +2827,70 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
27872827 return -1 ;
27882828}
27892829
2830+ int sequencer_skip (struct repository * r , struct replay_opts * opts )
2831+ {
2832+ enum replay_action action = -1 ;
2833+ sequencer_get_last_command (r , & action );
2834+
2835+ /*
2836+ * Check whether the subcommand requested to skip the commit is actually
2837+ * in progress and that it's safe to skip the commit.
2838+ *
2839+ * opts->action tells us which subcommand requested to skip the commit.
2840+ * If the corresponding .git/<ACTION>_HEAD exists, we know that the
2841+ * action is in progress and we can skip the commit.
2842+ *
2843+ * Otherwise we check that the last instruction was related to the
2844+ * particular subcommand we're trying to execute and barf if that's not
2845+ * the case.
2846+ *
2847+ * Finally we check that the rollback is "safe", i.e., has the HEAD
2848+ * moved? In this case, it doesn't make sense to "reset the merge" and
2849+ * "skip the commit" as the user already handled this by committing. But
2850+ * we'd not want to barf here, instead give advice on how to proceed. We
2851+ * only need to check that when .git/<ACTION>_HEAD doesn't exist because
2852+ * it gets removed when the user commits, so if it still exists we're
2853+ * sure the user can't have committed before.
2854+ */
2855+ switch (opts -> action ) {
2856+ case REPLAY_REVERT :
2857+ if (!file_exists (git_path_revert_head (r ))) {
2858+ if (action != REPLAY_REVERT )
2859+ return error (_ ("no revert in progress" ));
2860+ if (!rollback_is_safe ())
2861+ goto give_advice ;
2862+ }
2863+ break ;
2864+ case REPLAY_PICK :
2865+ if (!file_exists (git_path_cherry_pick_head (r ))) {
2866+ if (action != REPLAY_PICK )
2867+ return error (_ ("no cherry-pick in progress" ));
2868+ if (!rollback_is_safe ())
2869+ goto give_advice ;
2870+ }
2871+ break ;
2872+ default :
2873+ BUG ("unexpected action in sequencer_skip" );
2874+ }
2875+
2876+ if (skip_single_pick ())
2877+ return error (_ ("failed to skip the commit" ));
2878+ if (!is_directory (git_path_seq_dir ()))
2879+ return 0 ;
2880+
2881+ return sequencer_continue (r , opts );
2882+
2883+ give_advice :
2884+ error (_ ("there is nothing to skip" ));
2885+
2886+ if (advice_resolve_conflict ) {
2887+ advise (_ ("have you committed already?\n"
2888+ "try \"git %s --continue\"" ),
2889+ action == REPLAY_REVERT ? "revert" : "cherry-pick" );
2890+ }
2891+ return -1 ;
2892+ }
2893+
27902894static int save_todo (struct todo_list * todo_list , struct replay_opts * opts )
27912895{
27922896 struct lock_file todo_lock = LOCK_INIT ;
@@ -4257,7 +4361,7 @@ int sequencer_pick_revisions(struct repository *r,
42574361 */
42584362
42594363 if (walk_revs_populate_todo (& todo_list , opts ) ||
4260- create_seq_dir () < 0 )
4364+ create_seq_dir (r ) < 0 )
42614365 return -1 ;
42624366 if (get_oid ("HEAD" , & oid ) && (opts -> action == REPLAY_REVERT ))
42634367 return error (_ ("can't revert as initial commit" ));
0 commit comments