@@ -507,6 +507,20 @@ static int lookup_sha1_array(struct sha1_array *array,
507
507
return sha1_pos (sha1 , array -> sha1 , array -> sha1_nr , sha1_access );
508
508
}
509
509
510
+ static char * join_sha1_array_hex (struct sha1_array * array , char delim )
511
+ {
512
+ struct strbuf joined_hexs = STRBUF_INIT ;
513
+ int i ;
514
+
515
+ for (i = 0 ; i < array -> sha1_nr ; i ++ ) {
516
+ strbuf_addstr (& joined_hexs , sha1_to_hex (array -> sha1 [i ]));
517
+ if (i + 1 < array -> sha1_nr )
518
+ strbuf_addch (& joined_hexs , delim );
519
+ }
520
+
521
+ return strbuf_detach (& joined_hexs , NULL );
522
+ }
523
+
510
524
struct commit_list * filter_skipped (struct commit_list * list ,
511
525
struct commit_list * * tried ,
512
526
int show_all )
@@ -587,6 +601,30 @@ static void exit_if_skipped_commits(struct commit_list *tried,
587
601
exit (2 );
588
602
}
589
603
604
+ static int is_expected_rev (const unsigned char * sha1 )
605
+ {
606
+ const char * filename = git_path ("BISECT_EXPECTED_REV" );
607
+ struct stat st ;
608
+ struct strbuf str = STRBUF_INIT ;
609
+ FILE * fp ;
610
+ int res = 0 ;
611
+
612
+ if (stat (filename , & st ) || !S_ISREG (st .st_mode ))
613
+ return 0 ;
614
+
615
+ fp = fopen (filename , "r" );
616
+ if (!fp )
617
+ return 0 ;
618
+
619
+ if (strbuf_getline (& str , fp , '\n' ) != EOF )
620
+ res = !strcmp (str .buf , sha1_to_hex (sha1 ));
621
+
622
+ strbuf_release (& str );
623
+ fclose (fp );
624
+
625
+ return res ;
626
+ }
627
+
590
628
static void mark_expected_rev (char * bisect_rev_hex )
591
629
{
592
630
int len = strlen (bisect_rev_hex );
@@ -620,6 +658,98 @@ static int bisect_checkout(char *bisect_rev_hex)
620
658
return run_command_v_opt (argv_show_branch , RUN_GIT_CMD );
621
659
}
622
660
661
+ static struct commit * get_commit_reference (const unsigned char * sha1 )
662
+ {
663
+ struct commit * r = lookup_commit_reference (sha1 );
664
+ if (!r )
665
+ die ("Not a valid commit name %s" , sha1_to_hex (sha1 ));
666
+ return r ;
667
+ }
668
+
669
+ static struct commit * * get_bad_and_good_commits (int * rev_nr )
670
+ {
671
+ int len = 1 + good_revs .sha1_nr ;
672
+ struct commit * * rev = xmalloc (len * sizeof (* rev ));
673
+ int i , n = 0 ;
674
+
675
+ rev [n ++ ] = get_commit_reference (current_bad_sha1 );
676
+ for (i = 0 ; i < good_revs .sha1_nr ; i ++ )
677
+ rev [n ++ ] = get_commit_reference (good_revs .sha1 [i ]);
678
+ * rev_nr = n ;
679
+
680
+ return rev ;
681
+ }
682
+
683
+ static void handle_bad_merge_base (void )
684
+ {
685
+ if (is_expected_rev (current_bad_sha1 )) {
686
+ char * bad_hex = sha1_to_hex (current_bad_sha1 );
687
+ char * good_hex = join_sha1_array_hex (& good_revs , ' ' );
688
+
689
+ fprintf (stderr , "The merge base %s is bad.\n"
690
+ "This means the bug has been fixed "
691
+ "between %s and [%s].\n" ,
692
+ bad_hex , bad_hex , good_hex );
693
+
694
+ exit (3 );
695
+ }
696
+
697
+ fprintf (stderr , "Some good revs are not ancestor of the bad rev.\n"
698
+ "git bisect cannot work properly in this case.\n"
699
+ "Maybe you mistake good and bad revs?\n" );
700
+ exit (1 );
701
+ }
702
+
703
+ void handle_skipped_merge_base (const unsigned char * mb )
704
+ {
705
+ char * mb_hex = sha1_to_hex (mb );
706
+ char * bad_hex = sha1_to_hex (current_bad_sha1 );
707
+ char * good_hex = join_sha1_array_hex (& good_revs , ' ' );
708
+
709
+ fprintf (stderr , "Warning: the merge base between %s and [%s] "
710
+ "must be skipped.\n"
711
+ "So we cannot be sure the first bad commit is "
712
+ "between %s and %s.\n"
713
+ "We continue anyway.\n" ,
714
+ bad_hex , good_hex , mb_hex , bad_hex );
715
+ free (good_hex );
716
+ }
717
+
718
+ /*
719
+ * "check_merge_bases" checks that merge bases are not "bad".
720
+ *
721
+ * - If one is "bad", it means the user assumed something wrong
722
+ * and we must exit with a non 0 error code.
723
+ * - If one is "good", that's good, we have nothing to do.
724
+ * - If one is "skipped", we can't know but we should warn.
725
+ * - If we don't know, we should check it out and ask the user to test.
726
+ */
727
+ static void check_merge_bases (void )
728
+ {
729
+ struct commit_list * result ;
730
+ int rev_nr ;
731
+ struct commit * * rev = get_bad_and_good_commits (& rev_nr );
732
+
733
+ result = get_merge_bases_many (rev [0 ], rev_nr - 1 , rev + 1 , 0 );
734
+
735
+ for (; result ; result = result -> next ) {
736
+ const unsigned char * mb = result -> item -> object .sha1 ;
737
+ if (!hashcmp (mb , current_bad_sha1 )) {
738
+ handle_bad_merge_base ();
739
+ } else if (0 <= lookup_sha1_array (& good_revs , mb )) {
740
+ continue ;
741
+ } else if (0 <= lookup_sha1_array (& skipped_revs , mb )) {
742
+ handle_skipped_merge_base (mb );
743
+ } else {
744
+ printf ("Bisecting: a merge base must be tested\n" );
745
+ exit (bisect_checkout (sha1_to_hex (mb )));
746
+ }
747
+ }
748
+
749
+ free (rev );
750
+ free_commit_list (result );
751
+ }
752
+
623
753
/*
624
754
* We use the convention that exiting with an exit code 10 means that
625
755
* the bisection process finished successfully.
0 commit comments