{"thread":{"id":"42718","subject":"[RFC/PATCH 1/3] bisect--helper: `check_and_set_terms` shell function in C","startedAt":"2016-06-26T20:46:09Z","lastAt":"2016-06-26T20:46:22Z","messageCount":3,"participants":["Pranit Bauva"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"290203","messageId":"20160626204411.19919-1-pranit.bauva@gmail.com","threadId":"42718","inReplyTo":null,"subject":"[RFC/PATCH 1/3] bisect--helper: `check_and_set_terms` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-06-26T20:44:09Z","receivedAt":"2016-06-26T20:46:09Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Reimplement the `check_and_set_terms` shell function in C and add\n`check-and-set-terms` subcommand to `git bisect--helper` to call it from\ngit-bisect.sh\n\nUsing `--check-and-set-terms` subcommand is a temporary measure to port\nshell function in C so as to use the existing test suite. As more\nfunctions are ported, this subcommand will be retired and will be called\nby some other methods.\n\ncheck_and_set_terms() sets and receives two global variables namely\nTERM_GOOD and TERM_BAD in the shell script. Luckily the file BISECT_TERMS\nalso contains the value of those variables so its appropriate to evoke the\nmethod get_terms() after calling the subcommand so that it retrieves the\nvalue of TERM_GOOD and TERM_BAD from the file BISECT_TERMS. The two\nglobal variables are passed as arguments to the subcommand.\n\nAlso introduce bisect_terms_reinit() to release the previous memory of\nstruct bisect_terms and allocate new memory for it thus flushing out the\nprevious contents.\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\nThis series applies on top of my previous patch series[1].\n\n[1]: http://thread.gmane.org/gmane.comp.version-control.git/298263\n\n builtin/bisect--helper.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++-\n git-bisect.sh            | 36 ++++----------------------------\n 2 files changed, 56 insertions(+), 33 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex e946ba9..c387697 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -45,6 +45,13 @@ static int bisect_terms_release(struct bisect_terms *term)\n \treturn 0;\n }\n \n+static int bisect_terms_reinit(struct bisect_terms *term)\n+{\n+\tbisect_terms_release(term);\n+\tbisect_terms_init(term);\n+\treturn 0;\n+}\n+\n /*\n  * Check whether the string `term` belongs to the set of strings\n  * included in the variable arguments.\n@@ -254,6 +261,40 @@ static int bisect_write(const char *state, const char *rev,\n \treturn 0;\n }\n \n+static int check_and_set_terms(const char *cmd, struct bisect_terms *term)\n+{\n+\tif (one_of(cmd, \"skip\", \"start\", \"terms\", NULL))\n+\t\treturn 0;\n+\n+\tif (!is_empty_or_missing_file(git_path_bisect_write_terms()) &&\n+\t    strcmp(cmd, term->term_bad.buf) && strcmp(cmd, term->term_good.buf))\n+\t\treturn error(_(\"Invalid command: you're currently in a\"\n+\t\t\t\t\"'%s' '%s' bisect\"), term->term_bad.buf,\n+\t\t\t\tterm->term_good.buf);\n+\n+\tif (one_of(cmd, \"bad\", \"good\", NULL)) {\n+\t\tif (is_empty_or_missing_file(git_path_bisect_write_terms())) {\n+\t\t\tbisect_terms_reinit(term);\n+\t\t\tstrbuf_addstr(&term->term_bad, \"bad\");\n+\t\t\tstrbuf_addstr(&term->term_good, \"good\");\n+\t\t\treturn write_terms(term->term_bad.buf,\n+\t\t\t\t\t   term->term_good.buf);\n+\t\t}\n+\t}\n+\n+\tif (one_of(cmd, \"new\", \"old\", NULL)) {\n+\t\tif (is_empty_or_missing_file(git_path_bisect_write_terms())) {\n+\t\t\tbisect_terms_reinit(term);\n+\t\t\tstrbuf_addstr(&term->term_bad, \"new\");\n+\t\t\tstrbuf_addstr(&term->term_good, \"old\");\n+\t\t\treturn write_terms(term->term_bad.buf,\n+\t\t\t\t\t   term->term_good.buf);\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -262,7 +303,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tBISECT_CLEAN_STATE,\n \t\tBISECT_RESET,\n \t\tCHECK_EXPECTED_REVS,\n-\t\tBISECT_WRITE\n+\t\tBISECT_WRITE,\n+\t\tCHECK_AND_SET_TERMS\n \t} cmdmode = 0;\n \tint no_checkout = 0, res = 0;\n \tstruct option options[] = {\n@@ -278,6 +320,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"check for expected revs\"), CHECK_EXPECTED_REVS),\n \t\tOPT_CMDMODE(0, \"bisect-write\", &cmdmode,\n \t\t\t N_(\"write out the bisection state in BISECT_LOG\"), BISECT_WRITE),\n+\t\tOPT_CMDMODE(0, \"check-and-set-terms\", &cmdmode,\n+\t\t\t N_(\"check and set terms in a bisection state\"), CHECK_AND_SET_TERMS),\n \t\tOPT_BOOL(0, \"no-checkout\", &no_checkout,\n \t\t\t N_(\"update BISECT_HEAD instead of checking out the current commit\")),\n \t\tOPT_END()\n@@ -321,6 +365,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tstrbuf_addstr(&state.term_bad, argv[3]);\n \t\tres = bisect_write(argv[0], argv[1], &state, nolog);\n \t\tbreak;\n+\tcase CHECK_AND_SET_TERMS:\n+\t\tif (argc != 3)\n+\t\t\tdie(_(\"--check-and-set-terms requires 3 arguments\"));\n+\t\tstrbuf_addstr(&state.term_good, argv[1]);\n+\t\tstrbuf_addstr(&state.term_bad, argv[2]);\n+\t\tres = check_and_set_terms(argv[0], &state);\n+\t\tbreak;\n \tdefault:\n \t\tdie(\"BUG: unknown subcommand '%d'\", cmdmode);\n \t}\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex b9896a4..63ae742 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -239,7 +239,8 @@ bisect_skip() {\n bisect_state() {\n \tbisect_autostart\n \tstate=$1\n-\tcheck_and_set_terms $state\n+\tgit bisect--helper --check-and-set-terms $state $TERM_GOOD $TERM_BAD\n+\tget_terms\n \tcase \"$#,$state\" in\n \t0,*)\n \t\tdie \"$(gettext \"Please call 'bisect_state' with at least one argument.\")\" ;;\n@@ -390,7 +391,8 @@ bisect_replay () {\n \t\t\tcommand=\"$bisect\"\n \t\tfi\n \t\tget_terms\n-\t\tcheck_and_set_terms \"$command\"\n+\t\tgit bisect--helper --check-and-set-terms \"$command\" \"$TERM_GOOD\" \"$TERM_BAD\" || exit\n+\t\tget_terms\n \t\tcase \"$command\" in\n \t\tstart)\n \t\t\tcmd=\"bisect_start $rev\"\n@@ -480,36 +482,6 @@ get_terms () {\n \tfi\n }\n \n-check_and_set_terms () {\n-\tcmd=\"$1\"\n-\tcase \"$cmd\" in\n-\tskip|start|terms) ;;\n-\t*)\n-\t\tif test -s \"$GIT_DIR/BISECT_TERMS\" && test \"$cmd\" != \"$TERM_BAD\" && test \"$cmd\" != \"$TERM_GOOD\"\n-\t\tthen\n-\t\t\tdie \"$(eval_gettext \"Invalid command: you're currently in a \\$TERM_BAD/\\$TERM_GOOD bisect.\")\"\n-\t\tfi\n-\t\tcase \"$cmd\" in\n-\t\tbad|good)\n-\t\t\tif ! test -s \"$GIT_DIR/BISECT_TERMS\"\n-\t\t\tthen\n-\t\t\t\tTERM_BAD=bad\n-\t\t\t\tTERM_GOOD=good\n-\t\t\t\tgit bisect--helper --write-terms \"$TERM_BAD\" \"$TERM_GOOD\" || exit\n-\t\t\tfi\n-\t\t\t;;\n-\t\tnew|old)\n-\t\t\tif ! test -s \"$GIT_DIR/BISECT_TERMS\"\n-\t\t\tthen\n-\t\t\t\tTERM_BAD=new\n-\t\t\t\tTERM_GOOD=old\n-\t\t\t\tgit bisect--helper --write-terms \"$TERM_BAD\" \"$TERM_GOOD\" || exit\n-\t\t\tfi\n-\t\t\t;;\n-\t\tesac ;;\n-\tesac\n-}\n-\n bisect_voc () {\n \tcase \"$1\" in\n \tbad) echo \"bad|new\" ;;\n-- \n2.9.0\n\n"},{"id":"290204","messageId":"20160626204411.19919-2-pranit.bauva@gmail.com","threadId":"42718","inReplyTo":"20160626204411.19919-1-pranit.bauva@gmail.com","subject":"[RFC/PATCH 2/3] bisect--helper: `bisect_next_check` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-06-26T20:44:10Z","receivedAt":"2016-06-26T20:46:16Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Reimplement `bisect_next_check` shell function in C and add\n`bisect-next-check` subcommand to `git bisect--helper` to call it from\ngit-bisect.sh .\n\nUsing `--bisect-next-check` is a temporary measure to port shell\nfunction to C so as to use the existing test suite. As more functions\nare ported, this subcommand will be retired and will be called by some\nother methods.\n\nbisect_voc() is removed as it is redundant and does not serve any useful\npurpose. We are better off specifying \"bad|new\" \"good|old\" as and when\nwe require in bisect_next_check().\n\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++-\n git-bisect.sh            | 60 +++---------------------------------\n 2 files changed, 83 insertions(+), 57 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex c387697..9a289a1 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -6,6 +6,7 @@\n #include \"dir.h\"\n #include \"argv-array.h\"\n #include \"run-command.h\"\n+#include \"prompt.h\"\n \n static GIT_PATH_FUNC(git_path_bisect_write_terms, \"BISECT_TERMS\")\n static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXPECTED_REV\")\n@@ -23,6 +24,7 @@ static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --bisect-clean-state\"),\n \tN_(\"git bisect--helper --bisect-reset [<commit>]\"),\n \tN_(\"git bisect--helper --bisect-write <state> <revision> <TERM_GOOD> <TERM_BAD> [<nolog>]\"),\n+\tN_(\"git bisect--helper --bisect-next-check [<term>] <TERM_GOOD> <TERM_BAD\"),\n \tNULL\n };\n \n@@ -295,6 +297,68 @@ static int check_and_set_terms(const char *cmd, struct bisect_terms *term)\n \treturn 0;\n }\n \n+static int mark_good(const char *refname, const struct object_id *oid,\n+\t\t     int flag, void *cb_data)\n+{\n+\tint *m_good = (int *)cb_data;\n+\t*m_good = 0;\n+\treturn 0;\n+}\n+\n+static int bisect_next_check(const struct bisect_terms *state, const char *term)\n+{\n+\tint missing_good = 1, missing_bad = 1;\n+\tchar *bad_ref = xstrfmt(\"refs/bisect/%s\", state->term_bad.buf);\n+\tchar *good_ref = xstrfmt(\"%s*\", state->term_good.buf);\n+\tif (ref_exists(bad_ref))\n+\t\tmissing_bad = 0;\n+\n+\tfor_each_glob_ref_in(mark_good, good_ref, \"refs/bisect/\",\n+\t\t\t     (void *) &missing_good);\n+\tfree(good_ref);\n+\tfree(bad_ref);\n+\n+\tif (!missing_good && !missing_bad)\n+\t\treturn 0;\n+\n+\tif (!term)\n+\t\treturn -1;\n+\n+\tif (missing_good && !missing_bad && term && !strcmp(term, state->term_good.buf)) {\n+\t\tchar *yesno;\n+\t\t/*\n+\t\t * have bad (or new) but not good (or old). We could bisect\n+\t\t * although this is less optimum.\n+\t\t */\n+\t\tfprintf(stderr, \"Warning: bisecting only with a %s commit\\n\",\n+\t\t\tstate->term_bad.buf);\n+\t\tif (!isatty(0))\n+\t\t\treturn 0;\n+\t\t/*\n+\t\t * TRANSLATORS: Make sure to include [Y] and [n] in your\n+\t\t * translation. The program will only accept English input\n+\t\t * at this point.\n+\t\t */\n+\t\tyesno = git_prompt(_(\"Are you sure [Y/n]? \"), PROMPT_ECHO);\n+\t\tif (starts_with(yesno, \"N\") || starts_with(yesno, \"n\"))\n+\t\t\treturn -1;\n+\t\treturn 0;\n+\t}\n+\tif (!is_empty_or_missing_file(git_path_bisect_start()))\n+\t\treturn error(_(\"You need to give me at least one good|old and \"\n+\t\t\t\t\"bad|new revision. You can use \\\"git bisect \"\n+\t\t\t\t\"bad|new\\\" and \\\"git bisect good|old\\\" for \"\n+\t\t\t\t\"that. \\n\"));\n+\telse\n+\t\treturn error(_(\"You need to start by \\\"git bisect start\\\". \"\n+\t\t\t\t\"You then need to give me at least one good|\"\n+\t\t\t\t\"old and bad|new revision. You can use \\\"git \"\n+\t\t\t\t\"bisect bad|new\\\" and \\\"git bisect good|old\\\" \"\n+\t\t\t\t\" for that.\\n\"));\n+\n+\treturn 0;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -304,7 +368,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tBISECT_RESET,\n \t\tCHECK_EXPECTED_REVS,\n \t\tBISECT_WRITE,\n-\t\tCHECK_AND_SET_TERMS\n+\t\tCHECK_AND_SET_TERMS,\n+\t\tBISECT_NEXT_CHECK\n \t} cmdmode = 0;\n \tint no_checkout = 0, res = 0;\n \tstruct option options[] = {\n@@ -322,6 +387,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"write out the bisection state in BISECT_LOG\"), BISECT_WRITE),\n \t\tOPT_CMDMODE(0, \"check-and-set-terms\", &cmdmode,\n \t\t\t N_(\"check and set terms in a bisection state\"), CHECK_AND_SET_TERMS),\n+\t\tOPT_CMDMODE(0, \"bisect-next-check\", &cmdmode,\n+\t\t\t N_(\"check whether bad or good terms exist\"), BISECT_NEXT_CHECK),\n \t\tOPT_BOOL(0, \"no-checkout\", &no_checkout,\n \t\t\t N_(\"update BISECT_HEAD instead of checking out the current commit\")),\n \t\tOPT_END()\n@@ -372,6 +439,17 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tstrbuf_addstr(&state.term_bad, argv[2]);\n \t\tres = check_and_set_terms(argv[0], &state);\n \t\tbreak;\n+\tcase BISECT_NEXT_CHECK:\n+\t\tif (argc != 2 && argc != 3)\n+\t\t\tdie(_(\"--bisect-next-check requires 2 or 3 arguments\"));\n+\t\tstrbuf_addstr(&state.term_good, argv[0]);\n+\t\tstrbuf_addstr(&state.term_bad, argv[1]);\n+\t\tif (argc == 2) {\n+\t\t\tres = bisect_next_check(&state, NULL);\n+\t\t\tbreak;\n+\t\t}\n+\t\tres = bisect_next_check(&state, argv[2]);\n+\t\tbreak;\n \tdefault:\n \t\tdie(\"BUG: unknown subcommand '%d'\", cmdmode);\n \t}\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 63ae742..51b0a6b 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -271,59 +271,14 @@ bisect_state() {\n \tbisect_auto_next\n }\n \n-bisect_next_check() {\n-\tmissing_good= missing_bad=\n-\tgit show-ref -q --verify refs/bisect/$TERM_BAD || missing_bad=t\n-\ttest -n \"$(git for-each-ref \"refs/bisect/$TERM_GOOD-*\")\" || missing_good=t\n-\n-\tcase \"$missing_good,$missing_bad,$1\" in\n-\t,,*)\n-\t\t: have both $TERM_GOOD and $TERM_BAD - ok\n-\t\t;;\n-\t*,)\n-\t\t# do not have both but not asked to fail - just report.\n-\t\tfalse\n-\t\t;;\n-\tt,,\"$TERM_GOOD\")\n-\t\t# have bad (or new) but not good (or old).  we could bisect although\n-\t\t# this is less optimum.\n-\t\teval_gettextln \"Warning: bisecting only with a \\$TERM_BAD commit.\" >&2\n-\t\tif test -t 0\n-\t\tthen\n-\t\t\t# TRANSLATORS: Make sure to include [Y] and [n] in your\n-\t\t\t# translation. The program will only accept English input\n-\t\t\t# at this point.\n-\t\t\tgettext \"Are you sure [Y/n]? \" >&2\n-\t\t\tread yesno\n-\t\t\tcase \"$yesno\" in [Nn]*) exit 1 ;; esac\n-\t\tfi\n-\t\t: bisect without $TERM_GOOD...\n-\t\t;;\n-\t*)\n-\t\tbad_syn=$(bisect_voc bad)\n-\t\tgood_syn=$(bisect_voc good)\n-\t\tif test -s \"$GIT_DIR/BISECT_START\"\n-\t\tthen\n-\n-\t\t\teval_gettextln \"You need to give me at least one \\$bad_syn and one \\$good_syn revision.\n-(You can use \\\"git bisect \\$bad_syn\\\" and \\\"git bisect \\$good_syn\\\" for that.)\" >&2\n-\t\telse\n-\t\t\teval_gettextln \"You need to start by \\\"git bisect start\\\".\n-You then need to give me at least one \\$good_syn and one \\$bad_syn revision.\n-(You can use \\\"git bisect \\$bad_syn\\\" and \\\"git bisect \\$good_syn\\\" for that.)\" >&2\n-\t\tfi\n-\t\texit 1 ;;\n-\tesac\n-}\n-\n bisect_auto_next() {\n-\tbisect_next_check && bisect_next || :\n+\tgit bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD && bisect_next || :\n }\n \n bisect_next() {\n \tcase \"$#\" in 0) ;; *) usage ;; esac\n \tbisect_autostart\n-\tbisect_next_check $TERM_GOOD\n+\tgit bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD $TERM_GOOD|| exit\n \n \t# Perform all bisection computation, display and checkout\n \tgit bisect--helper --next-all $(test -f \"$GIT_DIR/BISECT_HEAD\" && echo --no-checkout)\n@@ -355,7 +310,7 @@ bisect_next() {\n }\n \n bisect_visualize() {\n-\tbisect_next_check fail\n+\tgit bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit\n \n \tif test $# = 0\n \tthen\n@@ -409,7 +364,7 @@ bisect_replay () {\n }\n \n bisect_run () {\n-\tbisect_next_check fail\n+\tgit bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit\n \n \twhile true\n \tdo\n@@ -482,13 +437,6 @@ get_terms () {\n \tfi\n }\n \n-bisect_voc () {\n-\tcase \"$1\" in\n-\tbad) echo \"bad|new\" ;;\n-\tgood) echo \"good|old\" ;;\n-\tesac\n-}\n-\n bisect_terms () {\n \tget_terms\n \tif ! test -s \"$GIT_DIR/BISECT_TERMS\"\n-- \n2.9.0\n\n"},{"id":"290205","messageId":"20160626204411.19919-3-pranit.bauva@gmail.com","threadId":"42718","inReplyTo":"20160626204411.19919-1-pranit.bauva@gmail.com","subject":"[RFC/PATCH 3/3] bisect--helper: `get_terms` & `bisect_terms` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-06-26T20:44:11Z","receivedAt":"2016-06-26T20:46:22Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Reimplement the `get_terms` and `bisect_terms` shell function in C and\nadd `bisect-terms` subcommand to `git bisect--helper` to call it from\ngit-bisect.sh .\n\nUsing `--bisect-terms` subcommand is a temporary measure to port shell\nfunction in C so as to use the existing test suite. As more functions\nare ported, this subcommand will be retired and will be called by some\nother methods.\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++-\n git-bisect.sh            | 35 ++--------------------------------\n 2 files changed, 50 insertions(+), 34 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 9a289a1..51a408c 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -359,6 +359,41 @@ static int bisect_next_check(const struct bisect_terms *state, const char *term)\n \treturn 0;\n }\n \n+static int get_terms(struct bisect_terms *term)\n+{\n+\tFILE *fp;\n+\tfp = fopen(git_path_bisect_write_terms(), \"r\");\n+\tif (!fp)\n+\t\treturn -1;\n+\n+\tbisect_terms_reinit(term);\n+\tif (strbuf_getline(&term->term_bad, fp) == EOF)\n+\t\treturn -1;\n+\tif (strbuf_getline(&term->term_good, fp) == EOF)\n+\t\treturn -1;\n+\treturn 0;\n+}\n+\n+static int bisect_terms(struct bisect_terms *term, const char *arg)\n+{\n+\tif (get_terms(term)) {\n+\t\tfprintf(stderr, \"no terms defined\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (!arg) {\n+\t\tprintf(\"Your current terms are %s for the old state\\nand \"\n+\t\t       \"%s for the new state.\\n\", term->term_good.buf,\n+\t\t       term->term_bad.buf);\n+\t\treturn 0;\n+\t}\n+\tif (one_of(arg, \"--term-good\", \"--term-old\", NULL))\n+\t\tprintf(\"%s\\n\", term->term_good.buf);\n+\tif (one_of(arg, \"--term-bad\", \"--term-new\", NULL))\n+\t\tprintf(\"%s\\n\", term->term_bad.buf);\n+\n+\treturn 0;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -369,7 +404,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tCHECK_EXPECTED_REVS,\n \t\tBISECT_WRITE,\n \t\tCHECK_AND_SET_TERMS,\n-\t\tBISECT_NEXT_CHECK\n+\t\tBISECT_NEXT_CHECK,\n+\t\tBISECT_TERMS\n \t} cmdmode = 0;\n \tint no_checkout = 0, res = 0;\n \tstruct option options[] = {\n@@ -389,6 +425,12 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"check and set terms in a bisection state\"), CHECK_AND_SET_TERMS),\n \t\tOPT_CMDMODE(0, \"bisect-next-check\", &cmdmode,\n \t\t\t N_(\"check whether bad or good terms exist\"), BISECT_NEXT_CHECK),\n+\t\tOPT_CMDMODE(0, \"bisect-terms\", &cmdmode,\n+\t\t\t N_(\"print out the bisect terms\"), BISECT_TERMS),\n+\t\tOPT_ARGUMENT(\"term-bad\", \"handle this in an individual function\"),\n+\t\tOPT_ARGUMENT(\"term-good\", \"handle this in an individual function\"),\n+\t\tOPT_ARGUMENT(\"term-new\", \"handle this in an individual function\"),\n+\t\tOPT_ARGUMENT(\"term-old\", \"handle this in an individual function\"),\n \t\tOPT_BOOL(0, \"no-checkout\", &no_checkout,\n \t\t\t N_(\"update BISECT_HEAD instead of checking out the current commit\")),\n \t\tOPT_END()\n@@ -450,6 +492,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t}\n \t\tres = bisect_next_check(&state, argv[2]);\n \t\tbreak;\n+\tcase BISECT_TERMS:\n+\t\tif (argc != 0 && argc != 1)\n+\t\t\tdie(_(\"--bisect-terms requires 0 or 1 argument\"));\n+\t\tres = bisect_terms(&state, argc ? argv[0] : NULL);\n+\t\tbreak;\n \tdefault:\n \t\tdie(\"BUG: unknown subcommand '%d'\", cmdmode);\n \t}\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 51b0a6b..5723601 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -355,7 +355,7 @@ bisect_replay () {\n \t\t\"$TERM_GOOD\"|\"$TERM_BAD\"|skip)\n \t\t\tgit bisect--helper --bisect-write \"$command\" \"$rev\" \"$TERM_GOOD\" \"$TERM_BAD\" || exit;;\n \t\tterms)\n-\t\t\tbisect_terms $rev ;;\n+\t\t\tgit bisect--helper --bisect-terms $rev ;;\n \t\t*)\n \t\t\tdie \"$(gettext \"?? what are you talking about?\")\" ;;\n \t\tesac\n@@ -437,37 +437,6 @@ get_terms () {\n \tfi\n }\n \n-bisect_terms () {\n-\tget_terms\n-\tif ! test -s \"$GIT_DIR/BISECT_TERMS\"\n-\tthen\n-\t\tdie \"$(gettext \"no terms defined\")\"\n-\tfi\n-\tcase \"$#\" in\n-\t0)\n-\t\tgettextln \"Your current terms are $TERM_GOOD for the old state\n-and $TERM_BAD for the new state.\"\n-\t\t;;\n-\t1)\n-\t\targ=$1\n-\t\tcase \"$arg\" in\n-\t\t\t--term-good|--term-old)\n-\t\t\t\tprintf '%s\\n' \"$TERM_GOOD\"\n-\t\t\t\t;;\n-\t\t\t--term-bad|--term-new)\n-\t\t\t\tprintf '%s\\n' \"$TERM_BAD\"\n-\t\t\t\t;;\n-\t\t\t*)\n-\t\t\t\tdie \"$(eval_gettext \"invalid argument \\$arg for 'git bisect terms'.\n-Supported options are: --term-good|--term-old and --term-bad|--term-new.\")\"\n-\t\t\t\t;;\n-\t\tesac\n-\t\t;;\n-\t*)\n-\t\tusage ;;\n-\tesac\n-}\n-\n case \"$#\" in\n 0)\n \tusage ;;\n@@ -498,7 +467,7 @@ case \"$#\" in\n \trun)\n \t\tbisect_run \"$@\" ;;\n \tterms)\n-\t\tbisect_terms \"$@\" ;;\n+\t\tgit bisect--helper --bisect-terms \"$@\" ;;\n \t*)\n \t\tusage ;;\n \tesac\n-- \n2.9.0\n\n"}]}