@@ -2654,15 +2654,41 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
2654
2654
return 0 ;
2655
2655
}
2656
2656
2657
- static int create_seq_dir (void )
2657
+ static int create_seq_dir (struct repository * r )
2658
2658
{
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 | " : "" );
2662
2686
return -1 ;
2663
- } else if (mkdir (git_path_seq_dir (), 0777 ) < 0 )
2687
+ }
2688
+ if (mkdir (git_path_seq_dir (), 0777 ) < 0 )
2664
2689
return error_errno (_ ("could not create sequencer directory '%s'" ),
2665
2690
git_path_seq_dir ());
2691
+
2666
2692
return 0 ;
2667
2693
}
2668
2694
@@ -2713,15 +2739,20 @@ static int rollback_is_safe(void)
2713
2739
return oideq (& actual_head , & expected_head );
2714
2740
}
2715
2741
2716
- static int reset_for_rollback (const struct object_id * oid )
2742
+ static int reset_merge (const struct object_id * oid )
2717
2743
{
2718
- const char * argv [4 ]; /* reset --merge <arg> + NULL */
2744
+ int ret ;
2745
+ struct argv_array argv = ARGV_ARRAY_INIT ;
2719
2746
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 ;
2725
2756
}
2726
2757
2727
2758
static int rollback_single_pick (struct repository * r )
@@ -2735,7 +2766,16 @@ static int rollback_single_pick(struct repository *r)
2735
2766
return error (_ ("cannot resolve HEAD" ));
2736
2767
if (is_null_oid (& head_oid ))
2737
2768
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 );
2739
2779
}
2740
2780
2741
2781
int sequencer_rollback (struct repository * r , struct replay_opts * opts )
@@ -2778,7 +2818,7 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
2778
2818
warning (_ ("You seem to have moved HEAD. "
2779
2819
"Not rewinding, check your HEAD!" ));
2780
2820
} else
2781
- if (reset_for_rollback (& oid ))
2821
+ if (reset_merge (& oid ))
2782
2822
goto fail ;
2783
2823
strbuf_release (& buf );
2784
2824
return sequencer_remove_state (opts );
@@ -2787,6 +2827,70 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
2787
2827
return -1 ;
2788
2828
}
2789
2829
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
+
2790
2894
static int save_todo (struct todo_list * todo_list , struct replay_opts * opts )
2791
2895
{
2792
2896
struct lock_file todo_lock = LOCK_INIT ;
@@ -4257,7 +4361,7 @@ int sequencer_pick_revisions(struct repository *r,
4257
4361
*/
4258
4362
4259
4363
if (walk_revs_populate_todo (& todo_list , opts ) ||
4260
- create_seq_dir () < 0 )
4364
+ create_seq_dir (r ) < 0 )
4261
4365
return -1 ;
4262
4366
if (get_oid ("HEAD" , & oid ) && (opts -> action == REPLAY_REVERT ))
4263
4367
return error (_ ("can't revert as initial commit" ));
0 commit comments