@@ -430,6 +430,12 @@ static int read_bisect_refs(void)
430
430
431
431
static GIT_PATH_FUNC (git_path_bisect_names , "BISECT_NAMES ")
432
432
static GIT_PATH_FUNC (git_path_bisect_expected_rev , "BISECT_EXPECTED_REV ")
433
+ static GIT_PATH_FUNC (git_path_bisect_ancestors_ok , "BISECT_ANCESTORS_OK ")
434
+ static GIT_PATH_FUNC (git_path_bisect_run , "BISECT_RUN ")
435
+ static GIT_PATH_FUNC (git_path_bisect_start , "BISECT_START ")
436
+ static GIT_PATH_FUNC (git_path_bisect_log , "BISECT_LOG ")
437
+ static GIT_PATH_FUNC (git_path_bisect_terms , "BISECT_TERMS ")
438
+ static GIT_PATH_FUNC (git_path_head_name , "head - name ")
433
439
434
440
static void read_bisect_paths (struct argv_array * array )
435
441
{
@@ -612,6 +618,12 @@ static void bisect_rev_setup(struct rev_info *revs, const char *prefix,
612
618
struct argv_array rev_argv = ARGV_ARRAY_INIT ;
613
619
int i ;
614
620
621
+ /*
622
+ * Since the code is slowly being converted to C, there might be
623
+ * instances where the revisions were initialized before. Thus
624
+ * we first need to reset it.
625
+ */
626
+ reset_revision_walk ();
615
627
init_revisions (revs , prefix );
616
628
revs -> abbrev = 0 ;
617
629
revs -> commit_format = CMIT_FMT_UNSPECIFIED ;
@@ -632,17 +644,22 @@ static void bisect_rev_setup(struct rev_info *revs, const char *prefix,
632
644
633
645
static void bisect_common (struct rev_info * revs )
634
646
{
647
+ /*
648
+ * We don't want to clean the bisection state
649
+ * as we need to get back to where we started
650
+ * by using `git bisect reset`.
651
+ */
635
652
if (prepare_revision_walk (revs ))
636
653
die ("revision walk setup failed" );
637
654
if (revs -> tree_objects )
638
655
mark_edges_uninteresting (revs , NULL );
639
656
}
640
657
641
- static void exit_if_skipped_commits (struct commit_list * tried ,
658
+ static int exit_if_skipped_commits (struct commit_list * tried ,
642
659
const struct object_id * bad )
643
660
{
644
661
if (!tried )
645
- return ;
662
+ return 0 ;
646
663
647
664
printf ("There are only 'skip'ped commits left to test.\n"
648
665
"The first %s commit could be any of:\n" , term_bad );
@@ -653,7 +670,13 @@ static void exit_if_skipped_commits(struct commit_list *tried,
653
670
if (bad )
654
671
printf ("%s\n" , oid_to_hex (bad ));
655
672
printf (_ ("We cannot bisect more!\n" ));
656
- exit (2 );
673
+
674
+ /*
675
+ * We don't want to clean the bisection state
676
+ * as we need to get back to where we started
677
+ * by using `git bisect reset`.
678
+ */
679
+ return 2 ;
657
680
}
658
681
659
682
static int is_expected_rev (const struct object_id * oid )
@@ -694,7 +717,7 @@ static int bisect_checkout(const unsigned char *bisect_rev, int no_checkout)
694
717
int res ;
695
718
res = run_command_v_opt (argv_checkout , RUN_GIT_CMD );
696
719
if (res )
697
- exit ( res ) ;
720
+ return res ;
698
721
}
699
722
700
723
argv_show_branch [1 ] = bisect_rev_hex ;
@@ -723,7 +746,7 @@ static struct commit **get_bad_and_good_commits(int *rev_nr)
723
746
return rev ;
724
747
}
725
748
726
- static void handle_bad_merge_base (void )
749
+ static int handle_bad_merge_base (void )
727
750
{
728
751
if (is_expected_rev (current_bad_oid )) {
729
752
char * bad_hex = oid_to_hex (current_bad_oid );
@@ -744,17 +767,23 @@ static void handle_bad_merge_base(void)
744
767
"between %s and [%s].\n" ),
745
768
bad_hex , term_bad , term_good , bad_hex , good_hex );
746
769
}
747
- exit (3 );
770
+ /*
771
+ * We don't want to clean the bisection state
772
+ * as we need to get back to where we started
773
+ * by using `git bisect reset`.
774
+ */
775
+ return 3 ;
748
776
}
749
777
750
778
fprintf (stderr , _ ("Some %s revs are not ancestors of the %s rev.\n"
751
779
"git bisect cannot work properly in this case.\n"
752
780
"Maybe you mistook %s and %s revs?\n" ),
753
781
term_good , term_bad , term_good , term_bad );
754
- exit (1 );
782
+ bisect_clean_state ();
783
+ return 1 ;
755
784
}
756
785
757
- static void handle_skipped_merge_base (const unsigned char * mb )
786
+ static int handle_skipped_merge_base (const unsigned char * mb )
758
787
{
759
788
char * mb_hex = sha1_to_hex (mb );
760
789
char * bad_hex = oid_to_hex (current_bad_oid );
@@ -767,41 +796,53 @@ static void handle_skipped_merge_base(const unsigned char *mb)
767
796
"We continue anyway." ),
768
797
bad_hex , good_hex , term_bad , mb_hex , bad_hex );
769
798
free (good_hex );
799
+ return 0 ;
770
800
}
771
801
772
802
/*
773
803
* "check_merge_bases" checks that merge bases are not "bad" (or "new").
774
804
*
775
805
* - If one is "bad" (or "new"), it means the user assumed something wrong
776
- * and we must exit with a non 0 error code.
806
+ * and we must return error with a non 0 error code.
777
807
* - If one is "good" (or "old"), that's good, we have nothing to do.
778
808
* - If one is "skipped", we can't know but we should warn.
779
809
* - If we don't know, we should check it out and ask the user to test.
780
810
*/
781
- static void check_merge_bases (int no_checkout )
811
+ static int check_merge_bases (int no_checkout )
782
812
{
783
813
struct commit_list * result ;
784
- int rev_nr ;
814
+ int rev_nr , res = 0 ;
785
815
struct commit * * rev = get_bad_and_good_commits (& rev_nr );
786
816
787
817
result = get_merge_bases_many (rev [0 ], rev_nr - 1 , rev + 1 );
788
818
789
819
for (; result ; result = result -> next ) {
790
820
const unsigned char * mb = result -> item -> object .oid .hash ;
791
821
if (!hashcmp (mb , current_bad_oid -> hash )) {
792
- handle_bad_merge_base ();
822
+ res = handle_bad_merge_base ();
823
+ break ;
793
824
} else if (0 <= sha1_array_lookup (& good_revs , mb )) {
794
825
continue ;
795
826
} else if (0 <= sha1_array_lookup (& skipped_revs , mb )) {
796
- handle_skipped_merge_base (mb );
827
+ res = handle_skipped_merge_base (mb );
828
+ break ;
797
829
} else {
798
830
printf (_ ("Bisecting: a merge base must be tested\n" ));
799
- exit (bisect_checkout (mb , no_checkout ));
831
+ res = bisect_checkout (mb , no_checkout );
832
+ /*
833
+ * We don't want to clean the bisection state
834
+ * as we need to get back to where we started
835
+ * by using `git bisect reset`.
836
+ */
837
+ if (!res )
838
+ exit (0 );
839
+ break ;
800
840
}
801
841
}
802
842
803
843
free (rev );
804
844
free_commit_list (result );
845
+ return res ;
805
846
}
806
847
807
848
static int check_ancestors (const char * prefix )
@@ -837,16 +878,21 @@ static int check_ancestors(const char *prefix)
837
878
*
838
879
* If that's not the case, we need to check the merge bases.
839
880
* If a merge base must be tested by the user, its source code will be
840
- * checked out to be tested by the user and we will exit .
881
+ * checked out to be tested by the user and we will return .
841
882
*/
842
- static void check_good_are_ancestors_of_bad (const char * prefix , int no_checkout )
883
+ static int check_good_are_ancestors_of_bad (const char * prefix , int no_checkout )
843
884
{
844
885
char * filename = git_pathdup ("BISECT_ANCESTORS_OK" );
845
886
struct stat st ;
846
- int fd ;
887
+ int fd , res = 0 ;
847
888
889
+ /*
890
+ * We don't want to clean the bisection state
891
+ * as we need to get back to where we started
892
+ * by using `git bisect reset`.
893
+ */
848
894
if (!current_bad_oid )
849
- die (_ ("a %s revision is needed" ), term_bad );
895
+ error (_ ("a %s revision is needed" ), term_bad );
850
896
851
897
/* Check if file BISECT_ANCESTORS_OK exists. */
852
898
if (!stat (filename , & st ) && S_ISREG (st .st_mode ))
@@ -858,7 +904,10 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
858
904
859
905
/* Check if all good revs are ancestor of the bad rev. */
860
906
if (check_ancestors (prefix ))
861
- check_merge_bases (no_checkout );
907
+ res = check_merge_bases (no_checkout );
908
+
909
+ if (res )
910
+ goto done ;
862
911
863
912
/* Create file BISECT_ANCESTORS_OK. */
864
913
fd = open (filename , O_CREAT | O_TRUNC | O_WRONLY , 0600 );
@@ -867,8 +916,11 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)
867
916
filename );
868
917
else
869
918
close (fd );
919
+
920
+ goto done ;
870
921
done :
871
922
free (filename );
923
+ return res ;
872
924
}
873
925
874
926
/*
@@ -927,7 +979,7 @@ void read_bisect_terms(const char **read_bad, const char **read_good)
927
979
}
928
980
929
981
/*
930
- * We use the convention that exiting with an exit code 10 means that
982
+ * We use the convention to return with an return code 10 means that
931
983
* the bisection process finished successfully.
932
984
* In this case the calling shell script should exit 0.
933
985
*
@@ -938,15 +990,17 @@ int bisect_next_all(const char *prefix, int no_checkout)
938
990
{
939
991
struct rev_info revs ;
940
992
struct commit_list * tried ;
941
- int reaches = 0 , all = 0 , nr , steps ;
993
+ int reaches = 0 , all = 0 , nr , steps , res ;
942
994
const unsigned char * bisect_rev ;
943
995
char steps_msg [32 ];
944
996
945
997
read_bisect_terms (& term_bad , & term_good );
946
998
if (read_bisect_refs ())
947
999
die (_ ("reading bisect refs failed" ));
948
1000
949
- check_good_are_ancestors_of_bad (prefix , no_checkout );
1001
+ res = check_good_are_ancestors_of_bad (prefix , no_checkout );
1002
+ if (res )
1003
+ return res ;
950
1004
951
1005
bisect_rev_setup (& revs , prefix , "%s" , "^%s" , 1 );
952
1006
revs .limited = 1 ;
@@ -958,34 +1012,52 @@ int bisect_next_all(const char *prefix, int no_checkout)
958
1012
revs .commits = managed_skipped (revs .commits , & tried );
959
1013
960
1014
if (!revs .commits ) {
1015
+ int res ;
961
1016
/*
962
- * We should exit here only if the "bad"
1017
+ * We should return error here only if the "bad"
963
1018
* commit is also a "skip" commit.
964
1019
*/
965
- exit_if_skipped_commits (tried , NULL );
1020
+ res = exit_if_skipped_commits (tried , NULL );
1021
+ if (res )
1022
+ return res ;
966
1023
967
1024
printf (_ ("%s was both %s and %s\n" ),
968
1025
oid_to_hex (current_bad_oid ),
969
1026
term_good ,
970
1027
term_bad );
971
- exit (1 );
1028
+
1029
+ /*
1030
+ * We don't want to clean the bisection state
1031
+ * as we need to get back to where we started
1032
+ * by using `git bisect reset`.
1033
+ */
1034
+ return 1 ;
972
1035
}
973
1036
974
1037
if (!all ) {
975
1038
fprintf (stderr , _ ("No testable commit found.\n"
976
1039
"Maybe you started with bad path parameters?\n" ));
977
- exit (4 );
1040
+
1041
+ /*
1042
+ * We don't want to clean the bisection state
1043
+ * as we need to get back to where we started
1044
+ * by using `git bisect reset`.
1045
+ */
1046
+ return 4 ;
978
1047
}
979
1048
980
1049
bisect_rev = revs .commits -> item -> object .oid .hash ;
981
1050
982
1051
if (!hashcmp (bisect_rev , current_bad_oid -> hash )) {
983
- exit_if_skipped_commits (tried , current_bad_oid );
1052
+ res = exit_if_skipped_commits (tried , current_bad_oid );
1053
+ if (res )
1054
+ return res ;
1055
+
984
1056
printf ("%s is the first %s commit\n" , sha1_to_hex (bisect_rev ),
985
1057
term_bad );
986
1058
show_diff_tree (prefix , revs .commits -> item );
987
1059
/* This means the bisection process succeeded. */
988
- exit ( 10 ) ;
1060
+ return 10 ;
989
1061
}
990
1062
991
1063
nr = all - reaches - 1 ;
@@ -999,7 +1071,11 @@ int bisect_next_all(const char *prefix, int no_checkout)
999
1071
"Bisecting: %d revisions left to test after this %s\n" ,
1000
1072
nr ), nr , steps_msg );
1001
1073
1002
- return bisect_checkout (bisect_rev , no_checkout );
1074
+ res = bisect_checkout (bisect_rev , no_checkout );
1075
+ if (res )
1076
+ bisect_clean_state ();
1077
+
1078
+ return res ;
1003
1079
}
1004
1080
1005
1081
static inline int log2i (int n )
@@ -1040,3 +1116,40 @@ int estimate_bisect_steps(int all)
1040
1116
1041
1117
return (e < 3 * x ) ? n : n - 1 ;
1042
1118
}
1119
+
1120
+ static int mark_for_removal (const char * refname , const struct object_id * oid ,
1121
+ int flag , void * cb_data )
1122
+ {
1123
+ struct string_list * refs = cb_data ;
1124
+ char * ref = xstrfmt ("refs/bisect%s" , refname );
1125
+ string_list_append (refs , ref );
1126
+ return 0 ;
1127
+ }
1128
+
1129
+ int bisect_clean_state (void )
1130
+ {
1131
+ int result = 0 ;
1132
+
1133
+ /* There may be some refs packed during bisection */
1134
+ struct string_list refs_for_removal = STRING_LIST_INIT_NODUP ;
1135
+ for_each_ref_in ("refs/bisect" , mark_for_removal , (void * ) & refs_for_removal );
1136
+ string_list_append (& refs_for_removal , xstrdup ("BISECT_HEAD" ));
1137
+ result = delete_refs (& refs_for_removal , REF_NODEREF );
1138
+ refs_for_removal .strdup_strings = 1 ;
1139
+ string_list_clear (& refs_for_removal , 0 );
1140
+ unlink_or_warn (git_path_bisect_expected_rev ());
1141
+ unlink_or_warn (git_path_bisect_ancestors_ok ());
1142
+ unlink_or_warn (git_path_bisect_log ());
1143
+ unlink_or_warn (git_path_bisect_names ());
1144
+ unlink_or_warn (git_path_bisect_run ());
1145
+ unlink_or_warn (git_path_bisect_terms ());
1146
+ /* Cleanup head-name if it got left by an old version of git-bisect */
1147
+ unlink_or_warn (git_path_head_name ());
1148
+ /*
1149
+ * Cleanup BISECT_START last to support the --no-checkout option
1150
+ * introduced in the commit 4796e823a.
1151
+ */
1152
+ unlink_or_warn (git_path_bisect_start ());
1153
+
1154
+ return result ;
1155
+ }
0 commit comments