@matheusbsbs / matheus-bagliano / commits / c053766280
Fork 0

bisect: implement the "check_merge_bases" function

And all functions needed to make it work. This is a port from the shell function with the same name "git-bisect.sh". This function is not used yet but it will be used later. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Christian Couder committed May 9, 2009 at 17:55 UTC c0537662806f4b3d3ba883d05a48fdf9120893f0
1 file changed +130
bisect.c
+130
@@ -507,6 +507,20 @@ static int lookup_sha1_array(struct sha1_array *array,
507 return sha1_pos(sha1, array->sha1, array->sha1_nr, sha1_access);
508 }
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 +
524 struct commit_list *filter_skipped(struct commit_list *list,
525 struct commit_list **tried,
526 int show_all)
@@ -587,6 +601,30 @@ static void exit_if_skipped_commits(struct commit_list *tried,
601 exit(2);
602 }
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 +
628 static void mark_expected_rev(char *bisect_rev_hex)
629 {
630 int len = strlen(bisect_rev_hex);
@@ -620,6 +658,98 @@ static int bisect_checkout(char *bisect_rev_hex)
658 return run_command_v_opt(argv_show_branch, RUN_GIT_CMD);
659 }
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 +
753 /*
754 * We use the convention that exiting with an exit code 10 means that
755 * the bisection process finished successfully.