{"thread":{"id":"60744","subject":"[PATCH] bisect: add --force flag to force checkout","startedAt":"2024-01-15T07:05:11Z","lastAt":"2024-01-16T22:30:36Z","messageCount":2,"participants":["Kevin Wang via GitGitGadget","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"486789","messageId":"pull.1641.git.git.1705302307639.gitgitgadget@gmail.com","threadId":"60744","inReplyTo":null,"subject":"[PATCH] bisect: add --force flag to force checkout","fromName":"Kevin Wang via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2024-01-15T07:05:07Z","receivedAt":"2024-01-15T07:05:11Z","isPatch":true,"sender":{"key":"name:Kevin Wang","avatar":null},"body":"From: Kevin Wang <kevmo314@gmail.com>\n\nAdds a `--force`/`-f` flag to `git bisect good/bad` and `git bisect run` to\nforce a checkout. Currently, if the repository state adds any local changes\nthe user must manually reset the repository state before moving to the next\nbisection step. This can happen with package lock files or log output data,\nfor example. With this change, a developer can run `git bisect run --force`\nto automatically reset the repository state after each evaluation. The flag\nis also supported as `git bisect (good|bad) --force` as well.\n\nSigned-off-by: Kevin Wang <kevmo314@gmail.com>\n---\n    bisect: add --force flag to force checkout\n    \n    Adds a --force/-f flag to git bisect good/bad and git bisect run to\n    force a checkout. Currently, if the repository state adds any local\n    changes the user must manually reset the repository state before moving\n    to the next bisection step. This can happen with package lock files or\n    log output data, for example. With this change, a developer can run git\n    bisect run --force to automatically reset the repository state after\n    each evaluation. The flag is also supported as git bisect (good|bad)\n    --force as well.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1641%2Fkevmo314%2Fbisect-force-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1641/kevmo314/bisect-force-v1\nPull-Request: https://github.com/git/git/pull/1641\n\n Documentation/git-bisect.txt |  13 ++++-\n bisect.c                     |  17 ++++--\n bisect.h                     |   4 +-\n builtin/bisect.c             |  50 +++++++++++-----\n t/t6030-bisect-porcelain.sh  | 109 +++++++++++++++++++++++++++++++++++\n 5 files changed, 167 insertions(+), 26 deletions(-)\n\ndiff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt\nindex aa02e462244..57357221718 100644\n--- a/Documentation/git-bisect.txt\n+++ b/Documentation/git-bisect.txt\n@@ -19,14 +19,14 @@ on the subcommand:\n  git bisect start [--term-(new|bad)=<term-new> --term-(old|good)=<term-old>]\n \t\t  [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]\n  git bisect (bad|new|<term-new>) [<rev>]\n- git bisect (good|old|<term-old>) [<rev>...]\n+ git bisect (good|old|<term-old>) [-f] [<rev>...]\n  git bisect terms [--term-good | --term-bad]\n  git bisect skip [(<rev>|<range>)...]\n  git bisect reset [<commit>]\n  git bisect (visualize|view)\n  git bisect replay <logfile>\n  git bisect log\n- git bisect run <cmd> [<arg>...]\n+ git bisect run [-f] <cmd> [<arg>...]\n  git bisect help\n \n This command uses a binary search algorithm to find which commit in\n@@ -381,6 +381,15 @@ ignored.\n This option is particularly useful in avoiding false positives when a merged\n branch contained broken or non-buildable commits, but the merge itself was OK.\n \n+-f::\n+--force::\n++\n+Throw away any local changes and untracked files before moving to the next\n+bisection step.\n++\n+This option may be useful if the repository state changes when testing a\n+revision.\n+\n EXAMPLES\n --------\n \ndiff --git a/bisect.c b/bisect.c\nindex 985b96ed132..72ce09f2015 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -713,7 +713,7 @@ static int is_expected_rev(const struct object_id *oid)\n }\n \n enum bisect_error bisect_checkout(const struct object_id *bisect_rev,\n-\t\t\t\t  int no_checkout)\n+\t\t\t\t  int no_checkout, int force_checkout)\n {\n \tstruct commit *commit;\n \tstruct pretty_print_context pp = {0};\n@@ -728,8 +728,13 @@ enum bisect_error bisect_checkout(const struct object_id *bisect_rev,\n \t\tstruct child_process cmd = CHILD_PROCESS_INIT;\n \n \t\tcmd.git_cmd = 1;\n-\t\tstrvec_pushl(&cmd.args, \"checkout\", \"-q\",\n-\t\t\t     oid_to_hex(bisect_rev), \"--\", NULL);\n+\t\tif (force_checkout) {\n+\t\t\tstrvec_pushl(&cmd.args, \"checkout\", \"-f\", \"-q\",\n+\t\t\t\t\toid_to_hex(bisect_rev), \"--\", NULL);\n+\t\t} else {\n+\t\t\tstrvec_pushl(&cmd.args, \"checkout\", \"-q\",\n+\t\t\t\t\toid_to_hex(bisect_rev), \"--\", NULL);\n+\t\t}\n \t\tif (run_command(&cmd))\n \t\t\t/*\n \t\t\t * Errors in `run_command()` itself, signaled by res < 0,\n@@ -850,7 +855,7 @@ static enum bisect_error check_merge_bases(int rev_nr, struct commit **rev, int\n \t\t\thandle_skipped_merge_base(mb);\n \t\t} else {\n \t\t\tprintf(_(\"Bisecting: a merge base must be tested\\n\"));\n-\t\t\tres = bisect_checkout(mb, no_checkout);\n+\t\t\tres = bisect_checkout(mb, no_checkout, 0);\n \t\t\tif (!res)\n \t\t\t\t/* indicate early success */\n \t\t\t\tres = BISECT_INTERNAL_SUCCESS_MERGE_BASE;\n@@ -1002,7 +1007,7 @@ void read_bisect_terms(const char **read_bad, const char **read_good)\n  * the end of bisect_helper::cmd_bisect__helper() helps bypassing\n  * all the code related to finding a commit to test.\n  */\n-enum bisect_error bisect_next_all(struct repository *r, const char *prefix)\n+enum bisect_error bisect_next_all(struct repository *r, const char *prefix, int force_checkout)\n {\n \tstruct strvec rev_argv = STRVEC_INIT;\n \tstruct rev_info revs = REV_INFO_INIT;\n@@ -1104,7 +1109,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)\n \t/* Clean up objects used, as they will be reused. */\n \trepo_clear_commit_marks(r, ALL_REV_FLAGS);\n \n-\tres = bisect_checkout(bisect_rev, no_checkout);\n+\tres = bisect_checkout(bisect_rev, no_checkout, force_checkout);\n cleanup:\n \trelease_revisions(&revs);\n \tstrvec_clear(&rev_argv);\ndiff --git a/bisect.h b/bisect.h\nindex ee3fd65f3bd..6f972365faa 100644\n--- a/bisect.h\n+++ b/bisect.h\n@@ -71,7 +71,7 @@ struct bisect_state {\n \tunsigned int nr_bad;\n };\n \n-enum bisect_error bisect_next_all(struct repository *r, const char *prefix);\n+enum bisect_error bisect_next_all(struct repository *r, const char *prefix, int force_checkout);\n \n int estimate_bisect_steps(int all);\n \n@@ -80,6 +80,6 @@ void read_bisect_terms(const char **bad, const char **good);\n int bisect_clean_state(void);\n \n enum bisect_error bisect_checkout(const struct object_id *bisect_rev,\n-\t\t\t\t  int no_checkout);\n+\t\t\t\t  int no_checkout, int force_checkout);\n \n #endif\ndiff --git a/builtin/bisect.c b/builtin/bisect.c\nindex 47fcce59ff7..99c16d57942 100644\n--- a/builtin/bisect.c\n+++ b/builtin/bisect.c\n@@ -29,7 +29,7 @@ static GIT_PATH_FUNC(git_path_bisect_run, \"BISECT_RUN\")\n \t   \"    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]\" \\\n \t   \"    [<pathspec>...]\")\n #define BUILTIN_GIT_BISECT_STATE_USAGE \\\n-\tN_(\"git bisect (good|bad) [<rev>...]\")\n+\tN_(\"git bisect (good|bad) [-f] [<rev>...]\")\n #define BUILTIN_GIT_BISECT_TERMS_USAGE \\\n \t\"git bisect terms [--term-good | --term-bad]\"\n #define BUILTIN_GIT_BISECT_SKIP_USAGE \\\n@@ -45,7 +45,7 @@ static GIT_PATH_FUNC(git_path_bisect_run, \"BISECT_RUN\")\n #define BUILTIN_GIT_BISECT_LOG_USAGE \\\n \t\"git bisect log\"\n #define BUILTIN_GIT_BISECT_RUN_USAGE \\\n-\tN_(\"git bisect run <cmd> [<arg>...]\")\n+\tN_(\"git bisect run [-f] <cmd> [<arg>...]\")\n \n static const char * const git_bisect_usage[] = {\n \tBUILTIN_GIT_BISECT_START_USAGE,\n@@ -651,7 +651,7 @@ static int bisect_successful(struct bisect_terms *terms)\n \treturn res;\n }\n \n-static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix)\n+static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix, int force_checkout)\n {\n \tenum bisect_error res;\n \n@@ -662,7 +662,7 @@ static enum bisect_error bisect_next(struct bisect_terms *terms, const char *pre\n \t\treturn BISECT_FAILED;\n \n \t/* Perform all bisection computation */\n-\tres = bisect_next_all(the_repository, prefix);\n+\tres = bisect_next_all(the_repository, prefix, force_checkout);\n \n \tif (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {\n \t\tres = bisect_successful(terms);\n@@ -674,14 +674,14 @@ static enum bisect_error bisect_next(struct bisect_terms *terms, const char *pre\n \treturn res;\n }\n \n-static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)\n+static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix, int force_checkout)\n {\n \tif (bisect_next_check(terms, NULL)) {\n \t\tbisect_print_status(terms);\n \t\treturn BISECT_OK;\n \t}\n \n-\treturn bisect_next(terms, prefix);\n+\treturn bisect_next(terms, prefix, force_checkout);\n }\n \n static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,\n@@ -875,7 +875,7 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,\n \tif (res)\n \t\treturn res;\n \n-\tres = bisect_auto_next(terms, NULL);\n+\tres = bisect_auto_next(terms, NULL, 0);\n \tif (!is_bisect_success(res))\n \t\tbisect_clean_state();\n \treturn res;\n@@ -917,7 +917,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,\n \t\t\t\t      const char **argv)\n {\n \tconst char *state;\n-\tint i, verify_expected = 1;\n+\tint i, force_checkout = 0, verify_expected = 1;\n \tstruct object_id oid, expected;\n \tstruct oid_array revs = OID_ARRAY_INIT;\n \n@@ -934,6 +934,13 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,\n \n \targv++;\n \targc--;\n+\n+\tif (argc > 0 && (!strcmp(argv[0], \"--force\") || !strcmp(argv[0], \"-f\"))) {\n+\t\tforce_checkout = 1;\n+\t\targv++;\n+\t\targc--;\n+\t}\n+\n \tif (argc > 1 && !strcmp(state, terms->term_bad))\n \t\treturn error(_(\"'git bisect %s' can take only one argument.\"), terms->term_bad);\n \n@@ -989,7 +996,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,\n \t}\n \n \toid_array_clear(&revs);\n-\treturn bisect_auto_next(terms, NULL);\n+\treturn bisect_auto_next(terms, NULL, force_checkout);\n }\n \n static enum bisect_error bisect_log(void)\n@@ -1078,7 +1085,7 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f\n \tif (res)\n \t\treturn BISECT_FAILED;\n \n-\treturn bisect_auto_next(terms, NULL);\n+\treturn bisect_auto_next(terms, NULL, 0);\n }\n \n static enum bisect_error bisect_skip(struct bisect_terms *terms, int argc,\n@@ -1173,7 +1180,7 @@ static int do_bisect_run(const char *command)\n \treturn run_command(&cmd);\n }\n \n-static int verify_good(const struct bisect_terms *terms, const char *command)\n+static int verify_good(const struct bisect_terms *terms, const char *command, int force_checkout)\n {\n \tint rc;\n \tenum bisect_error res;\n@@ -1189,13 +1196,13 @@ static int verify_good(const struct bisect_terms *terms, const char *command)\n \tif (read_ref(no_checkout ? \"BISECT_HEAD\" : \"HEAD\", &current_rev))\n \t\treturn -1;\n \n-\tres = bisect_checkout(&good_rev, no_checkout);\n+\tres = bisect_checkout(&good_rev, no_checkout, force_checkout);\n \tif (res != BISECT_OK)\n \t\treturn -1;\n \n \trc = do_bisect_run(command);\n \n-\tres = bisect_checkout(&current_rev, no_checkout);\n+\tres = bisect_checkout(&current_rev, no_checkout, force_checkout);\n \tif (res != BISECT_OK)\n \t\treturn -1;\n \n@@ -1209,6 +1216,7 @@ static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)\n \tconst char *new_state;\n \tint temporary_stdout_fd, saved_stdout;\n \tint is_first_run = 1;\n+\tint force_checkout = 0;\n \n \tif (bisect_next_check(terms, NULL))\n \t\treturn BISECT_FAILED;\n@@ -1218,8 +1226,14 @@ static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)\n \t\treturn BISECT_FAILED;\n \t}\n \n+\tif (argc > 0 && (!strcmp(argv[0], \"--force\") || !strcmp(argv[0], \"-f\"))) {\n+\t\tforce_checkout = 1;\n+\t\targv++;\n+\t\targc--;\n+\t}\n \tsq_quote_argv(&command, argv);\n \tstrbuf_ltrim(&command);\n+\n \twhile (1) {\n \t\tres = do_bisect_run(command.buf);\n \n@@ -1231,7 +1245,7 @@ static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)\n \t\t * missing or non-executable script.\n \t\t */\n \t\tif (is_first_run && (res == 126 || res == 127)) {\n-\t\t\tint rc = verify_good(terms, command.buf);\n+\t\t\tint rc = verify_good(terms, command.buf, force_checkout);\n \t\t\tis_first_run = 0;\n \t\t\tif (rc < 0 || 128 <= rc) {\n \t\t\t\terror(_(\"unable to verify %s on good\"\n@@ -1271,7 +1285,11 @@ static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)\n \t\tsaved_stdout = dup(1);\n \t\tdup2(temporary_stdout_fd, 1);\n \n-\t\tres = bisect_state(terms, 1, &new_state);\n+\t\tif (force_checkout) {\n+\t\t\tres = bisect_state(terms, 2, (const char *[]){ new_state, \"--force\" });\n+\t\t} else {\n+\t\t\tres = bisect_state(terms, 1, &new_state);\n+\t\t}\n \n \t\tfflush(stdout);\n \t\tdup2(saved_stdout, 1);\n@@ -1342,7 +1360,7 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref\n \t\treturn error(_(\"'%s' requires 0 arguments\"),\n \t\t\t     \"git bisect next\");\n \tget_terms(&terms);\n-\tres = bisect_next(&terms, prefix);\n+\tres = bisect_next(&terms, prefix, 0);\n \tfree_terms(&terms);\n \treturn res;\n }\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 561080bf240..eb17cc58a16 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -1259,4 +1259,113 @@ test_expect_success 'verify correct error message' '\n \tgrep \"git bisect good.*exited with error code\" error\n '\n \n+test_expect_success 'bisect dirty, explicit ref' '\n+\ttest_when_finished \"git bisect reset\" &&\n+    add_line_into_file \"Commit 1\" file &&\n+    add_line_into_file \"Commit 2\" file &&\n+    add_line_into_file \"Commit 3\" file &&\n+\tgit bisect start &&\n+\tgit bisect bad HEAD &&\n+\techo \"modified state\" >file &&\n+\ttest_when_finished \"git checkout -- file\" &&\n+\ttest_must_fail git bisect good HEAD~2\n+'\n+\n+test_expect_success 'bisect dirty good force, explicit ref' '\n+\ttest_when_finished \"git bisect reset\" &&\n+    add_line_into_file \"Commit 1\" file &&\n+    add_line_into_file \"Commit 2\" file &&\n+    add_line_into_file \"Commit 3\" file &&\n+\tgit bisect start &&\n+\tgit bisect bad HEAD &&\n+\techo \"modified state\" >file &&\n+\ttest_when_finished \"git checkout -- file\" &&\n+\tgit bisect good --force HEAD~2\n+'\n+\n+test_expect_success 'bisect dirty, implicit ref' '\n+\ttest_when_finished \"git bisect reset\" &&\n+    add_line_into_file \"Commit 1\" file &&\n+    add_line_into_file \"Commit 2\" file &&\n+    add_line_into_file \"Commit 3\" file &&\n+    add_line_into_file \"Commit 4\" file &&\n+    add_line_into_file \"Commit 5\" file &&\n+\tgit bisect start &&\n+\tgit bisect bad HEAD &&\n+\tgit bisect good HEAD~4 &&\n+\techo \"modified state\" >file &&\n+\ttest_when_finished \"git checkout -- file\" &&\n+\ttest_must_fail git bisect good &&\n+\ttest_must_fail git bisect bad\n+'\n+\n+test_expect_success 'bisect dirty good force, implicit ref' '\n+\ttest_when_finished \"git bisect reset\" &&\n+    add_line_into_file \"Commit 1\" file &&\n+    add_line_into_file \"Commit 2\" file &&\n+    add_line_into_file \"Commit 3\" file &&\n+    add_line_into_file \"Commit 4\" file &&\n+    add_line_into_file \"Commit 5\" file &&\n+\tgit bisect start &&\n+\tgit bisect bad HEAD &&\n+\tgit bisect good HEAD~4 &&\n+\techo \"modified state\" >file &&\n+\ttest_when_finished \"git checkout -- file\" &&\n+\tgit bisect good --force\n+'\n+\n+test_expect_success 'bisect dirty bad force, implicit ref' '\n+\ttest_when_finished \"git bisect reset\" &&\n+    add_line_into_file \"Commit 1\" file &&\n+    add_line_into_file \"Commit 2\" file &&\n+    add_line_into_file \"Commit 3\" file &&\n+    add_line_into_file \"Commit 4\" file &&\n+    add_line_into_file \"Commit 5\" file &&\n+\tgit bisect start &&\n+\tgit bisect bad HEAD &&\n+\tgit bisect good HEAD~4 &&\n+\techo \"modified state\" >file &&\n+\ttest_when_finished \"git checkout -- file\" &&\n+\tgit bisect bad --force\n+'\n+\n+test_expect_success 'bisect run dirty' '\n+\ttest_when_finished \"git bisect reset\" &&\n+\ttest_when_finished \"git checkout -- file\" &&\n+    add_line_into_file \"Bisect run 1\" file &&\n+    add_line_into_file \"Bisect run 2\" file &&\n+    add_line_into_file \"Bisect run 3\" file &&\n+    add_line_into_file \"Bisect run 4\" file &&\n+    add_line_into_file \"Bisect run 5\" file &&\n+\twrite_script test_script.sh <<-\\EOF &&\n+\t! echo \"modified state\" >file\n+\t! grep \"Bisect run 3\" || exit 126 >/dev/null\n+\tEOF\n+\tgit bisect start &&\n+\tgit bisect bad HEAD &&\n+\tgit bisect good HEAD~4 &&\n+\ttest_must_fail git bisect run ./test_script.sh\n+'\n+\n+test_expect_success 'bisect run dirty force' '\n+\ttest_when_finished \"git bisect reset\" &&\n+\ttest_when_finished \"git checkout -- file\" &&\n+    add_line_into_file \"Bisect run 1\" file &&\n+    add_line_into_file \"Bisect run 2\" file &&\n+    add_line_into_file \"Bisect run 3\" file &&\n+    add_line_into_file \"Bisect run 4\" file &&\n+    add_line_into_file \"Bisect run 5\" file &&\n+\twrite_script test_script.sh <<-\\EOF &&\n+\t! echo \"modified state\" >file\n+\t! grep \"Bisect run 3\" || exit 126 >/dev/null\n+\tEOF\n+\tHASH5=$(git rev-parse --verify HEAD) &&\n+\tgit bisect start &&\n+\tgit bisect bad HEAD &&\n+\tgit bisect good HEAD~4 &&\n+\techo \"doing run\\n\" &&\n+\tgit bisect run --force ./test_script.sh >my_bisect_log.txt &&\n+\tgrep \"$HASH5 is the first bad commit\" my_bisect_log.txt\n+'\n+\n test_done\n\nbase-commit: a26002b62827b89a19b1084bd75d9371d565d03c\n-- \ngitgitgadget\n"},{"id":"486895","messageId":"xmqqmst4ykqh.fsf@gitster.g","threadId":"60744","inReplyTo":"pull.1641.git.git.1705302307639.gitgitgadget@gmail.com","subject":"Re: [PATCH] bisect: add --force flag to force checkout","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-01-16T22:30:30Z","receivedAt":"2024-01-16T22:30:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Kevin Wang via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> From: Kevin Wang <kevmo314@gmail.com>\n>\n> Adds a `--force`/`-f` flag to `git bisect good/bad` and `git bisect run` to\n> force a checkout. Currently, if the repository state adds any local changes\n> the user must manually reset the repository state before moving to the next\n> bisection step. This can happen with package lock files or log output data,\n> for example. With this change, a developer can run `git bisect run --force`\n> to automatically reset the repository state after each evaluation. The flag\n> is also supported as `git bisect (good|bad) --force` as well.\n\nThe usual way to compose a log message is to\n\n - Give an observation on how the current system work in the present\n   tense (so no need to say \"Currently X is Y\", just \"X is Y\"), and\n   discuss what you perceive as a problem in it.\n\n - Propose a solution (optional---often, problem description\n   trivially leads to an obvious solution in reader's minds).\n\n - Give commands to the make codebase \"like so\".\n\nin this order.\n\nTo those who have been intimately following the discussion, it often\nis understandable without both, but we are not writing for those who\nreview the patches.  We are writing for future readers who are not\naware of the review discussion we have on list, so we should give\nsomething to prepare them by setting the stage and stating the\nobjective first, before going into how the patch solved it.\n\nHaving said all that.\n\nI highly doubt that this patch is a good idea.  If your \"bisect run\"\nscript needs to update something in the working tree before it runs\nsome test, the script is in a much better place than Git, which is\nunaware of what your run script is doing, to prepare the working\ntree into pristine state.  The best Git would be able to do would be\nto \"reset --hard\", but that will lose local modifications that are\ndeliberately there and has nothing to do with what your run script\ndid.\n\nAdding some description to the documentation of \"bisect run\" and\nteaching readers a common trick of structuring their run script\nbetter might be a more productive approach, I would have to say.\nFor example, when I bisect some old code, I may have to apply a\ntemporary patch to some of the sources to get them compile with more\nrecent compilers (I usually do this with a cherry-picking of a local\nfixup).  So my \"bisect run\" script might go like so:\n\n    #!/bin/sh\n    # bisect run\n\n    git apply local-fixup || exit 125\n    make test\n    status=$?\n    make distclean\n    git apply -R local-fixup || exit 125\n    exit $status\n\nThat is, I'd apply some local fix-up to the working tree files\nbefore running tests, and once done, I revert the local fix-up\nand exit from the run script with the exit status of the test\nI wanted to perform.\n    \nThis way, I can keep other local changes (things like changes to\ndocumentation files that I am working on, which has nothing to do\nwith the problem I am bisecting but I know they do not interfere)\nwithout wiping them away with a sledgehammer \"reset --hard\".  Your\n\"bisect good/bad -f\" sounds like the sledgehammer approach to me.\n\nThanks.\n"}]}