@@ -48,6 +48,12 @@ static GIT_PATH_FUNC(git_path_head_file, "sequencer/head")
4848static GIT_PATH_FUNC (git_path_abort_safety_file , "sequencer/abort-safety" )
4949
5050static GIT_PATH_FUNC (rebase_path , "rebase-merge" )
51+ /*
52+ * This file indicates that an interactive rebase is in progress, if it contians
53+ * an integer then that is a version indicator for the contents of files in
54+ * .git/rebase-merge
55+ */
56+ static GIT_PATH_FUNC (rebase_path_interactive , "rebase-merge/interactive" )
5157/*
5258 * The file containing rebase commands, comments, and empty lines.
5359 * This file is created by "git rebase -i" then edited by the user. As
@@ -645,42 +651,79 @@ static int write_author_script(const char *message)
645651 else if (* message != '\'' )
646652 strbuf_addch (& buf , * (message ++ ));
647653 else
648- strbuf_addf (& buf , "'\\\\ %c'" , * (message ++ ));
654+ strbuf_addf (& buf , "'\\%c'" , * (message ++ ));
649655 strbuf_addstr (& buf , "'\nGIT_AUTHOR_EMAIL='" );
650656 while (* message && * message != '\n' && * message != '\r' )
651657 if (skip_prefix (message , "> " , & message ))
652658 break ;
653659 else if (* message != '\'' )
654660 strbuf_addch (& buf , * (message ++ ));
655661 else
656- strbuf_addf (& buf , "'\\\\ %c'" , * (message ++ ));
662+ strbuf_addf (& buf , "'\\%c'" , * (message ++ ));
657663 strbuf_addstr (& buf , "'\nGIT_AUTHOR_DATE='@" );
658664 while (* message && * message != '\n' && * message != '\r' )
659665 if (* message != '\'' )
660666 strbuf_addch (& buf , * (message ++ ));
661667 else
662- strbuf_addf (& buf , "'\\\\ %c'" , * (message ++ ));
668+ strbuf_addf (& buf , "'\\%c'" , * (message ++ ));
663669 strbuf_addch (& buf , '\'' );
664670 res = write_message (buf .buf , buf .len , rebase_path_author_script (), 1 );
665671 strbuf_release (& buf );
666672 return res ;
667673}
668674
675+ /*
676+ * write_author_script() used to fail to terminate the GIT_AUTHOR_DATE line with
677+ * a "'" and also escaped "'" incorrectly as "'\\\\''" rather than "'\\''". Fix
678+ * these problems before dequoting in when git was upgraded while rebase was
679+ * stopped.
680+ */
681+ static int fix_bad_author_script (struct strbuf * script )
682+ {
683+ const char * next ;
684+ size_t off = 0 ;
685+
686+ while ((next = strstr (script -> buf + off , "'\\\\''" ))) {
687+ off = next - script -> buf + 4 ;
688+ strbuf_splice (script , next - script -> buf , 5 ,"'\\''" , 4 );
689+ }
690+
691+ if ((next = strstr (script -> buf , "\nGIT_AUTHOR_DATE='" )) &&
692+ (next = strchr (++ next , '\n' )) &&
693+ ++ next - script -> buf == script -> len ) {
694+ if (script -> buf [script -> len - 2 ] != '\'' )
695+ strbuf_insert (script , script -> len - 1 , "'" , 1 );
696+ } else {
697+ return error (_ ("unable to parse '%s'" ),
698+ rebase_path_author_script ());
699+ }
700+
701+ return 0 ;
702+ }
703+
669704/*
670705 * Read a list of environment variable assignments (such as the author-script
671706 * file) into an environment block. Returns -1 on error, 0 otherwise.
672707 */
673- static int read_env_script (struct argv_array * env )
708+ static int read_env_script (struct replay_opts * opts , struct argv_array * env )
674709{
675710 struct strbuf script = STRBUF_INIT ;
676711 int i , count = 0 ;
677- char * p , * p2 ;
712+ const char * p2 ;
713+ char * p ;
678714
679- if (strbuf_read_file (& script , rebase_path_author_script (), 256 ) <= 0 )
715+ if (strbuf_read_file (& script , rebase_path_author_script (), 256 ) <= 0 ) {
716+ strbuf_release (& script );
680717 return -1 ;
718+ }
719+
720+ if (!opts -> version && fix_bad_author_script (& script )) {
721+ strbuf_release (& script );
722+ return -1 ;
723+ }
681724
682725 for (p = script .buf ; * p ; p ++ )
683- if (skip_prefix (p , "'\\\\ ''" , ( const char * * ) & p2 ))
726+ if (skip_prefix (p , "'\\''" , & p2 ))
684727 strbuf_splice (& script , p - script .buf , p2 - p , "'" , 1 );
685728 else if (* p == '\'' )
686729 strbuf_splice (& script , p -- - script .buf , 1 , "" , 0 );
@@ -710,57 +753,64 @@ static char *get_author(const char *message)
710753}
711754
712755/* Read author-script and return an ident line (author <email> timestamp) */
713- static const char * read_author_ident (struct strbuf * buf )
756+ static int read_author_ident (struct replay_opts * opts , char * * author )
714757{
715758 const char * keys [] = {
716759 "GIT_AUTHOR_NAME=" , "GIT_AUTHOR_EMAIL=" , "GIT_AUTHOR_DATE="
717760 };
761+ struct strbuf buf = STRBUF_INIT ;
718762 struct strbuf out = STRBUF_INIT ;
719763 char * in , * eol ;
720764 const char * val [3 ];
721765 int i = 0 ;
722766
723- if (strbuf_read_file (buf , rebase_path_author_script (), 256 ) <= 0 )
724- return NULL ;
767+ if (strbuf_read_file (& buf , rebase_path_author_script (), 256 ) <= 0 ) {
768+ strbuf_release (& buf );
769+ return -1 ;
770+ }
771+
772+ if (!opts -> version && fix_bad_author_script (& buf )) {
773+ strbuf_release (& buf );
774+ return -1 ;
775+ }
725776
726- /* dequote values and construct ident line in-place */
727- for (in = buf -> buf ; i < 3 && in - buf -> buf < buf -> len ; i ++ ) {
777+ for (in = buf .buf ; i < 3 && in - buf .buf < buf .len ; i ++ ) {
728778 if (!skip_prefix (in , keys [i ], (const char * * )& in )) {
729- warning ( _ ( "could not parse '%s' (looking for '%s'" ),
730- rebase_path_author_script (), keys [ i ]);
731- return NULL ;
779+ strbuf_release ( & buf );
780+ return error ( _ ( "could not parse '%s' (looking for '%s')" ),
781+ rebase_path_author_script (), keys [ i ]) ;
732782 }
733-
734783 eol = strchrnul (in , '\n' );
735784 * eol = '\0' ;
736785 if (!sq_dequote (in )) {
737- warning ( _ ( "bad quoting on %s value in '%s'" ),
738- keys [ i ], rebase_path_author_script ());
739- return NULL ;
786+ strbuf_release ( & buf );
787+ return error ( _ ( "bad quoting on %s value in '%s'" ),
788+ keys [ i ], rebase_path_author_script ()) ;
740789 }
741790 val [i ] = in ;
742791 in = eol + 1 ;
743792 }
744793
745794 if (i < 3 ) {
746- warning ( _ ( "could not parse '%s' (looking for '%s')" ),
747- rebase_path_author_script (), keys [ i ]);
748- return NULL ;
795+ strbuf_release ( & buf );
796+ return error ( _ ( "could not parse '%s' (looking for '%s')" ),
797+ rebase_path_author_script (), keys [ i ]) ;
749798 }
750799
751800 /* validate date since fmt_ident() will die() on bad value */
752801 if (parse_date (val [2 ], & out )){
753- warning (_ ("invalid date format '%s' in '%s'" ),
802+ error (_ ("invalid date format '%s' in '%s'" ),
754803 val [2 ], rebase_path_author_script ());
755804 strbuf_release (& out );
756- return NULL ;
805+ strbuf_release (& buf );
806+ return -1 ;
757807 }
758808
759809 strbuf_reset (& out );
760810 strbuf_addstr (& out , fmt_ident (val [0 ], val [1 ], val [2 ], 0 ));
761- strbuf_swap ( buf , & out );
762- strbuf_release (& out );
763- return buf -> buf ;
811+ * author = strbuf_detach ( & out , NULL );
812+ strbuf_release (& buf );
813+ return 0 ;
764814}
765815
766816static const char staged_changes_advice [] =
@@ -820,12 +870,14 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
820870 const char * value ;
821871
822872 if ((flags & CREATE_ROOT_COMMIT ) && !(flags & AMEND_MSG )) {
823- struct strbuf msg = STRBUF_INIT , script = STRBUF_INIT ;
824- const char * author = is_rebase_i (opts ) ?
825- read_author_ident (& script ) : NULL ;
873+ struct strbuf msg = STRBUF_INIT ;
874+ char * author = NULL ;
826875 struct object_id root_commit , * cache_tree_oid ;
827876 int res = 0 ;
828877
878+ if (is_rebase_i (opts ) && read_author_ident (opts , & author ))
879+ return -1 ;
880+
829881 if (!defmsg )
830882 BUG ("root commit without message" );
831883
@@ -843,7 +895,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
843895 opts -> gpg_sign );
844896
845897 strbuf_release (& msg );
846- strbuf_release ( & script );
898+ free ( author );
847899 if (!res ) {
848900 update_ref (NULL , "CHERRY_PICK_HEAD" , & root_commit , NULL ,
849901 REF_NO_DEREF , UPDATE_REFS_MSG_ON_ERR );
@@ -855,7 +907,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
855907
856908 cmd .git_cmd = 1 ;
857909
858- if (is_rebase_i (opts ) && read_env_script (& cmd .env_array )) {
910+ if (is_rebase_i (opts ) && read_env_script (opts , & cmd .env_array )) {
859911 const char * gpg_opt = gpg_sign_opt_quoted (opts );
860912
861913 return error (_ (staged_changes_advice ),
@@ -2251,6 +2303,27 @@ static int read_populate_opts(struct replay_opts *opts)
22512303 if (is_rebase_i (opts )) {
22522304 struct strbuf buf = STRBUF_INIT ;
22532305
2306+ if (read_oneliner (& buf , rebase_path_interactive (), 0 )) {
2307+ if (buf .len ) {
2308+ char * end ;
2309+ long version = strtol (buf .buf , & end , 10 );
2310+ if (version < 1 || version > INT_MAX ||
2311+ * end != '\0' ) {
2312+ strbuf_release (& buf );
2313+ return error (_ ("unable to parse '%s'" ),
2314+ rebase_path_interactive ());
2315+ }
2316+ opts -> version = (int )version ;
2317+ } else {
2318+ opts -> version = 0 ;
2319+ }
2320+ strbuf_reset (& buf );
2321+ } else {
2322+ strbuf_release (& buf );
2323+ return error (_ ("unable to read '%s'" ),
2324+ rebase_path_interactive ());
2325+ }
2326+
22542327 if (read_oneliner (& buf , rebase_path_gpg_sign_opt (), 1 )) {
22552328 if (!starts_with (buf .buf , "-S" ))
22562329 strbuf_reset (& buf );
@@ -3103,7 +3176,7 @@ static int do_merge(struct commit *commit, const char *arg, int arg_len,
31033176 /* Octopus merge */
31043177 struct child_process cmd = CHILD_PROCESS_INIT ;
31053178
3106- if (read_env_script (& cmd .env_array )) {
3179+ if (read_env_script (opts , & cmd .env_array )) {
31073180 const char * gpg_opt = gpg_sign_opt_quoted (opts );
31083181
31093182 ret = error (_ (staged_changes_advice ), gpg_opt , gpg_opt );
0 commit comments