diff options
-rw-r--r-- | bisect.c | 3 | ||||
-rw-r--r-- | bisect.h | 4 | ||||
-rw-r--r-- | builtin/bisect--helper.c | 63 | ||||
-rwxr-xr-x | t/t6030-bisect-porcelain.sh | 4 |
4 files changed, 71 insertions, 3 deletions
@@ -724,7 +724,8 @@ static int is_expected_rev(const struct object_id *oid) return res; } -static enum bisect_error bisect_checkout(const struct object_id *bisect_rev, int no_checkout) +enum bisect_error bisect_checkout(const struct object_id *bisect_rev, + int no_checkout) { char bisect_rev_hex[GIT_MAX_HEXSZ + 1]; struct commit *commit; @@ -3,6 +3,7 @@ struct commit_list; struct repository; +struct object_id; /* * Find bisection. If something is found, `reaches` will be the number of @@ -69,4 +70,7 @@ void read_bisect_terms(const char **bad, const char **good); int bisect_clean_state(void); +enum bisect_error bisect_checkout(const struct object_id *bisect_rev, + int no_checkout); + #endif diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c index e529665d9f..50783a586c 100644 --- a/builtin/bisect--helper.c +++ b/builtin/bisect--helper.c @@ -1089,6 +1089,44 @@ static int bisect_visualize(struct bisect_terms *terms, const char **argv, int a return res; } +static int get_first_good(const char *refname, const struct object_id *oid, + int flag, void *cb_data) +{ + oidcpy(cb_data, oid); + return 1; +} + +static int verify_good(const struct bisect_terms *terms, + const char **quoted_argv) +{ + int rc; + enum bisect_error res; + struct object_id good_rev; + struct object_id current_rev; + char *good_glob = xstrfmt("%s-*", terms->term_good); + int no_checkout = ref_exists("BISECT_HEAD"); + + for_each_glob_ref_in(get_first_good, good_glob, "refs/bisect/", + &good_rev); + free(good_glob); + + if (read_ref(no_checkout ? "BISECT_HEAD" : "HEAD", ¤t_rev)) + return -1; + + res = bisect_checkout(&good_rev, no_checkout); + if (res != BISECT_OK) + return -1; + + printf(_("running %s\n"), quoted_argv[0]); + rc = run_command_v_opt(quoted_argv, RUN_USING_SHELL); + + res = bisect_checkout(¤t_rev, no_checkout); + if (res != BISECT_OK) + return -1; + + return rc; +} + static int bisect_run(struct bisect_terms *terms, const char **argv, int argc) { int res = BISECT_OK; @@ -1096,6 +1134,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc) struct strvec run_args = STRVEC_INIT; const char *new_state; int temporary_stdout_fd, saved_stdout; + int is_first_run = 1; if (bisect_next_check(terms, NULL)) return BISECT_FAILED; @@ -1113,6 +1152,30 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc) printf(_("running %s\n"), command.buf); res = run_command_v_opt(run_args.v, RUN_USING_SHELL); + /* + * Exit code 126 and 127 can either come from the shell + * if it was unable to execute or even find the script, + * or from the script itself. Check with a known-good + * revision to avoid trashing the bisect run due to a + * missing or non-executable script. + */ + if (is_first_run && (res == 126 || res == 127)) { + int rc = verify_good(terms, run_args.v); + is_first_run = 0; + if (rc < 0) { + error(_("unable to verify '%s' on good" + " revision"), command.buf); + res = BISECT_FAILED; + break; + } + if (rc == res) { + error(_("bogus exit code %d for good revision"), + rc); + res = BISECT_FAILED; + break; + } + } + if (res < 0 || 128 <= res) { error(_("bisect run failed: exit code %d from" " '%s' is < 0 or >= 128"), res, command.buf); diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index fc18796517..5382e5d216 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -290,7 +290,7 @@ test_expect_success 'bisect run accepts exit code 126 as bad' ' grep "$HASH3 is the first bad commit" my_bisect_log.txt ' -test_expect_failure POSIXPERM 'bisect run fails with non-executable test script' ' +test_expect_success POSIXPERM 'bisect run fails with non-executable test script' ' test_when_finished "git bisect reset" && >not-executable.sh && chmod -x not-executable.sh && @@ -313,7 +313,7 @@ test_expect_success 'bisect run accepts exit code 127 as bad' ' grep "$HASH3 is the first bad commit" my_bisect_log.txt ' -test_expect_failure 'bisect run fails with missing test script' ' +test_expect_success 'bisect run fails with missing test script' ' test_when_finished "git bisect reset" && rm -f does-not-exist.sh && git bisect start && |