@@ -48,6 +48,12 @@ static GIT_PATH_FUNC(git_path_head_file, "sequencer/head")
48
48
static GIT_PATH_FUNC (git_path_abort_safety_file , "sequencer/abort-safety" )
49
49
50
50
static 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" )
51
57
/*
52
58
* The file containing rebase commands, comments, and empty lines.
53
59
* 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)
645
651
else if (* message != '\'' )
646
652
strbuf_addch (& buf , * (message ++ ));
647
653
else
648
- strbuf_addf (& buf , "'\\\\ %c'" , * (message ++ ));
654
+ strbuf_addf (& buf , "'\\%c'" , * (message ++ ));
649
655
strbuf_addstr (& buf , "'\nGIT_AUTHOR_EMAIL='" );
650
656
while (* message && * message != '\n' && * message != '\r' )
651
657
if (skip_prefix (message , "> " , & message ))
652
658
break ;
653
659
else if (* message != '\'' )
654
660
strbuf_addch (& buf , * (message ++ ));
655
661
else
656
- strbuf_addf (& buf , "'\\\\ %c'" , * (message ++ ));
662
+ strbuf_addf (& buf , "'\\%c'" , * (message ++ ));
657
663
strbuf_addstr (& buf , "'\nGIT_AUTHOR_DATE='@" );
658
664
while (* message && * message != '\n' && * message != '\r' )
659
665
if (* message != '\'' )
660
666
strbuf_addch (& buf , * (message ++ ));
661
667
else
662
- strbuf_addf (& buf , "'\\\\ %c'" , * (message ++ ));
668
+ strbuf_addf (& buf , "'\\%c'" , * (message ++ ));
663
669
strbuf_addch (& buf , '\'' );
664
670
res = write_message (buf .buf , buf .len , rebase_path_author_script (), 1 );
665
671
strbuf_release (& buf );
666
672
return res ;
667
673
}
668
674
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
+
669
704
/*
670
705
* Read a list of environment variable assignments (such as the author-script
671
706
* file) into an environment block. Returns -1 on error, 0 otherwise.
672
707
*/
673
- static int read_env_script (struct argv_array * env )
708
+ static int read_env_script (struct replay_opts * opts , struct argv_array * env )
674
709
{
675
710
struct strbuf script = STRBUF_INIT ;
676
711
int i , count = 0 ;
677
- char * p , * p2 ;
712
+ const char * p2 ;
713
+ char * p ;
678
714
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 );
680
717
return -1 ;
718
+ }
719
+
720
+ if (!opts -> version && fix_bad_author_script (& script )) {
721
+ strbuf_release (& script );
722
+ return -1 ;
723
+ }
681
724
682
725
for (p = script .buf ; * p ; p ++ )
683
- if (skip_prefix (p , "'\\\\ ''" , ( const char * * ) & p2 ))
726
+ if (skip_prefix (p , "'\\''" , & p2 ))
684
727
strbuf_splice (& script , p - script .buf , p2 - p , "'" , 1 );
685
728
else if (* p == '\'' )
686
729
strbuf_splice (& script , p -- - script .buf , 1 , "" , 0 );
@@ -710,57 +753,64 @@ static char *get_author(const char *message)
710
753
}
711
754
712
755
/* 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 )
714
757
{
715
758
const char * keys [] = {
716
759
"GIT_AUTHOR_NAME=" , "GIT_AUTHOR_EMAIL=" , "GIT_AUTHOR_DATE="
717
760
};
761
+ struct strbuf buf = STRBUF_INIT ;
718
762
struct strbuf out = STRBUF_INIT ;
719
763
char * in , * eol ;
720
764
const char * val [3 ];
721
765
int i = 0 ;
722
766
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
+ }
725
776
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 ++ ) {
728
778
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 ]) ;
732
782
}
733
-
734
783
eol = strchrnul (in , '\n' );
735
784
* eol = '\0' ;
736
785
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 ()) ;
740
789
}
741
790
val [i ] = in ;
742
791
in = eol + 1 ;
743
792
}
744
793
745
794
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 ]) ;
749
798
}
750
799
751
800
/* validate date since fmt_ident() will die() on bad value */
752
801
if (parse_date (val [2 ], & out )){
753
- warning (_ ("invalid date format '%s' in '%s'" ),
802
+ error (_ ("invalid date format '%s' in '%s'" ),
754
803
val [2 ], rebase_path_author_script ());
755
804
strbuf_release (& out );
756
- return NULL ;
805
+ strbuf_release (& buf );
806
+ return -1 ;
757
807
}
758
808
759
809
strbuf_reset (& out );
760
810
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 ;
764
814
}
765
815
766
816
static const char staged_changes_advice [] =
@@ -820,12 +870,14 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
820
870
const char * value ;
821
871
822
872
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 ;
826
875
struct object_id root_commit , * cache_tree_oid ;
827
876
int res = 0 ;
828
877
878
+ if (is_rebase_i (opts ) && read_author_ident (opts , & author ))
879
+ return -1 ;
880
+
829
881
if (!defmsg )
830
882
BUG ("root commit without message" );
831
883
@@ -843,7 +895,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
843
895
opts -> gpg_sign );
844
896
845
897
strbuf_release (& msg );
846
- strbuf_release ( & script );
898
+ free ( author );
847
899
if (!res ) {
848
900
update_ref (NULL , "CHERRY_PICK_HEAD" , & root_commit , NULL ,
849
901
REF_NO_DEREF , UPDATE_REFS_MSG_ON_ERR );
@@ -855,7 +907,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
855
907
856
908
cmd .git_cmd = 1 ;
857
909
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 )) {
859
911
const char * gpg_opt = gpg_sign_opt_quoted (opts );
860
912
861
913
return error (_ (staged_changes_advice ),
@@ -2251,6 +2303,27 @@ static int read_populate_opts(struct replay_opts *opts)
2251
2303
if (is_rebase_i (opts )) {
2252
2304
struct strbuf buf = STRBUF_INIT ;
2253
2305
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
+
2254
2327
if (read_oneliner (& buf , rebase_path_gpg_sign_opt (), 1 )) {
2255
2328
if (!starts_with (buf .buf , "-S" ))
2256
2329
strbuf_reset (& buf );
@@ -3103,7 +3176,7 @@ static int do_merge(struct commit *commit, const char *arg, int arg_len,
3103
3176
/* Octopus merge */
3104
3177
struct child_process cmd = CHILD_PROCESS_INIT ;
3105
3178
3106
- if (read_env_script (& cmd .env_array )) {
3179
+ if (read_env_script (opts , & cmd .env_array )) {
3107
3180
const char * gpg_opt = gpg_sign_opt_quoted (opts );
3108
3181
3109
3182
ret = error (_ (staged_changes_advice ), gpg_opt , gpg_opt );
0 commit comments