Skip to content

Commit 7d14d4f

Browse files
committed
Merge branch 'mr/bisect-in-c-3' into seen
* mr/bisect-in-c-3: bisect--helper: retire `--bisect-autostart` subcommand bisect--helper: retire `--write-terms` subcommand bisect--helper: retire `--check-expected-revs` subcommand bisect--helper: reimplement `bisect_state` & `bisect_head` shell functions in C bisect--helper: retire `--next-all` subcommand bisect--helper: retire `--bisect-clean-state` subcommand bisect--helper: finish porting `bisect_start()` to C
2 parents 05098f2 + 20a99c3 commit 7d14d4f

File tree

2 files changed

+115
-151
lines changed

2 files changed

+115
-151
lines changed

builtin/bisect--helper.c

Lines changed: 109 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
2020
static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
2121

2222
static const char * const git_bisect_helper_usage[] = {
23-
N_("git bisect--helper --next-all"),
24-
N_("git bisect--helper --write-terms <bad_term> <good_term>"),
25-
N_("git bisect--helper --bisect-clean-state"),
2623
N_("git bisect--helper --bisect-reset [<commit>]"),
2724
N_("git bisect--helper --bisect-write [--no-log] <state> <revision> <good_term> <bad_term>"),
2825
N_("git bisect--helper --bisect-check-and-set-terms <command> <good_term> <bad_term>"),
@@ -32,7 +29,8 @@ static const char * const git_bisect_helper_usage[] = {
3229
" [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
3330
N_("git bisect--helper --bisect-next"),
3431
N_("git bisect--helper --bisect-auto-next"),
35-
N_("git bisect--helper --bisect-autostart"),
32+
N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
33+
N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
3634
NULL
3735
};
3836

@@ -85,6 +83,19 @@ static int one_of(const char *term, ...)
8583
return res;
8684
}
8785

86+
/*
87+
* return code BISECT_INTERNAL_SUCCESS_MERGE_BASE
88+
* and BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND are codes
89+
* that indicate special success.
90+
*/
91+
92+
static int is_bisect_success(enum bisect_error res)
93+
{
94+
return !res ||
95+
res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND ||
96+
res == BISECT_INTERNAL_SUCCESS_MERGE_BASE;
97+
}
98+
8899
static int write_in_file(const char *path, const char *mode, const char *format, va_list args)
89100
{
90101
FILE *fp = NULL;
@@ -174,30 +185,6 @@ static int write_terms(const char *bad, const char *good)
174185
return res;
175186
}
176187

177-
static int is_expected_rev(const char *expected_hex)
178-
{
179-
struct strbuf actual_hex = STRBUF_INIT;
180-
int res = 0;
181-
if (strbuf_read_file(&actual_hex, git_path_bisect_expected_rev(), 0) >= 40) {
182-
strbuf_trim(&actual_hex);
183-
res = !strcmp(actual_hex.buf, expected_hex);
184-
}
185-
strbuf_release(&actual_hex);
186-
return res;
187-
}
188-
189-
static void check_expected_revs(const char **revs, int rev_nr)
190-
{
191-
int i;
192-
193-
for (i = 0; i < rev_nr; i++) {
194-
if (!is_expected_rev(revs[i])) {
195-
unlink_or_warn(git_path_bisect_ancestors_ok());
196-
unlink_or_warn(git_path_bisect_expected_rev());
197-
}
198-
}
199-
}
200-
201188
static int bisect_reset(const char *commit)
202189
{
203190
struct strbuf branch = STRBUF_INIT;
@@ -609,12 +596,13 @@ static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char
609596
return bisect_next(terms, prefix);
610597
}
611598

