@@ -125,6 +125,12 @@ static GIT_PATH_FUNC(rebase_path_rewritten_list, "rebase-merge/rewritten-list")
125125static GIT_PATH_FUNC (rebase_path_rewritten_pending ,
126126 "rebase-merge/rewritten-pending" )
127127
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+
128134/*
129135 * The path of the file listing refs that need to be deleted after the rebase
130136 * 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
470476 transaction = ref_transaction_begin (& err );
471477 if (!transaction ||
472478 ref_transaction_update (transaction , "HEAD" ,
473- to , unborn ? & null_oid : from ,
479+ to , unborn && !is_rebase_i (opts ) ?
480+ & null_oid : from ,
474481 0 , sb .buf , & err ) ||
475482 ref_transaction_commit (transaction , & err )) {
476483 ref_transaction_free (transaction );
@@ -692,6 +699,52 @@ static char *get_author(const char *message)
692699 return NULL ;
693700}
694701
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+
695748static const char staged_changes_advice [] =
696749N_ ("you have staged changes in your working tree\n"
697750"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"
711764#define AMEND_MSG (1<<2)
712765#define CLEANUP_MSG (1<<3)
713766#define VERIFY_MSG (1<<4)
767+ #define CREATE_ROOT_COMMIT (1<<5)
714768
715769/*
716770 * 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,
730784 struct child_process cmd = CHILD_PROCESS_INIT ;
731785 const char * value ;
732786
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+
733821 cmd .git_cmd = 1 ;
734822
735823 if (is_rebase_i (opts )) {
@@ -1216,7 +1304,8 @@ static int do_commit(const char *msg_file, const char *author,
12161304{
12171305 int res = 1 ;
12181306
1219- if (!(flags & EDIT_MSG ) && !(flags & VERIFY_MSG )) {
1307+ if (!(flags & EDIT_MSG ) && !(flags & VERIFY_MSG ) &&
1308+ !(flags & CREATE_ROOT_COMMIT )) {
12201309 struct object_id oid ;
12211310 struct strbuf sb = STRBUF_INIT ;
12221311
@@ -1369,6 +1458,22 @@ static int is_fixup(enum todo_command command)
13691458 return command == TODO_FIXUP || command == TODO_SQUASH ;
13701459}
13711460
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+
13721477static int update_squash_messages (enum todo_command command ,
13731478 struct commit * commit , struct replay_opts * opts )
13741479{
@@ -1523,7 +1628,14 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
15231628 return error (_ ("your index file is unmerged." ));
15241629 } else {
15251630 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 )
15271639 oidcpy (& head , the_hash_algo -> empty_tree );
15281640 if (index_differs_from (unborn ? EMPTY_TREE_SHA1_HEX : "HEAD" ,
15291641 NULL , 0 ))
@@ -2136,6 +2248,12 @@ static int read_populate_opts(struct replay_opts *opts)
21362248 read_strategy_opts (opts , & buf );
21372249 strbuf_release (& buf );
21382250
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+
21392257 return 0 ;
21402258 }
21412259
0 commit comments