7
7
#include "quote.h"
8
8
#include "sha1-lookup.h"
9
9
#include "run-command.h"
10
+ #include "log-tree.h"
10
11
#include "bisect.h"
11
12
12
13
struct sha1_array {
@@ -27,7 +28,6 @@ struct argv_array {
27
28
int argv_alloc ;
28
29
};
29
30
30
- static const char * argv_diff_tree [] = {"diff-tree" , "--pretty" , NULL , NULL };
31
31
static const char * argv_checkout [] = {"checkout" , "-q" , NULL , "--" , NULL };
32
32
static const char * argv_show_branch [] = {"show-branch" , NULL , NULL };
33
33
@@ -521,14 +521,34 @@ static char *join_sha1_array_hex(struct sha1_array *array, char delim)
521
521
return strbuf_detach (& joined_hexs , NULL );
522
522
}
523
523
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
+ */
524
537
struct commit_list * filter_skipped (struct commit_list * list ,
525
538
struct commit_list * * tried ,
526
- int show_all )
539
+ int show_all ,
540
+ int * count ,
541
+ int * skipped_first )
527
542
{
528
543
struct commit_list * filtered = NULL , * * f = & filtered ;
529
544
530
545
* tried = NULL ;
531
546
547
+ if (skipped_first )
548
+ * skipped_first = 0 ;
549
+ if (count )
550
+ * count = 0 ;
551
+
532
552
if (!skipped_revs .sha1_nr )
533
553
return list ;
534
554
@@ -537,22 +557,82 @@ struct commit_list *filter_skipped(struct commit_list *list,
537
557
list -> next = NULL ;
538
558
if (0 <= lookup_sha1_array (& skipped_revs ,
539
559
list -> item -> object .sha1 )) {
560
+ if (skipped_first && !* skipped_first )
561
+ * skipped_first = 1 ;
540
562
/* Move current to tried list */
541
563
* tried = list ;
542
564
tried = & list -> next ;
543
565
} 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
+ }
546
573
/* Move current to filtered list */
547
574
* f = list ;
548
575
f = & list -> next ;
576
+ if (count )
577
+ (* count )++ ;
549
578
}
550
579
list = next ;
551
580
}
552
581
582
+ if (skipped_first && * skipped_first == -1 )
583
+ * skipped_first = 0 ;
584
+
553
585
return filtered ;
554
586
}
555
587
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
+
556
636
static void bisect_rev_setup (struct rev_info * revs , const char * prefix ,
557
637
const char * bad_format , const char * good_format ,
558
638
int read_paths )
@@ -771,7 +851,7 @@ static int check_ancestors(const char *prefix)
771
851
/* Clean up objects used, as they will be reused. */
772
852
for (i = 0 ; i < pending_copy .nr ; i ++ ) {
773
853
struct object * o = pending_copy .objects [i ].item ;
774
- unparse_commit ((struct commit * )o );
854
+ clear_commit_marks ((struct commit * )o , ALL_REV_FLAGS );
775
855
}
776
856
777
857
return res ;
@@ -815,6 +895,31 @@ static void check_good_are_ancestors_of_bad(const char *prefix)
815
895
close (fd );
816
896
}
817
897
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
+
818
923
/*
819
924
* We use the convention that exiting with an exit code 10 means that
820
925
* the bisection process finished successfully.
@@ -840,7 +945,7 @@ int bisect_next_all(const char *prefix)
840
945
841
946
revs .commits = find_bisection (revs .commits , & reaches , & all ,
842
947
!!skipped_revs .sha1_nr );
843
- revs .commits = filter_skipped (revs .commits , & tried , 0 );
948
+ revs .commits = managed_skipped (revs .commits , & tried );
844
949
845
950
if (!revs .commits ) {
846
951
/*
@@ -860,8 +965,7 @@ int bisect_next_all(const char *prefix)
860
965
if (!hashcmp (bisect_rev , current_bad_sha1 )) {
861
966
exit_if_skipped_commits (tried , current_bad_sha1 );
862
967
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 );
865
969
/* This means the bisection process succeeded. */
866
970
exit (10 );
867
971
}
0 commit comments