77#include "quote.h"
88#include "sha1-lookup.h"
99#include "run-command.h"
10+ #include "log-tree.h"
1011#include "bisect.h"
1112
1213struct sha1_array {
@@ -27,7 +28,6 @@ struct argv_array {
2728 int argv_alloc ;
2829};
2930
30- static const char * argv_diff_tree [] = {"diff-tree" , "--pretty" , NULL , NULL };
3131static const char * argv_checkout [] = {"checkout" , "-q" , NULL , "--" , NULL };
3232static const char * argv_show_branch [] = {"show-branch" , NULL , NULL };
3333
@@ -521,14 +521,34 @@ static char *join_sha1_array_hex(struct sha1_array *array, char delim)
521521 return strbuf_detach (& joined_hexs , NULL );
522522}
523523
524+ /*
525+ * In this function, passing a not NULL skipped_first is very special.
526+ * It means that we want to know if the first commit in the list is
527+ * skipped because we will want to test a commit away from it if it is
528+ * indeed skipped.
529+ * So if the first commit is skipped, we cannot take the shortcut to
530+ * just "return list" when we find the first non skipped commit, we
531+ * have to return a fully filtered list.
532+ *
533+ * We use (*skipped_first == -1) to mean "it has been found that the
534+ * first commit is not skipped". In this case *skipped_first is set back
535+ * to 0 just before the function returns.
536+ */
524537struct commit_list * filter_skipped (struct commit_list * list ,
525538 struct commit_list * * tried ,
526- int show_all )
539+ int show_all ,
540+ int * count ,
541+ int * skipped_first )
527542{
528543 struct commit_list * filtered = NULL , * * f = & filtered ;
529544
530545 * tried = NULL ;
531546
547+ if (skipped_first )
548+ * skipped_first = 0 ;
549+ if (count )
550+ * count = 0 ;
551+
532552 if (!skipped_revs .sha1_nr )
533553 return list ;
534554
@@ -537,22 +557,82 @@ struct commit_list *filter_skipped(struct commit_list *list,
537557 list -> next = NULL ;
538558 if (0 <= lookup_sha1_array (& skipped_revs ,
539559 list -> item -> object .sha1 )) {
560+ if (skipped_first && !* skipped_first )
561+ * skipped_first = 1 ;
540562 /* Move current to tried list */
541563 * tried = list ;
542564 tried = & list -> next ;
543565 } else {
544- if (!show_all )
545- return list ;
566+ if (!show_all ) {
567+ if (!skipped_first || !* skipped_first )
568+ return list ;
569+ } else if (skipped_first && !* skipped_first ) {
570+ /* This means we know it's not skipped */
571+ * skipped_first = -1 ;
572+ }
546573 /* Move current to filtered list */
547574 * f = list ;
548575 f = & list -> next ;
576+ if (count )
577+ (* count )++ ;
549578 }
550579 list = next ;
551580 }
552581
582+ if (skipped_first && * skipped_first == -1 )
583+ * skipped_first = 0 ;
584+
553585 return filtered ;
554586}
555587
588+ static struct commit_list * apply_skip_ratio (struct commit_list * list ,
589+ int count ,
590+ int skip_num , int skip_denom )
591+ {
592+ int index , i ;
593+ struct commit_list * cur , * previous ;
594+
595+ cur = list ;
596+ previous = NULL ;
597+ index = count * skip_num / skip_denom ;
598+
599+ for (i = 0 ; cur ; cur = cur -> next , i ++ ) {
600+ if (i == index ) {
601+ if (hashcmp (cur -> item -> object .sha1 , current_bad_sha1 ))
602+ return cur ;
603+ if (previous )
604+ return previous ;
605+ return list ;
606+ }
607+ previous = cur ;
608+ }
609+
610+ return list ;
611+ }
612+
613+ static struct commit_list * managed_skipped (struct commit_list * list ,
614+ struct commit_list * * tried )
615+ {
616+ int count , skipped_first ;
617+ int skip_num , skip_denom ;
618+
619+ * tried = NULL ;
620+
621+ if (!skipped_revs .sha1_nr )
622+ return list ;
623+
624+ list = filter_skipped (list , tried , 0 , & count , & skipped_first );
625+
626+ if (!skipped_first )
627+ return list ;
628+
629+ /* Use alternatively 1/5, 2/5 and 3/5 as skip ratio. */
630+ skip_num = count % 3 + 1 ;
631+ skip_denom = 5 ;
632+
633+ return apply_skip_ratio (list , count , skip_num , skip_denom );
634+ }
635+
556636static void bisect_rev_setup (struct rev_info * revs , const char * prefix ,
557637 const char * bad_format , const char * good_format ,
558638 int read_paths )
@@ -771,7 +851,7 @@ static int check_ancestors(const char *prefix)
771851 /* Clean up objects used, as they will be reused. */
772852 for (i = 0 ; i < pending_copy .nr ; i ++ ) {
773853 struct object * o = pending_copy .objects [i ].item ;
774- unparse_commit ((struct commit * )o );
854+ clear_commit_marks ((struct commit * )o , ALL_REV_FLAGS );
775855 }
776856
777857 return res ;
@@ -815,6 +895,31 @@ static void check_good_are_ancestors_of_bad(const char *prefix)
815895 close (fd );
816896}
817897
898+ /*
899+ * This does "git diff-tree --pretty COMMIT" without one fork+exec.
900+ */
901+ static void show_diff_tree (const char * prefix , struct commit * commit )
902+ {
903+ struct rev_info opt ;
904+
905+ /* diff-tree init */
906+ init_revisions (& opt , prefix );
907+ git_config (git_diff_basic_config , NULL ); /* no "diff" UI options */
908+ opt .abbrev = 0 ;
909+ opt .diff = 1 ;
910+
911+ /* This is what "--pretty" does */
912+ opt .verbose_header = 1 ;
913+ opt .use_terminator = 0 ;
914+ opt .commit_format = CMIT_FMT_DEFAULT ;
915+
916+ /* diff-tree init */
917+ if (!opt .diffopt .output_format )
918+ opt .diffopt .output_format = DIFF_FORMAT_RAW ;
919+
920+ log_tree_commit (& opt , commit );
921+ }
922+
818923/*
819924 * We use the convention that exiting with an exit code 10 means that
820925 * the bisection process finished successfully.
@@ -840,7 +945,7 @@ int bisect_next_all(const char *prefix)
840945
841946 revs .commits = find_bisection (revs .commits , & reaches , & all ,
842947 !!skipped_revs .sha1_nr );
843- revs .commits = filter_skipped (revs .commits , & tried , 0 );
948+ revs .commits = managed_skipped (revs .commits , & tried );
844949
845950 if (!revs .commits ) {
846951 /*
@@ -860,8 +965,7 @@ int bisect_next_all(const char *prefix)
860965 if (!hashcmp (bisect_rev , current_bad_sha1 )) {
861966 exit_if_skipped_commits (tried , current_bad_sha1 );
862967 printf ("%s is first bad commit\n" , bisect_rev_hex );
863- argv_diff_tree [2 ] = bisect_rev_hex ;
864- run_command_v_opt (argv_diff_tree , RUN_GIT_CMD );
968+ show_diff_tree (prefix , revs .commits -> item );
865969 /* This means the bisection process succeeded. */
866970 exit (10 );
867971 }
0 commit comments