66#include "list-objects.h"
77#include "quote.h"
88#include "sha1-lookup.h"
9+ #include "run-command.h"
910#include "bisect.h"
1011
1112static unsigned char (* skipped_sha1 )[20 ];
@@ -16,6 +17,12 @@ static const char **rev_argv;
1617static int rev_argv_nr ;
1718static int rev_argv_alloc ;
1819
20+ static const unsigned char * current_bad_sha1 ;
21+
22+ static const char * argv_diff_tree [] = {"diff-tree" , "--pretty" , NULL , NULL };
23+ static const char * argv_checkout [] = {"checkout" , "-q" , NULL , "--" , NULL };
24+ static const char * argv_show_branch [] = {"show-branch" , NULL , NULL };
25+
1926/* bits #0-15 in revision.h */
2027
2128#define COUNTED (1u<<16)
@@ -403,6 +410,7 @@ static int register_ref(const char *refname, const unsigned char *sha1,
403410{
404411 if (!strcmp (refname , "bad" )) {
405412 ALLOC_GROW (rev_argv , rev_argv_nr + 1 , rev_argv_alloc );
413+ current_bad_sha1 = sha1 ;
406414 rev_argv [rev_argv_nr ++ ] = xstrdup (sha1_to_hex (sha1 ));
407415 } else if (!prefixcmp (refname , "good-" )) {
408416 const char * hex = sha1_to_hex (sha1 );
@@ -560,3 +568,100 @@ int bisect_next_vars(const char *prefix)
560568
561569 return show_bisect_vars (& info , reaches , all );
562570}
571+
572+ static void exit_if_skipped_commits (struct commit_list * tried ,
573+ const unsigned char * bad )
574+ {
575+ if (!tried )
576+ return ;
577+
578+ printf ("There are only 'skip'ped commits left to test.\n"
579+ "The first bad commit could be any of:\n" );
580+ print_commit_list (tried , "%s\n" , "%s\n" );
581+ if (bad )
582+ printf ("%s\n" , sha1_to_hex (bad ));
583+ printf ("We cannot bisect more!\n" );
584+ exit (2 );
585+ }
586+
587+ static void mark_expected_rev (char * bisect_rev_hex )
588+ {
589+ int len = strlen (bisect_rev_hex );
590+ const char * filename = git_path ("BISECT_EXPECTED_REV" );
591+ int fd = open (filename , O_CREAT | O_TRUNC | O_WRONLY , 0600 );
592+
593+ if (fd < 0 )
594+ die ("could not create file '%s': %s" ,
595+ filename , strerror (errno ));
596+
597+ bisect_rev_hex [len ] = '\n' ;
598+ write_or_die (fd , bisect_rev_hex , len + 1 );
599+ bisect_rev_hex [len ] = '\0' ;
600+
601+ if (close (fd ) < 0 )
602+ die ("closing file %s: %s" , filename , strerror (errno ));
603+ }
604+
605+ static int bisect_checkout (char * bisect_rev_hex )
606+ {
607+ int res ;
608+
609+ mark_expected_rev (bisect_rev_hex );
610+
611+ argv_checkout [2 ] = bisect_rev_hex ;
612+ res = run_command_v_opt (argv_checkout , RUN_GIT_CMD );
613+ if (res )
614+ exit (res );
615+
616+ argv_show_branch [1 ] = bisect_rev_hex ;
617+ return run_command_v_opt (argv_show_branch , RUN_GIT_CMD );
618+ }
619+
620+ /*
621+ * We use the convention that exiting with an exit code 10 means that
622+ * the bisection process finished successfully.
623+ * In this case the calling shell script should exit 0.
624+ */
625+ int bisect_next_exit (const char * prefix )
626+ {
627+ struct rev_info revs ;
628+ struct commit_list * tried ;
629+ int reaches = 0 , all = 0 , nr ;
630+ const unsigned char * bisect_rev ;
631+ char bisect_rev_hex [41 ];
632+
633+ bisect_common (& revs , prefix , & reaches , & all );
634+
635+ revs .commits = filter_skipped (revs .commits , & tried , 0 );
636+
637+ if (!revs .commits ) {
638+ /*
639+ * We should exit here only if the "bad"
640+ * commit is also a "skip" commit.
641+ */
642+ exit_if_skipped_commits (tried , NULL );
643+
644+ printf ("%s was both good and bad\n" ,
645+ sha1_to_hex (current_bad_sha1 ));
646+ exit (1 );
647+ }
648+
649+ bisect_rev = revs .commits -> item -> object .sha1 ;
650+ memcpy (bisect_rev_hex , sha1_to_hex (bisect_rev ), 41 );
651+
652+ if (!hashcmp (bisect_rev , current_bad_sha1 )) {
653+ exit_if_skipped_commits (tried , current_bad_sha1 );
654+ printf ("%s is first bad commit\n" , bisect_rev_hex );
655+ argv_diff_tree [2 ] = bisect_rev_hex ;
656+ run_command_v_opt (argv_diff_tree , RUN_GIT_CMD );
657+ /* This means the bisection process succeeded. */
658+ exit (10 );
659+ }
660+
661+ nr = all - reaches - 1 ;
662+ printf ("Bisecting: %d revisions left to test after this "
663+ "(roughly %d steps)\n" , nr , estimate_bisect_steps (all ));
664+
665+ return bisect_checkout (bisect_rev_hex );
666+ }
667+
0 commit comments