@@ -507,6 +507,20 @@ static int lookup_sha1_array(struct sha1_array *array,
507507 return sha1_pos (sha1 , array -> sha1 , array -> sha1_nr , sha1_access );
508508}
509509
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+
510524struct commit_list * filter_skipped (struct commit_list * list ,
511525 struct commit_list * * tried ,
512526 int show_all )
@@ -587,6 +601,30 @@ static void exit_if_skipped_commits(struct commit_list *tried,
587601 exit (2 );
588602}
589603
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+
590628static void mark_expected_rev (char * bisect_rev_hex )
591629{
592630 int len = strlen (bisect_rev_hex );
@@ -620,6 +658,98 @@ static int bisect_checkout(char *bisect_rev_hex)
620658 return run_command_v_opt (argv_show_branch , RUN_GIT_CMD );
621659}
622660
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+
623753/*
624754 * We use the convention that exiting with an exit code 10 means that
625755 * the bisection process finished successfully.
0 commit comments