23
23
#include "hashmap.h"
24
24
#include "notes-utils.h"
25
25
#include "sigchain.h"
26
+ #include "unpack-trees.h"
27
+ #include "worktree.h"
26
28
27
29
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
28
30
@@ -120,6 +122,13 @@ static GIT_PATH_FUNC(rebase_path_stopped_sha, "rebase-merge/stopped-sha")
120
122
static GIT_PATH_FUNC (rebase_path_rewritten_list , "rebase-merge/rewritten-list" )
121
123
static GIT_PATH_FUNC (rebase_path_rewritten_pending ,
122
124
"rebase-merge/rewritten-pending" )
125
+
126
+ /*
127
+ * The path of the file listing refs that need to be deleted after the rebase
128
+ * finishes. This is used by the `label` command to record the need for cleanup.
129
+ */
130
+ static GIT_PATH_FUNC (rebase_path_refs_to_delete , "rebase-merge/refs-to-delete" )
131
+
123
132
/*
124
133
* The following files are written by git-rebase just after parsing the
125
134
* command-line (and are only consumed, not modified, by the sequencer).
@@ -245,18 +254,34 @@ static const char *gpg_sign_opt_quoted(struct replay_opts *opts)
245
254
246
255
int sequencer_remove_state (struct replay_opts * opts )
247
256
{
248
- struct strbuf dir = STRBUF_INIT ;
257
+ struct strbuf buf = STRBUF_INIT ;
249
258
int i ;
250
259
260
+ if (is_rebase_i (opts ) &&
261
+ strbuf_read_file (& buf , rebase_path_refs_to_delete (), 0 ) > 0 ) {
262
+ char * p = buf .buf ;
263
+ while (* p ) {
264
+ char * eol = strchr (p , '\n' );
265
+ if (eol )
266
+ * eol = '\0' ;
267
+ if (delete_ref ("(rebase -i) cleanup" , p , NULL , 0 ) < 0 )
268
+ warning (_ ("could not delete '%s'" ), p );
269
+ if (!eol )
270
+ break ;
271
+ p = eol + 1 ;
272
+ }
273
+ }
274
+
251
275
free (opts -> gpg_sign );
252
276
free (opts -> strategy );
253
277
for (i = 0 ; i < opts -> xopts_nr ; i ++ )
254
278
free (opts -> xopts [i ]);
255
279
free (opts -> xopts );
256
280
257
- strbuf_addstr (& dir , get_dir (opts ));
258
- remove_dir_recursively (& dir , 0 );
259
- strbuf_release (& dir );
281
+ strbuf_reset (& buf );
282
+ strbuf_addstr (& buf , get_dir (opts ));
283
+ remove_dir_recursively (& buf , 0 );
284
+ strbuf_release (& buf );
260
285
261
286
return 0 ;
262
287
}
@@ -1280,6 +1305,8 @@ enum todo_command {
1280
1305
TODO_SQUASH ,
1281
1306
/* commands that do something else than handling a single commit */
1282
1307
TODO_EXEC ,
1308
+ TODO_LABEL ,
1309
+ TODO_RESET ,
1283
1310
/* commands that do nothing but are counted for reporting progress */
1284
1311
TODO_NOOP ,
1285
1312
TODO_DROP ,
@@ -1298,6 +1325,8 @@ static struct {
1298
1325
{ 'f' , "fixup" },
1299
1326
{ 's' , "squash" },
1300
1327
{ 'x' , "exec" },
1328
+ { 'l' , "label" },
1329
+ { 't' , "reset" },
1301
1330
{ 0 , "noop" },
1302
1331
{ 'd' , "drop" },
1303
1332
{ 0 , NULL }
@@ -1803,7 +1832,8 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
1803
1832
return error (_ ("missing arguments for %s" ),
1804
1833
command_to_string (item -> command ));
1805
1834
1806
- if (item -> command == TODO_EXEC ) {
1835
+ if (item -> command == TODO_EXEC || item -> command == TODO_LABEL ||
1836
+ item -> command == TODO_RESET ) {
1807
1837
item -> commit = NULL ;
1808
1838
item -> arg = bol ;
1809
1839
item -> arg_len = (int )(eol - bol );
@@ -2471,6 +2501,159 @@ static int do_exec(const char *command_line)
2471
2501
return status ;
2472
2502
}
2473
2503
2504
+ static int safe_append (const char * filename , const char * fmt , ...)
2505
+ {
2506
+ va_list ap ;
2507
+ struct lock_file lock = LOCK_INIT ;
2508
+ int fd = hold_lock_file_for_update (& lock , filename ,
2509
+ LOCK_REPORT_ON_ERROR );
2510
+ struct strbuf buf = STRBUF_INIT ;
2511
+
2512
+ if (fd < 0 )
2513
+ return -1 ;
2514
+
2515
+ if (strbuf_read_file (& buf , filename , 0 ) < 0 && errno != ENOENT ) {
2516
+ error_errno (_ ("could not read '%s'" ), filename );
2517
+ rollback_lock_file (& lock );
2518
+ return -1 ;
2519
+ }
2520
+ strbuf_complete (& buf , '\n' );
2521
+ va_start (ap , fmt );
2522
+ strbuf_vaddf (& buf , fmt , ap );
2523
+ va_end (ap );
2524
+
2525
+ if (write_in_full (fd , buf .buf , buf .len ) < 0 ) {
2526
+ error_errno (_ ("could not write to '%s'" ), filename );
2527
+ strbuf_release (& buf );
2528
+ rollback_lock_file (& lock );
2529
+ return -1 ;
2530
+ }
2531
+ if (commit_lock_file (& lock ) < 0 ) {
2532
+ strbuf_release (& buf );
2533
+ rollback_lock_file (& lock );
2534
+ return error (_ ("failed to finalize '%s'" ), filename );
2535
+ }
2536
+
2537
+ strbuf_release (& buf );
2538
+ return 0 ;
2539
+ }
2540
+
2541
+ static int do_label (const char * name , int len )
2542
+ {
2543
+ struct ref_store * refs = get_main_ref_store ();
2544
+ struct ref_transaction * transaction ;
2545
+ struct strbuf ref_name = STRBUF_INIT , err = STRBUF_INIT ;
2546
+ struct strbuf msg = STRBUF_INIT ;
2547
+ int ret = 0 ;
2548
+ struct object_id head_oid ;
2549
+
2550
+ if (len == 1 && * name == '#' )
2551
+ return error ("Illegal label name: '%.*s'" , len , name );
2552
+
2553
+ strbuf_addf (& ref_name , "refs/rewritten/%.*s" , len , name );
2554
+ strbuf_addf (& msg , "rebase -i (label) '%.*s'" , len , name );
2555
+
2556
+ transaction = ref_store_transaction_begin (refs , & err );
2557
+ if (!transaction ) {
2558
+ error ("%s" , err .buf );
2559
+ ret = -1 ;
2560
+ } else if (get_oid ("HEAD" , & head_oid )) {
2561
+ error (_ ("could not read HEAD" ));
2562
+ ret = -1 ;
2563
+ } else if (ref_transaction_update (transaction , ref_name .buf , & head_oid ,
2564
+ NULL , 0 , msg .buf , & err ) < 0 ||
2565
+ ref_transaction_commit (transaction , & err )) {
2566
+ error ("%s" , err .buf );
2567
+ ret = -1 ;
2568
+ }
2569
+ ref_transaction_free (transaction );
2570
+ strbuf_release (& err );
2571
+ strbuf_release (& msg );
2572
+
2573
+ if (!ret )
2574
+ ret = safe_append (rebase_path_refs_to_delete (),
2575
+ "%s\n" , ref_name .buf );
2576
+ strbuf_release (& ref_name );
2577
+
2578
+ return ret ;
2579
+ }
2580
+
2581
+ static const char * reflog_message (struct replay_opts * opts ,
2582
+ const char * sub_action , const char * fmt , ...);
2583
+
2584
+ static int do_reset (const char * name , int len , struct replay_opts * opts )
2585
+ {
2586
+ struct strbuf ref_name = STRBUF_INIT ;
2587
+ struct object_id oid ;
2588
+ struct lock_file lock = LOCK_INIT ;
2589
+ struct tree_desc desc ;
2590
+ struct tree * tree ;
2591
+ struct unpack_trees_options unpack_tree_opts ;
2592
+ int ret = 0 , i ;
2593
+
2594
+ if (hold_locked_index (& lock , LOCK_REPORT_ON_ERROR ) < 0 )
2595
+ return -1 ;
2596
+
2597
+ /* Determine the length of the label */
2598
+ for (i = 0 ; i < len ; i ++ )
2599
+ if (isspace (name [i ]))
2600
+ len = i ;
2601
+
2602
+ strbuf_addf (& ref_name , "refs/rewritten/%.*s" , len , name );
2603
+ if (get_oid (ref_name .buf , & oid ) &&
2604
+ get_oid (ref_name .buf + strlen ("refs/rewritten/" ), & oid )) {
2605
+ error (_ ("could not read '%s'" ), ref_name .buf );
2606
+ rollback_lock_file (& lock );
2607
+ strbuf_release (& ref_name );
2608
+ return -1 ;
2609
+ }
2610
+
2611
+ memset (& unpack_tree_opts , 0 , sizeof (unpack_tree_opts ));
2612
+ setup_unpack_trees_porcelain (& unpack_tree_opts , "reset" );
2613
+ unpack_tree_opts .head_idx = 1 ;
2614
+ unpack_tree_opts .src_index = & the_index ;
2615
+ unpack_tree_opts .dst_index = & the_index ;
2616
+ unpack_tree_opts .fn = oneway_merge ;
2617
+ unpack_tree_opts .merge = 1 ;
2618
+ unpack_tree_opts .update = 1 ;
2619
+
2620
+ if (read_cache_unmerged ()) {
2621
+ rollback_lock_file (& lock );
2622
+ strbuf_release (& ref_name );
2623
+ return error_resolve_conflict (_ (action_name (opts )));
2624
+ }
2625
+
2626
+ if (!fill_tree_descriptor (& desc , & oid )) {
2627
+ error (_ ("failed to find tree of %s" ), oid_to_hex (& oid ));
2628
+ rollback_lock_file (& lock );
2629
+ free ((void * )desc .buffer );
2630
+ strbuf_release (& ref_name );
2631
+ return -1 ;
2632
+ }
2633
+
2634
+ if (unpack_trees (1 , & desc , & unpack_tree_opts )) {
2635
+ rollback_lock_file (& lock );
2636
+ free ((void * )desc .buffer );
2637
+ strbuf_release (& ref_name );
2638
+ return -1 ;
2639
+ }
2640
+
2641
+ tree = parse_tree_indirect (& oid );
2642
+ prime_cache_tree (& the_index , tree );
2643
+
2644
+ if (write_locked_index (& the_index , & lock , COMMIT_LOCK ) < 0 )
2645
+ ret = error (_ ("could not write index" ));
2646
+ free ((void * )desc .buffer );
2647
+
2648
+ if (!ret )
2649
+ ret = update_ref (reflog_message (opts , "reset" , "'%.*s'" ,
2650
+ len , name ), "HEAD" , & oid ,
2651
+ NULL , 0 , UPDATE_REFS_MSG_ON_ERR );
2652
+
2653
+ strbuf_release (& ref_name );
2654
+ return ret ;
2655
+ }
2656
+
2474
2657
static int is_final_fixup (struct todo_list * todo_list )
2475
2658
{
2476
2659
int i = todo_list -> current ;
@@ -2574,7 +2757,7 @@ N_("Could not execute the todo command\n"
2574
2757
2575
2758
static int pick_commits (struct todo_list * todo_list , struct replay_opts * opts )
2576
2759
{
2577
- int res = 0 ;
2760
+ int res = 0 , reschedule = 0 ;
2578
2761
2579
2762
setenv (GIT_REFLOG_ACTION , action_name (opts ), 0 );
2580
2763
if (opts -> allow_ff )
@@ -2645,7 +2828,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
2645
2828
intend_to_amend ();
2646
2829
return error_failed_squash (item -> commit , opts ,
2647
2830
item -> arg_len , item -> arg );
2648
- } else if (res && is_rebase_i (opts ))
2831
+ } else if (res && is_rebase_i (opts ) && item -> commit )
2649
2832
return res | error_with_patch (item -> commit ,
2650
2833
item -> arg , item -> arg_len , opts , res ,
2651
2834
item -> command == TODO_REWORD );
@@ -2671,9 +2854,25 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
2671
2854
/* `current` will be incremented below */
2672
2855
todo_list -> current = -1 ;
2673
2856
}
2857
+ } else if (item -> command == TODO_LABEL ) {
2858
+ if ((res = do_label (item -> arg , item -> arg_len )))
2859
+ reschedule = 1 ;
2860
+ } else if (item -> command == TODO_RESET ) {
2861
+ if ((res = do_reset (item -> arg , item -> arg_len , opts )))
2862
+ reschedule = 1 ;
2674
2863
} else if (!is_noop (item -> command ))
2675
2864
return error (_ ("unknown command %d" ), item -> command );
2676
2865
2866
+ if (reschedule ) {
2867
+ advise (_ (rescheduled_advice ),
2868
+ get_item_line_length (todo_list ,
2869
+ todo_list -> current ),
2870
+ get_item_line (todo_list , todo_list -> current ));
2871
+ todo_list -> current -- ;
2872
+ if (save_todo (todo_list , opts ))
2873
+ return -1 ;
2874
+ }
2875
+
2677
2876
todo_list -> current ++ ;
2678
2877
if (res )
2679
2878
return res ;
0 commit comments