612-
static int bisect_start(struct bisect_terms *terms, const char **argv, int argc)
599+
static enum bisect_error bisect_start(struct bisect_terms *terms, const char **argv, int argc)
613600
{
614601
int no_checkout = 0;
615602
int first_parent_only = 0;
616603
int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
617-
int flags, pathspec_pos, res = 0;
604+
int flags, pathspec_pos;
605+
enum bisect_error res = BISECT_OK;
618606
struct string_list revs = STRING_LIST_INIT_DUP;
619607
struct string_list states = STRING_LIST_INIT_DUP;
620608
struct strbuf start_head = STRBUF_INIT;
@@ -753,14 +741,7 @@ static int bisect_start(struct bisect_terms *terms, const char **argv, int argc)
753741
* Get rid of any old bisect state.
754742
*/
755743
if (bisect_clean_state())
756-
return -1;
757-
758-
/*
759-
* In case of mistaken revs or checkout error, or signals received,
760-
* "bisect_auto_next" below may exit or misbehave.
761-
* We have to trap this to be able to clean up using
762-
* "bisect_clean_state".
763-
*/
744+
return BISECT_FAILED;
764745

765746
/*
766747
* Write new start state
@@ -777,7 +758,7 @@ static int bisect_start(struct bisect_terms *terms, const char **argv, int argc)
777758
}
778759
if (update_ref(NULL, "BISECT_HEAD", &oid, NULL, 0,
779760
UPDATE_REFS_MSG_ON_ERR)) {
780-
res = -1;
761+
res = BISECT_FAILED;
781762
goto finish;
782763
}
783764
}
@@ -789,25 +770,31 @@ static int bisect_start(struct bisect_terms *terms, const char **argv, int argc)
789770
for (i = 0; i < states.nr; i++)
790771
if (bisect_write(states.items[i].string,
791772
revs.items[i].string, terms, 1)) {
792-
res = -1;
773+
res = BISECT_FAILED;
793774
goto finish;
794775
}
795776

796777
if (must_write_terms && write_terms(terms->term_bad,
797778
terms->term_good)) {
798-
res = -1;
779+
res = BISECT_FAILED;
799780
goto finish;
800781
}
801782

802783
res = bisect_append_log_quoted(argv);
803784
if (res)
804-
res = -1;
785+
res = BISECT_FAILED;
805786

806787
finish:
807788
string_list_clear(&revs, 0);
808789
string_list_clear(&states, 0);
809790
strbuf_release(&start_head);
810791
strbuf_release(&bisect_names);
792+
if (res)
793+
return res;
794+
795+
res = bisect_auto_next(terms, NULL);
796+
if (!is_bisect_success(res))
797+
bisect_clean_state();
811798
return res;
812799
}
813800

@@ -843,33 +830,94 @@ static int bisect_autostart(struct bisect_terms *terms)
843830
return res;
844831
}
845832

833+
static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv,
834+
int argc)
835+
{
836+
const char *state;
837+
int i, verify_expected = 1;
838+
struct object_id oid, expected;
839+
struct strbuf buf = STRBUF_INIT;
840+
struct oid_array revs = OID_ARRAY_INIT;
841+
842+
if (!argc)
843+
return error(_("Please call `--bisect-state` with at least one argument"));
844+
845+
if (bisect_autostart(terms))
846+
return BISECT_FAILED;
847+
848+
state = argv[0];
849+
if (check_and_set_terms(terms, state) ||
850+
!one_of(state, terms->term_good, terms->term_bad, "skip", NULL))
851+
return BISECT_FAILED;
852+
853+
argv++;
854+
argc--;
855+
if (argc > 1 && !strcmp(state, terms->term_bad))
856+
return error(_("'git bisect %s' can take only one argument."), terms->term_bad);
857+
858+
if (argc == 0) {
859+
const char *head = "BISECT_HEAD";
860+
enum get_oid_result res_head = get_oid(head, &oid);
861+
862+
if (res_head == MISSING_OBJECT) {
863+
head = "HEAD";
864+
res_head = get_oid(head, &oid);
865+
}
866+
867+
if (res_head)
868+
error(_("Bad rev input: %s"), head);
869+
oid_array_append(&revs, &oid);
870+
}
871+
872+
/*
873+
* All input revs must be checked before executing bisect_write()
874+
* to discard junk revs.
875+
*/
876+
877+
for (; argc; argc--, argv++) {
878+
if (get_oid(*argv, &oid)){
879+
error(_("Bad rev input: %s"), *argv);
880+
return BISECT_FAILED;
881+
}
882+
oid_array_append(&revs, &oid);
883+
}
884+
885+
if (strbuf_read_file(&buf, git_path_bisect_expected_rev(), 0) < the_hash_algo->hexsz ||
886+
get_oid_hex(buf.buf, &expected) < 0)
887+
verify_expected = 0; /* Ignore invalid file contents */
888+
strbuf_release(&buf);
889+
890+
for (i = 0; i < revs.nr; i++) {
891+
if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0))
892+
return BISECT_FAILED;
893+
894+
if (verify_expected && !oideq(&revs.oid[i], &expected)) {
895+
unlink_or_warn(git_path_bisect_ancestors_ok());
896+
unlink_or_warn(git_path_bisect_expected_rev());
897+
verify_expected = 0;
898+
}
899+
}
900+
901+
oid_array_clear(&revs);
902+
return bisect_auto_next(terms, NULL);
903+
}
904+
846905
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
847906
{
848907
enum {
849-
NEXT_ALL = 1,
850-
WRITE_TERMS,
851-
BISECT_CLEAN_STATE,
852-
CHECK_EXPECTED_REVS,
853-
BISECT_RESET,
908+
BISECT_RESET = 1,
854909
BISECT_WRITE,
855910
CHECK_AND_SET_TERMS,
856911
BISECT_NEXT_CHECK,
857912
BISECT_TERMS,
858913
BISECT_START,
859914
BISECT_AUTOSTART,
860915
BISECT_NEXT,
861-
BISECT_AUTO_NEXT
916+
BISECT_AUTO_NEXT,
917+
BISECT_STATE
862918
} cmdmode = 0;
863919
int res = 0, nolog = 0;
864920
struct option options[] = {
865-
OPT_CMDMODE(0, "next-all", &cmdmode,
866-
N_("perform 'git bisect next'"), NEXT_ALL),
867-
OPT_CMDMODE(0, "write-terms", &cmdmode,
868-
N_("write the terms to .git/BISECT_TERMS"), WRITE_TERMS),
869-
OPT_CMDMODE(0, "bisect-clean-state", &cmdmode,
870-
N_("cleanup the bisection state"), BISECT_CLEAN_STATE),
871-
OPT_CMDMODE(0, "check-expected-revs", &cmdmode,
872-
N_("check for expected revs"), CHECK_EXPECTED_REVS),
873921
OPT_CMDMODE(0, "bisect-reset", &cmdmode,
874922
N_("reset the bisection state"), BISECT_RESET),
875923
OPT_CMDMODE(0, "bisect-write", &cmdmode,
@@ -886,8 +934,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
886934
N_("find the next bisection commit"), BISECT_NEXT),
887935
OPT_CMDMODE(0, "bisect-auto-next", &cmdmode,
888936
N_("verify the next bisection state then checkout the next bisection commit"), BISECT_AUTO_NEXT),
889-
OPT_CMDMODE(0, "bisect-autostart", &cmdmode,
890-
N_("start the bisection if it has not yet been started"), BISECT_AUTOSTART),
937+
OPT_CMDMODE(0, "bisect-state", &cmdmode,
938+
N_("mark the state of ref (or refs)"), BISECT_STATE),
891939
OPT_BOOL(0, "no-log", &nolog,
892940
N_("no log for BISECT_WRITE")),
893941
OPT_END()
@@ -902,20 +950,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
902950
usage_with_options(git_bisect_helper_usage, options);
903951

904952
switch (cmdmode) {
905-
case NEXT_ALL:
906-
res = bisect_next_all(the_repository, prefix);
907-
break;
908-
case WRITE_TERMS:
909-
if (argc != 2)
910-
return error(_("--write-terms requires two arguments"));
911-
return write_terms(argv[0], argv[1]);
912-
case BISECT_CLEAN_STATE:
913-
if (argc != 0)
914-
return error(_("--bisect-clean-state requires no arguments"));
915-
return bisect_clean_state();
916-
case CHECK_EXPECTED_REVS:
917-
check_expected_revs(argv, argc);
918-
return 0;
919953
case BISECT_RESET:
920954
if (argc > 1)
921955
return error(_("--bisect-reset requires either no argument or a commit"));
@@ -959,11 +993,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
959993
get_terms(&terms);
960994
res = bisect_auto_next(&terms, prefix);
961995
break;
962-
case BISECT_AUTOSTART:
963-
if (argc)
964-
return error(_("--bisect-autostart does not accept arguments"));
996+
case BISECT_STATE:
965997
set_terms(&terms, "bad", "good");
966-
res = bisect_autostart(&terms);
998+
get_terms(&terms);
999+
res = bisect_state(&terms, argv, argc);
9671000
break;
9681001
default:
9691002
BUG("unknown subcommand %d", cmdmode);

0 commit comments

Comments
 (0)