@@ -125,6 +125,12 @@ static GIT_PATH_FUNC(rebase_path_rewritten_list, "rebase-merge/rewritten-list")
125
125
static GIT_PATH_FUNC (rebase_path_rewritten_pending ,
126
126
"rebase-merge/rewritten-pending" )
127
127
128
+ /*
129
+ * The path of the file containig the OID of the "squash onto" commit, i.e.
130
+ * the dummy commit used for `reset [new root]`.
131
+ */
132
+ static GIT_PATH_FUNC (rebase_path_squash_onto , "rebase-merge/squash-onto" )
133
+
128
134
/*
129
135
* The path of the file listing refs that need to be deleted after the rebase
130
136
* finishes. This is used by the `label` command to record the need for cleanup.
@@ -470,7 +476,8 @@ static int fast_forward_to(const struct object_id *to, const struct object_id *f
470
476
transaction = ref_transaction_begin (& err );
471
477
if (!transaction ||
472
478
ref_transaction_update (transaction , "HEAD" ,
473
- to , unborn ? & null_oid : from ,
479
+ to , unborn && !is_rebase_i (opts ) ?
480
+ & null_oid : from ,
474
481
0 , sb .buf , & err ) ||
475
482
ref_transaction_commit (transaction , & err )) {
476
483
ref_transaction_free (transaction );
@@ -692,6 +699,52 @@ static char *get_author(const char *message)
692
699
return NULL ;
693
700
}
694
701
702
+ /* Read author-script and return an ident line (author <email> timestamp) */
703
+ static const char * read_author_ident (struct strbuf * buf )
704
+ {
705
+ const char * keys [] = {
706
+ "GIT_AUTHOR_NAME=" , "GIT_AUTHOR_EMAIL=" , "GIT_AUTHOR_DATE="
707
+ };
708
+ char * in , * out , * eol ;
709
+ int i = 0 , len ;
710
+
711
+ if (strbuf_read_file (buf , rebase_path_author_script (), 256 ) <= 0 )
712
+ return NULL ;
713
+
714
+ /* dequote values and construct ident line in-place */
715
+ for (in = out = buf -> buf ; i < 3 && in - buf -> buf < buf -> len ; i ++ ) {
716
+ if (!skip_prefix (in , keys [i ], (const char * * )& in )) {
717
+ warning ("could not parse '%s' (looking for '%s'" ,
718
+ rebase_path_author_script (), keys [i ]);
719
+ return NULL ;
720
+ }
721
+
722
+ eol = strchrnul (in , '\n' );
723
+ * eol = '\0' ;
724
+ sq_dequote (in );
725
+ len = strlen (in );
726
+
727
+ if (i > 0 ) /* separate values by spaces */
728
+ * (out ++ ) = ' ' ;
729
+ if (i == 1 ) /* email needs to be surrounded by <...> */
730
+ * (out ++ ) = '<' ;
731
+ memmove (out , in , len );
732
+ out += len ;
733
+ if (i == 1 ) /* email needs to be surrounded by <...> */
734
+ * (out ++ ) = '>' ;
735
+ in = eol + 1 ;
736
+ }
737
+
738
+ if (i < 3 ) {
739
+ warning ("could not parse '%s' (looking for '%s')" ,
740
+ rebase_path_author_script (), keys [i ]);
741
+ return NULL ;
742
+ }
743
+
744
+ buf -> len = out - buf -> buf ;
745
+ return buf -> buf ;
746
+ }
747
+
695
748
static const char staged_changes_advice [] =
696
749
N_ ("you have staged changes in your working tree\n"
697
750
"If these changes are meant to be squashed into the previous commit, run:\n"
@@ -711,6 +764,7 @@ N_("you have staged changes in your working tree\n"
711
764
#define AMEND_MSG (1<<2)
712
765
#define CLEANUP_MSG (1<<3)
713
766
#define VERIFY_MSG (1<<4)
767
+ #define CREATE_ROOT_COMMIT (1<<5)
714
768
715
769
/*
716
770
* If we are cherry-pick, and if the merge did not result in
@@ -730,6 +784,40 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
730
784
struct child_process cmd = CHILD_PROCESS_INIT ;
731
785
const char * value ;
732
786
787
+ if (flags & CREATE_ROOT_COMMIT ) {
788
+ struct strbuf msg = STRBUF_INIT , script = STRBUF_INIT ;
789
+ const char * author = is_rebase_i (opts ) ?
790
+ read_author_ident (& script ) : NULL ;
791
+ struct object_id root_commit , * cache_tree_oid ;
792
+ int res = 0 ;
793
+
794
+ if (!defmsg )
795
+ BUG ("root commit without message" );
796
+
797
+ if (!(cache_tree_oid = get_cache_tree_oid ()))
798
+ res = -1 ;
799
+
800
+ if (!res )
801
+ res = strbuf_read_file (& msg , defmsg , 0 );
802
+
803
+ if (res <= 0 )
804
+ res = error_errno (_ ("could not read '%s'" ), defmsg );
805
+ else
806
+ res = commit_tree (msg .buf , msg .len , cache_tree_oid ,
807
+ NULL , & root_commit , author ,
808
+ opts -> gpg_sign );
809
+
810
+ strbuf_release (& msg );
811
+ strbuf_release (& script );
812
+ if (!res ) {
813
+ update_ref (NULL , "CHERRY_PICK_HEAD" , & root_commit , NULL ,
814
+ REF_NO_DEREF , UPDATE_REFS_MSG_ON_ERR );
815
+ res = update_ref (NULL , "HEAD" , & root_commit , NULL , 0 ,
816
+ UPDATE_REFS_MSG_ON_ERR );
817
+ }
818
+ return res < 0 ? error (_ ("writing root commit" )) : 0 ;
819
+ }
820
+
733
821
cmd .git_cmd = 1 ;
734
822
735
823
if (is_rebase_i (opts )) {
@@ -1216,7 +1304,8 @@ static int do_commit(const char *msg_file, const char *author,
1216
1304
{
1217
1305
int res = 1 ;
1218
1306
1219
- if (!(flags & EDIT_MSG ) && !(flags & VERIFY_MSG )) {
1307
+ if (!(flags & EDIT_MSG ) && !(flags & VERIFY_MSG ) &&
1308
+ !(flags & CREATE_ROOT_COMMIT )) {
1220
1309
struct object_id oid ;
1221
1310
struct strbuf sb = STRBUF_INIT ;
1222
1311
@@ -1369,6 +1458,22 @@ static int is_fixup(enum todo_command command)
1369
1458
return command == TODO_FIXUP || command == TODO_SQUASH ;
1370
1459
}
1371
1460
1461
+ /* Does this command create a (non-merge) commit? */
1462
+ static int is_pick_or_similar (enum todo_command command )
1463
+ {
1464
+ switch (command ) {
1465
+ case TODO_PICK :
1466
+ case TODO_REVERT :
1467
+ case TODO_EDIT :
1468
+ case TODO_REWORD :
1469
+ case TODO_FIXUP :
1470
+ case TODO_SQUASH :
1471
+ return 1 ;
1472
+ default :
1473
+ return 0 ;
1474
+ }
1475
+ }
1476
+
1372
1477
static int update_squash_messages (enum todo_command command ,
1373
1478
struct commit * commit , struct replay_opts * opts )
1374
1479
{
@@ -1523,7 +1628,14 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
1523
1628
return error (_ ("your index file is unmerged." ));
1524
1629
} else {
1525
1630
unborn = get_oid ("HEAD" , & head );
1526
- if (unborn )
1631
+ /* Do we want to generate a root commit? */
1632
+ if (is_pick_or_similar (command ) && opts -> have_squash_onto &&
1633
+ !oidcmp (& head , & opts -> squash_onto )) {
1634
+ if (is_fixup (command ))
1635
+ return error (_ ("cannot fixup root commit" ));
1636
+ flags |= CREATE_ROOT_COMMIT ;
1637
+ unborn = 1 ;
1638
+ } else if (unborn )
1527
1639
oidcpy (& head , the_hash_algo -> empty_tree );
1528
1640
if (index_differs_from (unborn ? EMPTY_TREE_SHA1_HEX : "HEAD" ,
1529
1641
NULL , 0 ))
@@ -2136,6 +2248,12 @@ static int read_populate_opts(struct replay_opts *opts)
2136
2248
read_strategy_opts (opts , & buf );
2137
2249
strbuf_release (& buf );
2138
2250
2251
+ if (read_oneliner (& buf , rebase_path_squash_onto (), 0 )) {
2252
+ if (get_oid_hex (buf .buf , & opts -> squash_onto ) < 0 )
2253
+ return error (_ ("unusable squash-onto" ));
2254
+ opts -> have_squash_onto = 1 ;
2255
+ }
2256
+
2139
2257
return 0 ;
2140
2258
}
2141
2259
0 commit comments