@@ -46,6 +46,35 @@ static GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo")
4646 * actions.
4747 */
4848static GIT_PATH_FUNC (rebase_path_done , "rebase-merge/done" )
49+ /*
50+ * The commit message that is planned to be used for any changes that
51+ * need to be committed following a user interaction.
52+ */
53+ static GIT_PATH_FUNC (rebase_path_message , "rebase-merge/message" )
54+ /*
55+ * The file into which is accumulated the suggested commit message for
56+ * squash/fixup commands. When the first of a series of squash/fixups
57+ * is seen, the file is created and the commit message from the
58+ * previous commit and from the first squash/fixup commit are written
59+ * to it. The commit message for each subsequent squash/fixup commit
60+ * is appended to the file as it is processed.
61+ *
62+ * The first line of the file is of the form
63+ * # This is a combination of $count commits.
64+ * where $count is the number of commits whose messages have been
65+ * written to the file so far (including the initial "pick" commit).
66+ * Each time that a commit message is processed, this line is read and
67+ * updated. It is deleted just before the combined commit is made.
68+ */
69+ static GIT_PATH_FUNC (rebase_path_squash_msg , "rebase-merge/message-squash" )
70+ /*
71+ * If the current series of squash/fixups has not yet included a squash
72+ * command, then this file exists and holds the commit message of the
73+ * original "pick" commit. (If the series ends without a "squash"
74+ * command, then this can be used as the commit message of the combined
75+ * commit without opening the editor.)
76+ */
77+ static GIT_PATH_FUNC (rebase_path_fixup_msg , "rebase-merge/message-fixup" )
4978/*
5079 * A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
5180 * GIT_AUTHOR_DATE that will be used for the commit that is currently
@@ -641,6 +670,8 @@ enum todo_command {
641670 TODO_PICK = 0 ,
642671 TODO_REVERT ,
643672 TODO_EDIT ,
673+ TODO_FIXUP ,
674+ TODO_SQUASH ,
644675 /* commands that do something else than handling a single commit */
645676 TODO_EXEC ,
646677 /* commands that do nothing but are counted for reporting progress */
@@ -651,6 +682,8 @@ static const char *todo_command_strings[] = {
651682 "pick" ,
652683 "revert" ,
653684 "edit" ,
685+ "fixup" ,
686+ "squash" ,
654687 "exec" ,
655688 "noop"
656689};
@@ -667,15 +700,114 @@ static int is_noop(const enum todo_command command)
667700 return TODO_NOOP <= (size_t )command ;
668701}
669702
703+ static int is_fixup (enum todo_command command )
704+ {
705+ return command == TODO_FIXUP || command == TODO_SQUASH ;
706+ }
707+
708+ static int update_squash_messages (enum todo_command command ,
709+ struct commit * commit , struct replay_opts * opts )
710+ {
711+ struct strbuf buf = STRBUF_INIT ;
712+ int count , res ;
713+ const char * message , * body ;
714+
715+ if (file_exists (rebase_path_squash_msg ())) {
716+ struct strbuf header = STRBUF_INIT ;
717+ char * eol , * p ;
718+
719+ if (strbuf_read_file (& buf , rebase_path_squash_msg (), 2048 ) <= 0 )
720+ return error (_ ("could not read '%s'" ),
721+ rebase_path_squash_msg ());
722+
723+ p = buf .buf + 1 ;
724+ eol = strchrnul (buf .buf , '\n' );
725+ if (buf .buf [0 ] != comment_line_char ||
726+ (p += strcspn (p , "0123456789\n" )) == eol )
727+ return error (_ ("unexpected 1st line of squash message:"
728+ "\n\n\t%.*s" ),
729+ (int )(eol - buf .buf ), buf .buf );
730+ count = strtol (p , NULL , 10 );
731+
732+ if (count < 1 )
733+ return error (_ ("invalid 1st line of squash message:\n"
734+ "\n\t%.*s" ),
735+ (int )(eol - buf .buf ), buf .buf );
736+
737+ strbuf_addf (& header , "%c " , comment_line_char );
738+ strbuf_addf (& header ,
739+ _ ("This is a combination of %d commits." ), ++ count );
740+ strbuf_splice (& buf , 0 , eol - buf .buf , header .buf , header .len );
741+ strbuf_release (& header );
742+ } else {
743+ unsigned char head [20 ];
744+ struct commit * head_commit ;
745+ const char * head_message , * body ;
746+
747+ if (get_sha1 ("HEAD" , head ))
748+ return error (_ ("need a HEAD to fixup" ));
749+ if (!(head_commit = lookup_commit_reference (head )))
750+ return error (_ ("could not read HEAD" ));
751+ if (!(head_message = get_commit_buffer (head_commit , NULL )))
752+ return error (_ ("could not read HEAD's commit message" ));
753+
754+ find_commit_subject (head_message , & body );
755+ if (write_message (body , strlen (body ),
756+ rebase_path_fixup_msg (), 0 )) {
757+ unuse_commit_buffer (head_commit , head_message );
758+ return error (_ ("cannot write '%s'" ),
759+ rebase_path_fixup_msg ());
760+ }
761+
762+ count = 2 ;
763+ strbuf_addf (& buf , "%c " , comment_line_char );
764+ strbuf_addf (& buf , _ ("This is a combination of %d commits." ),
765+ count );
766+ strbuf_addf (& buf , "\n%c " , comment_line_char );
767+ strbuf_addstr (& buf , _ ("This is the 1st commit message:" ));
768+ strbuf_addstr (& buf , "\n\n" );
769+ strbuf_addstr (& buf , body );
770+
771+ unuse_commit_buffer (head_commit , head_message );
772+ }
773+
774+ if (!(message = get_commit_buffer (commit , NULL )))
775+ return error (_ ("could not read commit message of %s" ),
776+ oid_to_hex (& commit -> object .oid ));
777+ find_commit_subject (message , & body );
778+
779+ if (command == TODO_SQUASH ) {
780+ unlink (rebase_path_fixup_msg ());
781+ strbuf_addf (& buf , "\n%c " , comment_line_char );
782+ strbuf_addf (& buf , _ ("This is the commit message #%d:" ), count );
783+ strbuf_addstr (& buf , "\n\n" );
784+ strbuf_addstr (& buf , body );
785+ } else if (command == TODO_FIXUP ) {
786+ strbuf_addf (& buf , "\n%c " , comment_line_char );
787+ strbuf_addf (& buf , _ ("The commit message #%d will be skipped:" ),
788+ count );
789+ strbuf_addstr (& buf , "\n\n" );
790+ strbuf_add_commented_lines (& buf , body , strlen (body ));
791+ } else
792+ return error (_ ("unknown command: %d" ), command );
793+ unuse_commit_buffer (commit , message );
794+
795+ res = write_message (buf .buf , buf .len , rebase_path_squash_msg (), 0 );
796+ strbuf_release (& buf );
797+ return res ;
798+ }
799+
670800static int do_pick_commit (enum todo_command command , struct commit * commit ,
671- struct replay_opts * opts )
801+ struct replay_opts * opts , int final_fixup )
672802{
803+ int edit = opts -> edit , cleanup_commit_message = 0 ;
804+ const char * msg_file = edit ? NULL : git_path_merge_msg ();
673805 unsigned char head [20 ];
674806 struct commit * base , * next , * parent ;
675807 const char * base_label , * next_label ;
676808 struct commit_message msg = { NULL , NULL , NULL , NULL };
677809 struct strbuf msgbuf = STRBUF_INIT ;
678- int res , unborn = 0 , allow ;
810+ int res , unborn = 0 , amend = 0 , allow ;
679811
680812 if (opts -> no_commit ) {
681813 /*
@@ -720,7 +852,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
720852 else
721853 parent = commit -> parents -> item ;
722854
723- if (opts -> allow_ff &&
855+ if (opts -> allow_ff && ! is_fixup ( command ) &&
724856 ((parent && !hashcmp (parent -> object .oid .hash , head )) ||
725857 (!parent && unborn )))
726858 return fast_forward_to (commit -> object .oid .hash , head , unborn , opts );
@@ -779,6 +911,27 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
779911 }
780912 }
781913
914+ if (is_fixup (command )) {
915+ if (update_squash_messages (command , commit , opts ))
916+ return -1 ;
917+ amend = 1 ;
918+ if (!final_fixup )
919+ msg_file = rebase_path_squash_msg ();
920+ else if (file_exists (rebase_path_fixup_msg ())) {
921+ cleanup_commit_message = 1 ;
922+ msg_file = rebase_path_fixup_msg ();
923+ } else {
924+ const char * dest = git_path ("SQUASH_MSG" );
925+ unlink (dest );
926+ if (copy_file (dest , rebase_path_squash_msg (), 0666 ))
927+ return error (_ ("could not rename '%s' to '%s'" ),
928+ rebase_path_squash_msg (), dest );
929+ unlink (git_path ("MERGE_MSG" ));
930+ msg_file = dest ;
931+ edit = 1 ;
932+ }
933+ }
934+
782935 if (!opts -> strategy || !strcmp (opts -> strategy , "recursive" ) || command == TODO_REVERT ) {
783936 res = do_recursive_merge (base , next , base_label , next_label ,
784937 head , & msgbuf , opts );
@@ -834,8 +987,13 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
834987 goto leave ;
835988 }
836989 if (!opts -> no_commit )
837- res = run_git_commit (opts -> edit ? NULL : git_path_merge_msg (),
838- opts , allow , opts -> edit , 0 , 0 );
990+ res = run_git_commit (msg_file , opts , allow , edit , amend ,
991+ cleanup_commit_message );
992+
993+ if (!res && final_fixup ) {
994+ unlink (rebase_path_fixup_msg ());
995+ unlink (rebase_path_squash_msg ());
996+ }
839997
840998leave :
841999 free_message (commit , & msg );
@@ -976,7 +1134,7 @@ static int parse_insn_buffer(char *buf, struct todo_list *todo_list)
9761134{
9771135 struct todo_item * item ;
9781136 char * p = buf , * next_p ;
979- int i , res = 0 ;
1137+ int i , res = 0 , fixup_okay = file_exists ( rebase_path_done ()) ;
9801138
9811139 for (i = 1 ; * p ; i ++ , p = next_p ) {
9821140 char * eol = strchrnul (p , '\n' );
@@ -991,8 +1149,16 @@ static int parse_insn_buffer(char *buf, struct todo_list *todo_list)
9911149 if (parse_insn_line (item , p , eol )) {
9921150 res = error (_ ("invalid line %d: %.*s" ),
9931151 i , (int )(eol - p ), p );
994- item -> command = -1 ;
1152+ item -> command = TODO_NOOP ;
9951153 }
1154+
1155+ if (fixup_okay )
1156+ ; /* do nothing */
1157+ else if (is_fixup (item -> command ))
1158+ return error (_ ("cannot '%s' without a previous commit" ),
1159+ command_to_string (item -> command ));
1160+ else if (!is_noop (item -> command ))
1161+ fixup_okay = 1 ;
9961162 }
9971163 if (!todo_list -> nr )
9981164 return error (_ ("no commits parsed." ));
@@ -1435,6 +1601,20 @@ static int error_with_patch(struct commit *commit,
14351601 return exit_code ;
14361602}
14371603
1604+ static int error_failed_squash (struct commit * commit ,
1605+ struct replay_opts * opts , int subject_len , const char * subject )
1606+ {
1607+ if (rename (rebase_path_squash_msg (), rebase_path_message ()))
1608+ return error (_ ("could not rename '%s' to '%s'" ),
1609+ rebase_path_squash_msg (), rebase_path_message ());
1610+ unlink (rebase_path_fixup_msg ());
1611+ unlink (git_path ("MERGE_MSG" ));
1612+ if (copy_file (git_path ("MERGE_MSG" ), rebase_path_message (), 0666 ))
1613+ return error (_ ("could not copy '%s' to '%s'" ),
1614+ rebase_path_message (), git_path ("MERGE_MSG" ));
1615+ return error_with_patch (commit , subject , subject_len , opts , 1 , 0 );
1616+ }
1617+
14381618static int do_exec (const char * command_line )
14391619{
14401620 const char * child_argv [] = { NULL , NULL };
@@ -1475,6 +1655,21 @@ static int do_exec(const char *command_line)
14751655 return status ;
14761656}
14771657
1658+ static int is_final_fixup (struct todo_list * todo_list )
1659+ {
1660+ int i = todo_list -> current ;
1661+
1662+ if (!is_fixup (todo_list -> items [i ].command ))
1663+ return 0 ;
1664+
1665+ while (++ i < todo_list -> nr )
1666+ if (is_fixup (todo_list -> items [i ].command ))
1667+ return 0 ;
1668+ else if (!is_noop (todo_list -> items [i ].command ))
1669+ break ;
1670+ return 1 ;
1671+ }
1672+
14781673static int pick_commits (struct todo_list * todo_list , struct replay_opts * opts )
14791674{
14801675 int res = 0 ;
@@ -1490,9 +1685,15 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
14901685 struct todo_item * item = todo_list -> items + todo_list -> current ;
14911686 if (save_todo (todo_list , opts ))
14921687 return -1 ;
1493- if (item -> command <= TODO_EDIT ) {
1688+ if (is_rebase_i (opts )) {
1689+ unlink (rebase_path_message ());
1690+ unlink (rebase_path_author_script ());
1691+ unlink (rebase_path_stopped_sha ());
1692+ unlink (rebase_path_amend ());
1693+ }
1694+ if (item -> command <= TODO_SQUASH ) {
14941695 res = do_pick_commit (item -> command , item -> commit ,
1495- opts );
1696+ opts , is_final_fixup ( todo_list ) );
14961697 if (item -> command == TODO_EDIT ) {
14971698 struct commit * commit = item -> commit ;
14981699 if (!res )
@@ -1503,6 +1704,12 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
15031704 item -> arg , item -> arg_len , opts , res ,
15041705 !res );
15051706 }
1707+ if (res && is_fixup (item -> command )) {
1708+ if (res == 1 )
1709+ intend_to_amend ();
1710+ return error_failed_squash (item -> commit , opts ,
1711+ item -> arg_len , item -> arg );
1712+ }
15061713 } else if (item -> command == TODO_EXEC ) {
15071714 char * end_of_arg = (char * )(item -> arg + item -> arg_len );
15081715 int saved = * end_of_arg ;
@@ -1601,7 +1808,7 @@ static int single_pick(struct commit *cmit, struct replay_opts *opts)
16011808{
16021809 setenv (GIT_REFLOG_ACTION , action_name (opts ), 0 );
16031810 return do_pick_commit (opts -> action == REPLAY_PICK ?
1604- TODO_PICK : TODO_REVERT , cmit , opts );
1811+ TODO_PICK : TODO_REVERT , cmit , opts , 0 );
16051812}
16061813
16071814int sequencer_pick_revisions (struct replay_opts * opts )
0 commit comments