21
21
#include "diff.h"
22
22
#include "wt-status.h"
23
23
#include "revision.h"
24
+ #include "rerere.h"
24
25
25
26
static char const * const builtin_rebase_usage [] = {
26
27
N_ ("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
@@ -91,6 +92,7 @@ struct rebase_options {
91
92
REBASE_INTERACTIVE_EXPLICIT = 1 <<4 ,
92
93
} flags ;
93
94
struct strbuf git_am_opt ;
95
+ const char * action ;
94
96
};
95
97
96
98
static int is_interactive (struct rebase_options * opts )
@@ -115,6 +117,62 @@ static const char *state_dir_path(const char *filename, struct rebase_options *o
115
117
return path .buf ;
116
118
}
117
119
120
+ /* Read one file, then strip line endings */
121
+ static int read_one (const char * path , struct strbuf * buf )
122
+ {
123
+ if (strbuf_read_file (buf , path , 0 ) < 0 )
124
+ return error_errno (_ ("could not read '%s'" ), path );
125
+ strbuf_trim_trailing_newline (buf );
126
+ return 0 ;
127
+ }
128
+
129
+ /* Initialize the rebase options from the state directory. */
130
+ static int read_basic_state (struct rebase_options * opts )
131
+ {
132
+ struct strbuf head_name = STRBUF_INIT ;
133
+ struct strbuf buf = STRBUF_INIT ;
134
+ struct object_id oid ;
135
+
136
+ if (read_one (state_dir_path ("head-name" , opts ), & head_name ) ||
137
+ read_one (state_dir_path ("onto" , opts ), & buf ))
138
+ return -1 ;
139
+ opts -> head_name = starts_with (head_name .buf , "refs/" ) ?
140
+ xstrdup (head_name .buf ) : NULL ;
141
+ strbuf_release (& head_name );
142
+ if (get_oid (buf .buf , & oid ))
143
+ return error (_ ("could not get 'onto': '%s'" ), buf .buf );
144
+ opts -> onto = lookup_commit_or_die (& oid , buf .buf );
145
+
146
+ /*
147
+ * We always write to orig-head, but interactive rebase used to write to
148
+ * head. Fall back to reading from head to cover for the case that the
149
+ * user upgraded git with an ongoing interactive rebase.
150
+ */
151
+ strbuf_reset (& buf );
152
+ if (file_exists (state_dir_path ("orig-head" , opts ))) {
153
+ if (read_one (state_dir_path ("orig-head" , opts ), & buf ))
154
+ return -1 ;
155
+ } else if (read_one (state_dir_path ("head" , opts ), & buf ))
156
+ return -1 ;
157
+ if (get_oid (buf .buf , & opts -> orig_head ))
158
+ return error (_ ("invalid orig-head: '%s'" ), buf .buf );
159
+
160
+ strbuf_reset (& buf );
161
+ if (read_one (state_dir_path ("quiet" , opts ), & buf ))
162
+ return -1 ;
163
+ if (buf .len )
164
+ opts -> flags &= ~REBASE_NO_QUIET ;
165
+ else
166
+ opts -> flags |= REBASE_NO_QUIET ;
167
+
168
+ if (file_exists (state_dir_path ("verbose" , opts )))
169
+ opts -> flags |= REBASE_VERBOSE ;
170
+
171
+ strbuf_release (& buf );
172
+
173
+ return 0 ;
174
+ }
175
+
118
176
static int finish_rebase (struct rebase_options * opts )
119
177
{
120
178
struct strbuf dir = STRBUF_INIT ;
@@ -168,12 +226,13 @@ static int run_specific_rebase(struct rebase_options *opts)
168
226
add_var (& script_snippet , "state_dir" , opts -> state_dir );
169
227
170
228
add_var (& script_snippet , "upstream_name" , opts -> upstream_name );
171
- add_var (& script_snippet , "upstream" ,
172
- oid_to_hex (& opts -> upstream -> object .oid ));
229
+ add_var (& script_snippet , "upstream" , opts -> upstream ?
230
+ oid_to_hex (& opts -> upstream -> object .oid ) : NULL );
173
231
add_var (& script_snippet , "head_name" ,
174
232
opts -> head_name ? opts -> head_name : "detached HEAD" );
175
233
add_var (& script_snippet , "orig_head" , oid_to_hex (& opts -> orig_head ));
176
- add_var (& script_snippet , "onto" , oid_to_hex (& opts -> onto -> object .oid ));
234
+ add_var (& script_snippet , "onto" , opts -> onto ?
235
+ oid_to_hex (& opts -> onto -> object .oid ) : NULL );
177
236
add_var (& script_snippet , "onto_name" , opts -> onto_name );
178
237
add_var (& script_snippet , "revisions" , opts -> revisions );
179
238
add_var (& script_snippet , "restrict_revision" , opts -> restrict_revision ?
@@ -189,6 +248,7 @@ static int run_specific_rebase(struct rebase_options *opts)
189
248
opts -> flags & REBASE_FORCE ? "t" : "" );
190
249
if (opts -> switch_to )
191
250
add_var (& script_snippet , "switch_to" , opts -> switch_to );
251
+ add_var (& script_snippet , "action" , opts -> action ? opts -> action : "" );
192
252
193
253
switch (opts -> type ) {
194
254
case REBASE_AM :
@@ -400,12 +460,21 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
400
460
.git_am_opt = STRBUF_INIT ,
401
461
};
402
462
const char * branch_name ;
403
- int ret , flags , in_progress = 0 ;
463
+ int ret , flags , total_argc , in_progress = 0 ;
404
464
int ok_to_skip_pre_rebase = 0 ;
405
465
struct strbuf msg = STRBUF_INIT ;
406
466
struct strbuf revisions = STRBUF_INIT ;
407
467
struct strbuf buf = STRBUF_INIT ;
408
468
struct object_id merge_base ;
469
+ enum {
470
+ NO_ACTION ,
471
+ ACTION_CONTINUE ,
472
+ ACTION_SKIP ,
473
+ ACTION_ABORT ,
474
+ ACTION_QUIT ,
475
+ ACTION_EDIT_TODO ,
476
+ ACTION_SHOW_CURRENT_PATCH ,
477
+ } action = NO_ACTION ;
409
478
struct option builtin_rebase_options [] = {
410
479
OPT_STRING (0 , "onto" , & options .onto_name ,
411
480
N_ ("revision" ),
@@ -427,6 +496,20 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
427
496
OPT_BIT (0 , "no-ff" , & options .flags ,
428
497
N_ ("cherry-pick all commits, even if unchanged" ),
429
498
REBASE_FORCE ),
499
+ OPT_CMDMODE (0 , "continue" , & action , N_ ("continue" ),
500
+ ACTION_CONTINUE ),
501
+ OPT_CMDMODE (0 , "skip" , & action ,
502
+ N_ ("skip current patch and continue" ), ACTION_SKIP ),
503
+ OPT_CMDMODE (0 , "abort" , & action ,
504
+ N_ ("abort and check out the original branch" ),
505
+ ACTION_ABORT ),
506
+ OPT_CMDMODE (0 , "quit" , & action ,
507
+ N_ ("abort but keep HEAD where it is" ), ACTION_QUIT ),
508
+ OPT_CMDMODE (0 , "edit-todo" , & action , N_ ("edit the todo list "
509
+ "during an interactive rebase" ), ACTION_EDIT_TODO ),
510
+ OPT_CMDMODE (0 , "show-current-patch" , & action ,
511
+ N_ ("show the patch file being applied or merged" ),
512
+ ACTION_SHOW_CURRENT_PATCH ),
430
513
OPT_END (),
431
514
};
432
515
@@ -456,6 +539,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
456
539
457
540
git_config (rebase_config , & options );
458
541
542
+ strbuf_reset (& buf );
543
+ strbuf_addf (& buf , "%s/applying" , apply_dir ());
544
+ if (file_exists (buf .buf ))
545
+ die (_ ("It looks like 'git am' is in progress. Cannot rebase." ));
546
+
459
547
if (is_directory (apply_dir ())) {
460
548
options .type = REBASE_AM ;
461
549
options .state_dir = apply_dir ();
@@ -480,14 +568,110 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
480
568
if (options .type != REBASE_UNSPECIFIED )
481
569
in_progress = 1 ;
482
570
571
+ total_argc = argc ;
483
572
argc = parse_options (argc , argv , prefix ,
484
573
builtin_rebase_options ,
485
574
builtin_rebase_usage , 0 );
486
575
576
+ if (action != NO_ACTION && total_argc != 2 ) {
577
+ usage_with_options (builtin_rebase_usage ,
578
+ builtin_rebase_options );
579
+ }
580
+
487
581
if (argc > 2 )
488
582
usage_with_options (builtin_rebase_usage ,
489
583
builtin_rebase_options );
490
584
585
+ if (action != NO_ACTION && !in_progress )
586
+ die (_ ("No rebase in progress?" ));
587
+
588
+ if (action == ACTION_EDIT_TODO && !is_interactive (& options ))
589
+ die (_ ("The --edit-todo action can only be used during "
590
+ "interactive rebase." ));
591
+
592
+ switch (action ) {
593
+ case ACTION_CONTINUE : {
594
+ struct object_id head ;
595
+ struct lock_file lock_file = LOCK_INIT ;
596
+ int fd ;
597
+
598
+ options .action = "continue" ;
599
+
600
+ /* Sanity check */
601
+ if (get_oid ("HEAD" , & head ))
602
+ die (_ ("Cannot read HEAD" ));
603
+
604
+ fd = hold_locked_index (& lock_file , 0 );
605
+ if (read_index (the_repository -> index ) < 0 )
606
+ die (_ ("could not read index" ));
607
+ refresh_index (the_repository -> index , REFRESH_QUIET , NULL , NULL ,
608
+ NULL );
609
+ if (0 <= fd )
610
+ update_index_if_able (the_repository -> index ,
611
+ & lock_file );
612
+ rollback_lock_file (& lock_file );
613
+
614
+ if (has_unstaged_changes (1 )) {
615
+ puts (_ ("You must edit all merge conflicts and then\n"
616
+ "mark them as resolved using git add" ));
617
+ exit (1 );
618
+ }
619
+ if (read_basic_state (& options ))
620
+ exit (1 );
621
+ goto run_rebase ;
622
+ }
623
+ case ACTION_SKIP : {
624
+ struct string_list merge_rr = STRING_LIST_INIT_DUP ;
625
+
626
+ options .action = "skip" ;
627
+
628
+ rerere_clear (& merge_rr );
629
+ string_list_clear (& merge_rr , 1 );
630
+
631
+ if (reset_head (NULL , "reset" , NULL , 0 ) < 0 )
632
+ die (_ ("could not discard worktree changes" ));
633
+ if (read_basic_state (& options ))
634
+ exit (1 );
635
+ goto run_rebase ;
636
+ }
637
+ case ACTION_ABORT : {
638
+ struct string_list merge_rr = STRING_LIST_INIT_DUP ;
639
+ options .action = "abort" ;
640
+
641
+ rerere_clear (& merge_rr );
642
+ string_list_clear (& merge_rr , 1 );
643
+
644
+ if (read_basic_state (& options ))
645
+ exit (1 );
646
+ if (reset_head (& options .orig_head , "reset" ,
647
+ options .head_name , 0 ) < 0 )
648
+ die (_ ("could not move back to %s" ),
649
+ oid_to_hex (& options .orig_head ));
650
+ ret = finish_rebase (& options );
651
+ goto cleanup ;
652
+ }
653
+ case ACTION_QUIT : {
654
+ strbuf_reset (& buf );
655
+ strbuf_addstr (& buf , options .state_dir );
656
+ ret = !!remove_dir_recursively (& buf , 0 );
657
+ if (ret )
658
+ die (_ ("could not remove '%s'" ), options .state_dir );
659
+ goto cleanup ;
660
+ }
661
+ case ACTION_EDIT_TODO :
662
+ options .action = "edit-todo" ;
663
+ options .dont_finish_rebase = 1 ;
664
+ goto run_rebase ;
665
+ case ACTION_SHOW_CURRENT_PATCH :
666
+ options .action = "show-current-patch" ;
667
+ options .dont_finish_rebase = 1 ;
668
+ goto run_rebase ;
669
+ case NO_ACTION :
670
+ break ;
671
+ default :
672
+ BUG ("action: %d" , action );
673
+ }
674
+
491
675
/* Make sure no rebase is in progress */
492
676
if (in_progress ) {
493
677
const char * last_slash = strrchr (options .state_dir , '/' );
@@ -719,6 +903,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
719
903
720
904
options .revisions = revisions .buf ;
721
905
906
+ run_rebase :
722
907
ret = !!run_specific_rebase (& options );
723
908
724
909
cleanup :
0 commit comments