{"thread":{"id":"65508","subject":"[PATCH v3 1/2] bisect: use selected alternate terms in status output","startedAt":"2026-04-17T17:06:04Z","lastAt":"2026-04-17T19:50:53Z","messageCount":4,"participants":["Jonas Rebmann","Junio C Hamano"],"isPatch":true,"patchVersion":3,"patchTotal":2},"messages":[{"id":"541830","messageId":"20260417-bisect-terms-v3-1-d659fa547261@schlaraffenlan.de","threadId":"65508","inReplyTo":"20260417-bisect-terms-v3-0-d659fa547261@schlaraffenlan.de","subject":"[PATCH v3 1/2] bisect: use selected alternate terms in status output","fromName":"Jonas Rebmann","fromEmail":"kernel@schlaraffenlan.de","sentAt":"2026-04-17T16:48:30Z","receivedAt":"2026-04-17T17:06:04Z","isPatch":true,"body":"Alternate bisect terms are helpful when the terms \"good\" and \"bad\" are\nconfusing such as when bisecting for the resolution of an issue (the\nfirst good commit) rather than the introduction of a regression.\n\nThese terms must be used when marking a commit (e.g. `git bisect new`),\nthey will be used in reference names (e.g. refs/bisect/new) and they are\nused in parts of git's log output such as \"<sha> was both old and new\"\nin git bisect skip's output.\n\nHowever, hardcoded \"good\"/\"bad\" terms are still used in a few status\nmessages and can cause confusion about the status of the bisect such as:\n\n  $ git bisect old\n  [sha] is the first bad commit\n\nor about the required action such as:\n\n  status: waiting for bad commit, 1 good commit known\n  $ git bisect bad\n  error: Invalid command: you're currently in a new/old bisect\n  fatal: unknown command: 'bad'\n\nThis commit updates all remaining output messages which use hardcoded\n\"good\" and \"bad\" terms to use the selected terms consistently across the\nbisect output and adds tests.\n\nSigned-off-by: Jonas Rebmann <kernel@schlaraffenlan.de>\n---\n builtin/bisect.c            | 23 +++++++++++++----------\n t/t6030-bisect-porcelain.sh | 38 +++++++++++++++++++++++++-------------\n 2 files changed, 38 insertions(+), 23 deletions(-)\n\ndiff --git a/builtin/bisect.c b/builtin/bisect.c\nindex 4520e585d0..2b44911c0b 100644\n--- a/builtin/bisect.c\n+++ b/builtin/bisect.c\n@@ -465,13 +465,16 @@ static void bisect_print_status(const struct bisect_terms *terms)\n \t\treturn;\n \n \tif (!state.nr_good && !state.nr_bad)\n-\t\tbisect_log_printf(_(\"status: waiting for both good and bad commits\\n\"));\n+\t\tbisect_log_printf(_(\"status: waiting for both '%s' and '%s' commits\\n\"),\n+\t\t\t\t  terms->term_good, terms->term_bad);\n \telse if (state.nr_good)\n-\t\tbisect_log_printf(Q_(\"status: waiting for bad commit, %d good commit known\\n\",\n-\t\t\t\t     \"status: waiting for bad commit, %d good commits known\\n\",\n-\t\t\t\t     state.nr_good), state.nr_good);\n+\t\tbisect_log_printf(Q_(\"status: waiting for '%s' commit, %d '%s' commit known\\n\",\n+\t\t\t\t     \"status: waiting for '%s' commit, %d '%s' commits known\\n\",\n+\t\t\t\t     state.nr_good),\n+\t\t\t\t  terms->term_bad, state.nr_good, terms->term_good);\n \telse\n-\t\tbisect_log_printf(_(\"status: waiting for good commit(s), bad commit known\\n\"));\n+\t\tbisect_log_printf(_(\"status: waiting for '%s' commit(s), '%s' commit known\\n\"),\n+\t\t\t\t  terms->term_good, terms->term_bad);\n }\n \n static int bisect_next_check(const struct bisect_terms *terms,\n@@ -1262,14 +1265,14 @@ static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)\n \t\t\tint rc = verify_good(terms, command.buf);\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-\t\t\t\t\t\" revision\"), command.buf);\n+\t\t\t\terror(_(\"unable to verify %s on %s revision\"),\n+\t\t\t\t      command.buf, terms->term_good);\n \t\t\t\tres = BISECT_FAILED;\n \t\t\t\tbreak;\n \t\t\t}\n \t\t\tif (rc == res) {\n-\t\t\t\terror(_(\"bogus exit code %d for good revision\"),\n-\t\t\t\t      rc);\n+\t\t\t\terror(_(\"bogus exit code %d for %s revision\"),\n+\t\t\t\t      rc, terms->term_good);\n \t\t\t\tres = BISECT_FAILED;\n \t\t\t\tbreak;\n \t\t\t}\n@@ -1314,7 +1317,7 @@ static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)\n \t\t\tputs(_(\"bisect run success\"));\n \t\t\tres = BISECT_OK;\n \t\t} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {\n-\t\t\tputs(_(\"bisect found first bad commit\"));\n+\t\t\tprintf(_(\"bisect found first %s commit\\n\"), terms->term_bad);\n \t\t\tres = BISECT_OK;\n \t\t} else if (res) {\n \t\t\terror(_(\"bisect run failed: 'git bisect %s'\"\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 1ba9ca219e..3751e5cc8b 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -1077,12 +1077,14 @@ test_expect_success 'bisect terms shows good/bad after start' '\n \n test_expect_success 'bisect start with one term1 and term2' '\n \tgit bisect reset &&\n-\tgit bisect start --term-old term2 --term-new term1 &&\n-\tgit bisect term2 $HASH1 &&\n+\tgit bisect start --term-old term2 --term-new term1 >bisect_result &&\n+\ttest_grep \"status: waiting for both '\\''term2'\\'' and '\\''term1'\\'' commits\" bisect_result &&\n+\tgit bisect term2 $HASH1 >bisect_result &&\n+\ttest_grep \"status: waiting for '\\''term1'\\'' commit, 1 '\\''term2'\\'' commit known\" bisect_result &&\n \tgit bisect term1 $HASH4 &&\n \tgit bisect term1 &&\n \tgit bisect term1 >bisect_result &&\n-\tgrep \"$HASH2 is the first term1 commit\" bisect_result &&\n+\ttest_grep \"$HASH2 is the first term1 commit\" bisect_result &&\n \tgit bisect log >log_to_replay.txt &&\n \tgit bisect reset\n '\n@@ -1103,6 +1105,16 @@ test_expect_success 'bisect replay with term1 and term2' '\n \tgit bisect reset\n '\n \n+test_expect_success 'bisect run term1 term2' '\n+\tgit bisect reset &&\n+\tgit bisect start --term-new term1 --term-old term2 $HASH4 $HASH1 &&\n+\tgit bisect term1 &&\n+\tgit bisect run false >bisect_result &&\n+\ttest_grep \"bisect found first term1 commit\" bisect_result &&\n+\tgit bisect log >log_to_replay.txt &&\n+\tgit bisect reset\n+'\n+\n test_expect_success 'bisect start term1 term2' '\n \tgit bisect reset &&\n \tgit bisect start --term-new term1 --term-old term2 $HASH4 $HASH1 &&\n@@ -1224,29 +1236,29 @@ test_expect_success 'bisect visualize with a filename with dash and space' '\n test_expect_success 'bisect state output with multiple good commits' '\n \tgit bisect reset &&\n \tgit bisect start >output &&\n-\tgrep \"waiting for both good and bad commits\" output &&\n+\tgrep \"waiting for both '\\''good'\\'' and '\\''bad'\\'' commits\" output &&\n \tgit bisect log >output &&\n-\tgrep \"waiting for both good and bad commits\" output &&\n+\tgrep \"waiting for both '\\''good'\\'' and '\\''bad'\\'' commits\" output &&\n \tgit bisect good \"$HASH1\" >output &&\n-\tgrep \"waiting for bad commit, 1 good commit known\" output &&\n+\tgrep \"waiting for '\\''bad'\\'' commit, 1 '\\''good'\\'' commit known\" output &&\n \tgit bisect log >output &&\n-\tgrep \"waiting for bad commit, 1 good commit known\" output &&\n+\tgrep \"waiting for '\\''bad'\\'' commit, 1 '\\''good'\\'' commit known\" output &&\n \tgit bisect good \"$HASH2\" >output &&\n-\tgrep \"waiting for bad commit, 2 good commits known\" output &&\n+\tgrep \"waiting for '\\''bad'\\'' commit, 2 '\\''good'\\'' commits known\" output &&\n \tgit bisect log >output &&\n-\tgrep \"waiting for bad commit, 2 good commits known\" output\n+\tgrep \"waiting for '\\''bad'\\'' commit, 2 '\\''good'\\'' commits known\" output\n '\n \n test_expect_success 'bisect state output with bad commit' '\n \tgit bisect reset &&\n \tgit bisect start >output &&\n-\tgrep \"waiting for both good and bad commits\" output &&\n+\tgrep \"waiting for both '\\''good'\\'' and '\\''bad'\\'' commits\" output &&\n \tgit bisect log >output &&\n-\tgrep \"waiting for both good and bad commits\" output &&\n+\tgrep \"waiting for both '\\''good'\\'' and '\\''bad'\\'' commits\" output &&\n \tgit bisect bad \"$HASH4\" >output &&\n-\tgrep -F \"waiting for good commit(s), bad commit known\" output &&\n+\tgrep -F \"waiting for '\\''good'\\'' commit(s), '\\''bad'\\'' commit known\" output &&\n \tgit bisect log >output &&\n-\tgrep -F \"waiting for good commit(s), bad commit known\" output\n+\tgrep -F \"waiting for '\\''good'\\'' commit(s), '\\''bad'\\'' commit known\" output\n '\n \n test_expect_success 'verify correct error message' '\n\n-- \n2.53.0\n\n"},{"id":"541832","messageId":"20260417-bisect-terms-v3-2-d659fa547261@schlaraffenlan.de","threadId":"65508","inReplyTo":"20260417-bisect-terms-v3-0-d659fa547261@schlaraffenlan.de","subject":"[PATCH v3 2/2] rev-parse: use selected alternate terms to look up refs","fromName":"Jonas Rebmann","fromEmail":"kernel@schlaraffenlan.de","sentAt":"2026-04-17T16:48:31Z","receivedAt":"2026-04-17T17:25:56Z","isPatch":true,"body":"git rev-parse --bisect does not work when alternate bisect terms are\nused, simply listing no revisions at all.\n\nThis is because a such bisect using e.g. \"old\" and \"new\" in place of\n\"good\" and \"bad\" will name refs \"refs/bisect/old\" (or new) accordingly\nso the hardcoded \"refs/bisect/bad\" (and good) yields no results in a\nbisect using alternate terms.\n\nUse the current bisect_terms to make rev-parse --bisect work in an\nalternate term bisect.\n\nSigned-off-by: Jonas Rebmann <kernel@schlaraffenlan.de>\n---\n builtin/rev-parse.c  | 15 +++++++++++++--\n t/t1500-rev-parse.sh | 25 +++++++++++++++++++++++++\n 2 files changed, 38 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 218b5f34d6..7531edae9e 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -10,6 +10,7 @@\n #include \"builtin.h\"\n \n #include \"abspath.h\"\n+#include \"bisect.h\"\n #include \"config.h\"\n #include \"commit.h\"\n #include \"environment.h\"\n@@ -940,13 +941,23 @@ int cmd_rev_parse(int argc,\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--bisect\")) {\n+\t\t\t\tchar *prefix;\n+\t\t\t\tchar *term_bad = NULL;\n+\t\t\t\tchar *term_good = NULL;\n \t\t\t\tstruct refs_for_each_ref_options opts = { 0 };\n-\t\t\t\topts.prefix = \"refs/bisect/bad\";\n+\t\t\t\tread_bisect_terms(&term_bad, &term_good);\n+\t\t\t\tprefix = xstrfmt(\"refs/bisect/%s\", term_bad);\n+\t\t\t\topts.prefix = prefix;\n \t\t\t\trefs_for_each_ref_ext(get_main_ref_store(the_repository),\n \t\t\t\t\t\t      show_reference, NULL, &opts);\n-\t\t\t\topts.prefix = \"refs/bisect/good\";\n+\t\t\t\tfree(prefix);\n+\t\t\t\tprefix = xstrfmt(\"refs/bisect/%s\", term_good);\n+\t\t\t\topts.prefix = prefix;\n \t\t\t\trefs_for_each_ref_ext(get_main_ref_store(the_repository),\n \t\t\t\t\t\t      anti_reference, NULL, &opts);\n+\t\t\t\tfree(prefix);\n+\t\t\t\tfree(term_good);\n+\t\t\t\tfree(term_bad);\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (opt_with_value(arg, \"--branches\", &arg)) {\ndiff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh\nindex 98c5a772bd..38067d95f7 100755\n--- a/t/t1500-rev-parse.sh\n+++ b/t/t1500-rev-parse.sh\n@@ -337,6 +337,31 @@ test_expect_success 'rev-parse --bisect includes bad, excludes good' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'rev-parse --bisect works with alternate terms' '\n+\ttest_commit_bulk 6 &&\n+\n+\tgit bisect start --term-old=known --term-new=curious &&\n+\n+\tgit update-ref refs/bisect/curious-1 HEAD~1 &&\n+\tgit update-ref refs/bisect/bad HEAD~2 &&\n+\tgit update-ref refs/bisect/curious-3 HEAD~3 &&\n+\tgit update-ref refs/bisect/known-3 HEAD~3 &&\n+\tgit update-ref refs/bisect/curious-4 HEAD~4 &&\n+\tgit update-ref refs/bisect/good HEAD~4 &&\n+\n+\t# Note: refs/bisect/bad and refs/bisect/goood should be ignored because this\n+\t# is a bisect with custom terms (known/curious)\n+\tcat >expect <<-EOF &&\n+\trefs/bisect/curious-1\n+\trefs/bisect/curious-3\n+\trefs/bisect/curious-4\n+\t^refs/bisect/known-3\n+\tEOF\n+\n+\tgit rev-parse --symbolic-full-name --bisect >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success '--short= truncates to the actual hash length' '\n \tgit rev-parse HEAD >expect &&\n \tgit rev-parse --short=100 HEAD >actual &&\n\n-- \n2.53.0\n\n"},{"id":"541833","messageId":"20260417-bisect-terms-v3-0-d659fa547261@schlaraffenlan.de","threadId":"65508","inReplyTo":null,"subject":"[PATCH v3 0/2] Avoid hardcoded \"good\"/\"bad\" bisect terms","fromName":"Jonas Rebmann","fromEmail":"kernel@schlaraffenlan.de","sentAt":"2026-04-17T16:48:29Z","receivedAt":"2026-04-17T18:07:53Z","isPatch":true,"body":"While checking whether all output messages of git bisect were covered by\n[PATCH 1/2] bisect: use selected alternate terms in status output I\nfound hardcoded good/bad refs leading to incompatibility of git\nrev-parse --bisect with alternate bisect run terms. This is addressed by\n[PATCH 2/2] rev-parse: use selected alternate terms to look up refs\n\nSigned-off-by: Jonas Rebmann <kernel@schlaraffenlan.de>\n---\nChanges in v3:\n- when referencing newly introduced terms, reference them in single\n  quotes (Thanks, Phillip)\n- Prefer test_grep over grep in updated Tests (Thanks, Phillip)\n- Improve commit messages (Thanks, Phillip)\n- Don't leak memory after read_bisect_terms() (Thanks, Phillip)\n- Don't leak memory after xstrfmt() (Thanks, Junio)\n- Add test case to patch 2/2\n- Link to v2: https://patch.msgid.link/20260323-bisect-terms-v2-0-8d6bdb2c9c7e@schlaraffenlan.de\n\nChanges in v2:\n- Improve commit message\n- Add tests\n- Include second patch for hardcoded good/bad in rev-parse\n- Link to v1: https://lore.kernel.org/r/20260320-bisect-terms-v1-1-c30c9540542a@schlaraffenlan.de\n\n---\nJonas Rebmann (2):\n      bisect: use selected alternate terms in status output\n      rev-parse: use selected alternate terms to look up refs\n\n builtin/bisect.c            | 23 +++++++++++++----------\n builtin/rev-parse.c         | 15 +++++++++++++--\n t/t1500-rev-parse.sh        | 25 +++++++++++++++++++++++++\n t/t6030-bisect-porcelain.sh | 38 +++++++++++++++++++++++++-------------\n 4 files changed, 76 insertions(+), 25 deletions(-)\n---\nbase-commit: 1b296b0f55885fa8fc649c4b31c37f3d86f3f9cf\nchange-id: 20260320-bisect-terms-76036676769c\n\nBest regards,\n--  \nJonas Rebmann <kernel@schlaraffenlan.de>\n\n"},{"id":"541837","messageId":"xmqqjyu5weli.fsf@gitster.g","threadId":"65508","inReplyTo":"20260417-bisect-terms-v3-1-d659fa547261@schlaraffenlan.de","subject":"Re: [PATCH v3 1/2] bisect: use selected alternate terms in status output","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-04-17T19:50:49Z","receivedAt":"2026-04-17T19:50:53Z","isPatch":true,"body":"Jonas Rebmann <kernel@schlaraffenlan.de> writes:\n\n>  \tif (!state.nr_good && !state.nr_bad)\n> -\t\tbisect_log_printf(_(\"status: waiting for both good and bad commits\\n\"));\n> +\t\tbisect_log_printf(_(\"status: waiting for both '%s' and '%s' commits\\n\"),\n> +\t\t\t\t  terms->term_good, terms->term_bad);\n\nI think this was new in v2 (which I somehow did not pick up).  Good\nfinding, but not limited to this one, I wonder how these custom\nterms interact with localization.  The 'quotes' around these terms\ndo help by hinting that they are not a normal adjectives given to\nthe noun 'commits', so that might be good enough, but that still\nassumes that the .term_good and .term_bad, even when they are not\n'good' and 'bad', are good adjectives that can apply to 'commits'.\nI'd expect in most use cases that would hold, but the command does\nnot prevent you from calling more recent ones 'dog commits' and the\nones before the transition point 'cat commits' ;-).\n\nOf course, rephrasing the above to\n\n\twaiting for both commit(s) marked as '%s' and as '%s'\n\nwould be ultra-awkward, even if it may be the safest.  So I dunno.\n\n> -\t\t\t\terror(_(\"unable to verify %s on good\"\n> -\t\t\t\t\t\" revision\"), command.buf);\n> +\t\t\t\terror(_(\"unable to verify %s on %s revision\"),\n> +\t\t\t\t      command.buf, terms->term_good);\n\nAnd from that point of view, this unquoted \"ON good REVISION\" might\nbecome a problem, because it asssumes that .term_good would be\nreadable as an adjective given to the noun 'revision', which might\nnot hold true even without translation.  The command.buf contains a\ncommand with its arguments, and .term_good contains the custom term.\nPerhaps both should be placed in '%s' quotes?\n\n>  \t\t\t\tres = BISECT_FAILED;\n>  \t\t\t\tbreak;\n>  \t\t\t}\n>  \t\t\tif (rc == res) {\n> -\t\t\t\terror(_(\"bogus exit code %d for good revision\"),\n> -\t\t\t\t      rc);\n> +\t\t\t\terror(_(\"bogus exit code %d for %s revision\"),\n> +\t\t\t\t      rc, terms->term_good);\n\nDitto for quoting 'good' that is no longer a normal adjective that\nadorns the noun 'revision', in the context of a translated message.\n\n> @@ -1314,7 +1317,7 @@ static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)\n>  \t\t\tputs(_(\"bisect run success\"));\n>  \t\t\tres = BISECT_OK;\n>  \t\t} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {\n> -\t\t\tputs(_(\"bisect found first bad commit\"));\n> +\t\t\tprintf(_(\"bisect found first %s commit\\n\"), terms->term_bad);\n\nDitto for quoting 'bad' here.\n"}]}