Skip to content

Commit 7c4d680

Browse files
committed
Merge branch 'mr/bisect-in-c-3' into seen
Rewriting "git bisect" in C continues. How ready is this one? * 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 f248b08 + b0f6494 commit 7c4d680

File tree

2 files changed

+117
-151
lines changed

2 files changed

+117
-151
lines changed

builtin/bisect--helper.c

Lines changed: 111 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,96 @@ 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+
oid_array_clear(&revs);
881+
return BISECT_FAILED;
882+
}
883+
oid_array_append(&revs, &oid);
884+
}
885+
886+
if (strbuf_read_file(&buf, git_path_bisect_expected_rev(), 0) < the_hash_algo->hexsz ||
887+
get_oid_hex(buf.buf, &expected) < 0)
888+
verify_expected = 0; /* Ignore invalid file contents */
889+
strbuf_release(&buf);
890+
891+
for (i = 0; i < revs.nr; i++) {
892+
if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {
893+
oid_array_clear(&revs);
894+
return BISECT_FAILED;
895+
}
896+
if (verify_expected && !oideq(&revs.oid[i], &expected)) {
897+
unlink_or_warn(git_path_bisect_ancestors_ok());
898+
unlink_or_warn(git_path_bisect_expected_rev());
899+
verify_expected = 0;
900+
}
901+
}
902+
903+
oid_array_clear(&revs);
904+
return bisect_auto_next(terms, NULL);
905+
}
906+
846907
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
847908
{
848909
enum {
849-
NEXT_ALL = 1,
850-
WRITE_TERMS,
851-
BISECT_CLEAN_STATE,
852-
CHECK_EXPECTED_REVS,
853-
BISECT_RESET,
910+
BISECT_RESET = 1,
854911
BISECT_WRITE,
855912
CHECK_AND_SET_TERMS,
856913
BISECT_NEXT_CHECK,
857914
BISECT_TERMS,
858915
BISECT_START,
859916
BISECT_AUTOSTART,
860917
BISECT_NEXT,
861-
BISECT_AUTO_NEXT
918+
BISECT_AUTO_NEXT,
919+
BISECT_STATE
862920
} cmdmode = 0;
863921
int res = 0, nolog = 0;
864922
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),
873923
OPT_CMDMODE(0, "bisect-reset", &cmdmode,
874924
N_("reset the bisection state"), BISECT_RESET),
875925
OPT_CMDMODE(0, "bisect-write", &cmdmode,
@@ -886,8 +936,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
886936
N_("find the next bisection commit"), BISECT_NEXT),
887937
OPT_CMDMODE(0, "bisect-auto-next", &cmdmode,
888938
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),
939+
OPT_CMDMODE(0, "bisect-state", &cmdmode,
940+
N_("mark the state of ref (or refs)"), BISECT_STATE),
891941
OPT_BOOL(0, "no-log", &nolog,
892942
N_("no log for BISECT_WRITE")),
893943
OPT_END()
@@ -902,20 +952,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
902952
usage_with_options(git_bisect_helper_usage, options);
903953

904954
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;
919955
case BISECT_RESET:
920956
if (argc > 1)
921957
return error(_("--bisect-reset requires either no argument or a commit"));
@@ -959,11 +995,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
959995
get_terms(&terms);
960996
res = bisect_auto_next(&terms, prefix);
961997
break;
962-
case BISECT_AUTOSTART:
963-
if (argc)
964-
return error(_("--bisect-autostart does not accept arguments"));
998+
case BISECT_STATE:
965999
set_terms(&terms, "bad", "good");
966-
res = bisect_autostart(&terms);
1000+
get_terms(&terms);
1001+
res = bisect_state(&terms, argv, argc);
9671002
break;
9681003
default:
9691004
BUG("unknown subcommand %d", cmdmode);

0 commit comments

Comments
 (0)