{"thread":{"id":"43909","subject":"[PATCH v14 25/27] bisect--helper: retire `--bisect-autostart` subcommand","startedAt":"2016-08-23T12:00:52Z","lastAt":"2016-08-30T20:17:46Z","messageCount":62,"participants":["Pranit Bauva","Junio C Hamano"],"isPatch":true,"patchVersion":14,"patchTotal":27},"messages":[{"id":"299900","messageId":"01020156b73fe6dd-4714236e-c26d-4ee8-b36e-caf516618d87-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 25/27] bisect--helper: retire `--bisect-autostart` subcommand","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:00:52Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"The `--bisect-autostart` subcommand is no longer used in the shell\nscript and the function `bisect_autostart()` is called from the C\nimplementation.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 11 -----------\n 1 file changed, 11 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 8982f29..a89e2f7 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -27,7 +27,6 @@ static const char * const git_bisect_helper_usage[] = {\n \t\t\t\t\t      \"[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]\"),\n \tN_(\"git bisect--helper --bisect-next\"),\n \tN_(\"git bisect--helper --bisect-auto-next\"),\n-\tN_(\"git bisect--helper --bisect-autostart\"),\n \tN_(\"git bisect--helper --bisect-state (bad|new) [<rev>]\"),\n \tN_(\"git bisect--helper --bisect-state (good|old) [<rev>...]\"),\n \tN_(\"git bisect--helper --bisect-replay <filename>\"),\n@@ -974,7 +973,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tBISECT_START,\n \t\tBISECT_NEXT,\n \t\tBISECT_AUTO_NEXT,\n-\t\tBISECT_AUTOSTART,\n \t\tBISECT_STATE,\n \t\tBISECT_LOG,\n \t\tBISECT_REPLAY\n@@ -993,8 +991,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"find the next bisection commit\"), BISECT_NEXT),\n \t\tOPT_CMDMODE(0, \"bisect-auto-next\", &cmdmode,\n \t\t\t N_(\"verify the next bisection state then find the next bisection state\"), BISECT_AUTO_NEXT),\n-\t\tOPT_CMDMODE(0, \"bisect-autostart\", &cmdmode,\n-\t\t\t N_(\"start the bisection if BISECT_START empty or missing\"), BISECT_AUTOSTART),\n \t\tOPT_CMDMODE(0, \"bisect-state\", &cmdmode,\n \t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\n \t\tOPT_CMDMODE(0, \"bisect-log\", &cmdmode,\n@@ -1050,13 +1046,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tget_terms(&terms);\n \t\tres = bisect_auto_next(&terms, prefix);\n \t\tbreak;\n-\tcase BISECT_AUTOSTART:\n-\t\tif (argc)\n-\t\t\tdie(_(\"--bisect-autostart requires 0 arguments\"));\n-\t\tstrbuf_addstr(&terms.term_good, \"good\");\n-\t\tstrbuf_addstr(&terms.term_bad, \"bad\");\n-\t\tres = bisect_autostart(&terms);\n-\t\tbreak;\n \tcase BISECT_STATE:\n \t\tif (argc == 0)\n \t\t\tdie(_(\"--bisect-state requires at least 1 argument\"));\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299901","messageId":"01020156b73fe6b9-5e500c96-9bc3-4a6b-beb9-b5988dc9ee85-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 13/27] bisect--helper: `bisect_start` shell function partially in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:00:58Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Reimplement the `bisect_start` shell function partially in C and add\n`bisect-start` subcommand to `git bisect--helper` to call it from\ngit-bisect.sh .\n\nThe last part is not converted because it calls another shell function\n`bisect_start` shell function will be completed after the `bisect_next`\nshell function is ported in C.\n\nUsing `--bisect-start` 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: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++-\n git-bisect.sh            | 133 +-------------------------\n 2 files changed, 238 insertions(+), 133 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 44adf6b..c64996a 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -7,6 +7,7 @@\n #include \"argv-array.h\"\n #include \"run-command.h\"\n #include \"prompt.h\"\n+#include \"quote.h\"\n \n static GIT_PATH_FUNC(git_path_bisect_terms, \"BISECT_TERMS\")\n static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXPECTED_REV\")\n@@ -14,6 +15,8 @@ static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, \"BISECT_ANCESTORS_OK\")\n static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n static GIT_PATH_FUNC(git_path_bisect_head, \"BISECT_HEAD\")\n+static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n+static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NAMES\")\n \n static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --next-all [--no-checkout]\"),\n@@ -24,6 +27,8 @@ static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --bisect-check-and-set-terms <command> <TERM_GOOD> <TERM_BAD>\"),\n \tN_(\"git bisect--helper --bisect-next-check [<term>] <TERM_GOOD> <TERM_BAD\"),\n \tN_(\"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]\"),\n+\tN_(\"git bisect--helper --bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]\"\n+\t\t\t\t\t      \"[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]\"),\n \tNULL\n };\n \n@@ -391,6 +396,226 @@ static int bisect_terms(struct bisect_terms *terms, const char **argv, int argc)\n \treturn 0;\n }\n \n+static int bisect_start(struct bisect_terms *terms, int no_checkout,\n+\t\t\tconst char **argv, int argc)\n+{\n+\tint i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;\n+\tint flags, pathspec_pos;\n+\tstruct string_list revs = STRING_LIST_INIT_DUP;\n+\tstruct string_list states = STRING_LIST_INIT_DUP;\n+\tstruct strbuf start_head = STRBUF_INIT;\n+\tstruct strbuf bisect_names = STRBUF_INIT;\n+\tstruct strbuf orig_args = STRBUF_INIT;\n+\tconst char *head;\n+\tunsigned char sha1[20];\n+\tFILE *fp;\n+\tstruct object_id oid;\n+\n+\tif (is_bare_repository())\n+\t\tno_checkout = 1;\n+\n+\tfor (i = 0; i < argc; i++) {\n+\t\tif (!strcmp(argv[i], \"--\")) {\n+\t\t\thas_double_dash = 1;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tfor (i = 0; i < argc; i++) {\n+\t\tconst char *commit_id = xstrfmt(\"%s^{commit}\", argv[i]);\n+\t\tif (!strcmp(argv[i], \"--\")) {\n+\t\t\thas_double_dash = 1;\n+\t\t\tbreak;\n+\t\t} else if (!strcmp(argv[i], \"--no-checkout\"))\n+\t\t\tno_checkout = 1;\n+\t\telse if (!strcmp(argv[i], \"--term-good\") ||\n+\t\t\t !strcmp(argv[i], \"--term-old\")) {\n+\t\t\tmust_write_terms = 1;\n+\t\t\tstrbuf_reset(&terms->term_good);\n+\t\t\tstrbuf_addstr(&terms->term_good, argv[++i]);\n+\t\t} else if (skip_prefix(argv[i], \"--term-good=\", &argv[i])) {\n+\t\t\tmust_write_terms = 1;\n+\t\t\tstrbuf_reset(&terms->term_good);\n+\t\t\tstrbuf_addstr(&terms->term_good, argv[i]);\n+\t\t} else if (skip_prefix(argv[i], \"--term-old=\", &argv[i])) {\n+\t\t\tmust_write_terms = 1;\n+\t\t\tstrbuf_reset(&terms->term_good);\n+\t\t\tstrbuf_addstr(&terms->term_good, argv[i]);\n+\t\t} else if (!strcmp(argv[i], \"--term-bad\") ||\n+\t\t\t !strcmp(argv[i], \"--term-new\")) {\n+\t\t\tmust_write_terms = 1;\n+\t\t\tstrbuf_reset(&terms->term_bad);\n+\t\t\tstrbuf_addstr(&terms->term_bad, argv[++i]);\n+\t\t} else if (skip_prefix(argv[i], \"--term-bad=\", &argv[i])) {\n+\t\t\tmust_write_terms = 1;\n+\t\t\tstrbuf_reset(&terms->term_bad);\n+\t\t\tstrbuf_addstr(&terms->term_bad, argv[i]);\n+\t\t} else if (skip_prefix(argv[i], \"--term-new=\", &argv[i])) {\n+\t\t\tmust_write_terms = 1;\n+\t\t\tstrbuf_reset(&terms->term_good);\n+\t\t\tstrbuf_addstr(&terms->term_good, argv[i]);\n+\t\t} else if (starts_with(argv[i], \"--\") &&\n+\t\t\t !one_of(argv[i], \"--term-good\", \"--term-bad\", NULL)) {\n+\t\t\tstring_list_clear(&revs, 0);\n+\t\t\tstring_list_clear(&states, 0);\n+\t\t\tdie(_(\"unrecognised option: '%s'\"), argv[i]);\n+\t\t} else if (get_oid(commit_id, &oid) && has_double_dash) {\n+\t\t\tstring_list_clear(&revs, 0);\n+\t\t\tstring_list_clear(&states, 0);\n+\t\t\tdie(_(\"'%s' does not appear to be a valid revision\"), argv[i]);\n+\t\t} else {\n+\t\t\tstring_list_append(&revs, oid_to_hex(&oid));\n+\t\t}\n+\t}\n+\tpathspec_pos = i;\n+\n+\t/*\n+\t * The user ran \"git bisect start <sha1> <sha1>\", hence did not\n+\t * explicitly specify the terms, but we are already starting to\n+\t * set references named with the default terms, and won't be able\n+\t * to change afterwards.\n+\t */\n+\tmust_write_terms |= !!revs.nr;\n+\tfor (i = 0; i < revs.nr; i++) {\n+\t\tif (bad_seen)\n+\t\t\tstring_list_append(&states, terms->term_good.buf);\n+\t\telse {\n+\t\t\tbad_seen = 1;\n+\t\t\tstring_list_append(&states, terms->term_bad.buf);\n+\t\t}\n+\t}\n+\n+\t/*\n+\t * Verify HEAD\n+\t */\n+\thead = resolve_ref_unsafe(\"HEAD\", 0, sha1, &flags);\n+\tif (!head) {\n+\t\tif (get_sha1(\"HEAD\", sha1)) {\n+\t\t\tstring_list_clear(&revs, 0);\n+\t\t\tstring_list_clear(&states, 0);\n+\t\t\tdie(_(\"Bad HEAD - I need a HEAD\"));\n+\t\t}\n+\t}\n+\tif (!is_empty_or_missing_file(git_path_bisect_start())) {\n+\t\t/* Reset to the rev from where we started */\n+\t\tstrbuf_read_file(&start_head, git_path_bisect_start(), 0);\n+\t\tstrbuf_trim(&start_head);\n+\t\tif (!no_checkout) {\n+\t\t\tstruct argv_array argv = ARGV_ARRAY_INIT;\n+\t\t\targv_array_pushl(&argv, \"checkout\", start_head.buf,\n+\t\t\t\t\t \"--\", NULL);\n+\t\t\tif (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {\n+\t\t\t\terror(_(\"checking out '%s' failed. Try 'git \"\n+\t\t\t\t\t\"bisect start <valid-branch>'.\"),\n+\t\t\t\t      start_head.buf);\n+\t\t\t\tstrbuf_release(&start_head);\n+\t\t\t\tstring_list_clear(&revs, 0);\n+\t\t\t\tstring_list_clear(&states, 0);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t}\n+\t} else {\n+\t\tif (starts_with(head, \"refs/heads/\") ||\n+\t\t    !get_oid_hex(head, &oid) || ref_exists(head)) {\n+\t\t\t/*\n+\t\t\t * This error message should only be triggered by\n+\t\t\t * cogito usage, and cogito users should understand\n+\t\t\t * it relates to cg-seek.\n+\t\t\t */\n+\t\t\tif (!is_empty_or_missing_file(git_path_head_name())) {\n+\t\t\t\tstrbuf_release(&start_head);\n+\t\t\t\tstring_list_clear(&revs, 0);\n+\t\t\t\tstring_list_clear(&states, 0);\n+\t\t\t\tdie(_(\"won't bisect on cg-seek'ed tree\"));\n+\t\t\t}\n+\t\t\tif (starts_with(head, \"refs/heads/\")) {\n+\t\t\t\tstrbuf_reset(&start_head);\n+\t\t\t\tstrbuf_addstr(&start_head, head + 11);\n+\t\t\t}\n+\t\t\telse {\n+\t\t\t\tstrbuf_reset(&start_head);\n+\t\t\t\tstrbuf_addstr(&start_head, sha1_to_hex(sha1));\n+\t\t\t}\n+\t\t} else {\n+\t\t\tstrbuf_release(&start_head);\n+\t\t\tstring_list_clear(&revs, 0);\n+\t\t\tstring_list_clear(&states, 0);\n+\t\t\tdie(_(\"Bad HEAD - strange symbolic ref\"));\n+\t\t}\n+\t}\n+\n+\t/*\n+\t * Get rid of any old bisect state.\n+\t */\n+\tif (bisect_clean_state()) {\n+\t\treturn -1;\n+\t}\n+\t/*\n+\t * In case of mistaken revs or checkout error, or signals received,\n+\t * \"bisect_auto_next\" below may exit or misbehave.\n+\t * We have to trap this to be able to clean up using\n+\t * \"bisect_clean_state\".\n+\t */\n+\n+\t/*\n+\t * Write new start state\n+\t */\n+\twrite_file(git_path_bisect_start(), \"%s\\n\", start_head.buf);\n+\n+\tif (no_checkout) {\n+\t\tget_oid(start_head.buf, &oid);\n+\t\tif (update_ref(NULL, \"BISECT_HEAD\", oid.hash, NULL, 0,\n+\t\t\t       UPDATE_REFS_MSG_ON_ERR)) {\n+\t\t\tstrbuf_release(&start_head);\n+\t\t\tstring_list_clear(&revs, 0);\n+\t\t\tstring_list_clear(&states, 0);\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\tstrbuf_release(&start_head);\n+\n+\tif (pathspec_pos < argc - 1)\n+\t\tsq_quote_argv(&bisect_names, argv + pathspec_pos, 0);\n+\twrite_file(git_path_bisect_names(), \"%s\\n\", bisect_names.buf);\n+\tstrbuf_release(&bisect_names);\n+\n+\tfor (i = 0; i < states.nr; i++) {\n+\t\tif (bisect_write(states.items[i].string,\n+\t\t\t\t  revs.items[i].string, terms, 1)) {\n+\t\t\tstring_list_clear(&revs, 0);\n+\t\t\tstring_list_clear(&states, 0);\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\tstring_list_clear(&revs, 0);\n+\tstring_list_clear(&states, 0);\n+\n+\tif (must_write_terms)\n+\t\tif (write_terms(terms->term_bad.buf, terms->term_good.buf))\n+\t\t\treturn -1;\n+\n+\tfp = fopen(git_path_bisect_log(), \"a\");\n+\tif (!fp)\n+\t\treturn -1;\n+\n+\tif (fprintf(fp, \"git bisect start\") < 1)\n+\t\treturn -1;\n+\n+\tsq_quote_argv(&orig_args, argv, 0);\n+\tif (fprintf(fp, \"%s\", orig_args.buf) < 0) {\n+\t\tstrbuf_release(&orig_args);\n+\t\treturn -1;\n+\t}\n+\tstrbuf_release(&orig_args);\n+\tif (fprintf(fp, \"\\n\") < 1) {\n+\t\tfclose(fp);\n+\t\treturn -1;\n+\t}\n+\tfclose(fp);\n+\n+\treturn 0;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -402,7 +627,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tBISECT_WRITE,\n \t\tCHECK_AND_SET_TERMS,\n \t\tBISECT_NEXT_CHECK,\n-\t\tBISECT_TERMS\n+\t\tBISECT_TERMS,\n+\t\tBISECT_START\n \t} cmdmode = 0;\n \tint no_checkout = 0, res = 0;\n \tstruct option options[] = {\n@@ -424,6 +650,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\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_CMDMODE(0, \"bisect-start\", &cmdmode,\n+\t\t\t N_(\"start the bisect session\"), BISECT_START),\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@@ -432,7 +660,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tbisect_terms_init(&terms);\n \n \targc = parse_options(argc, argv, prefix, options,\n-\t\t\t     git_bisect_helper_usage, PARSE_OPT_KEEP_UNKNOWN);\n+\t\t\t     git_bisect_helper_usage,\n+\t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);\n \n \tif (!cmdmode)\n \t\tusage_with_options(git_bisect_helper_usage, options);\n@@ -486,6 +715,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"--bisect-terms requires 0 or 1 argument\"));\n \t\tres = bisect_terms(&terms, argv, argc);\n \t\tbreak;\n+\tcase BISECT_START:\n+\t\tstrbuf_addstr(&terms.term_good, \"good\");\n+\t\tstrbuf_addstr(&terms.term_bad, \"bad\");\n+\t\tres = bisect_start(&terms, no_checkout, argv, argc);\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 d6c8b5a..f0896b3 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -71,122 +71,7 @@ bisect_autostart() {\n }\n \n bisect_start() {\n-\t#\n-\t# Check for one bad and then some good revisions.\n-\t#\n-\thas_double_dash=0\n-\tfor arg; do\n-\t\tcase \"$arg\" in --) has_double_dash=1; break ;; esac\n-\tdone\n-\torig_args=$(git rev-parse --sq-quote \"$@\")\n-\tbad_seen=0\n-\teval=''\n-\tmust_write_terms=0\n-\trevs=''\n-\tif test \"z$(git rev-parse --is-bare-repository)\" != zfalse\n-\tthen\n-\t\tmode=--no-checkout\n-\telse\n-\t\tmode=''\n-\tfi\n-\twhile [ $# -gt 0 ]; do\n-\t\targ=\"$1\"\n-\t\tcase \"$arg\" in\n-\t\t--)\n-\t\t\tshift\n-\t\t\tbreak\n-\t\t;;\n-\t\t--no-checkout)\n-\t\t\tmode=--no-checkout\n-\t\t\tshift ;;\n-\t\t--term-good|--term-old)\n-\t\t\tshift\n-\t\t\tmust_write_terms=1\n-\t\t\tTERM_GOOD=$1\n-\t\t\tshift ;;\n-\t\t--term-good=*|--term-old=*)\n-\t\t\tmust_write_terms=1\n-\t\t\tTERM_GOOD=${1#*=}\n-\t\t\tshift ;;\n-\t\t--term-bad|--term-new)\n-\t\t\tshift\n-\t\t\tmust_write_terms=1\n-\t\t\tTERM_BAD=$1\n-\t\t\tshift ;;\n-\t\t--term-bad=*|--term-new=*)\n-\t\t\tmust_write_terms=1\n-\t\t\tTERM_BAD=${1#*=}\n-\t\t\tshift ;;\n-\t\t--*)\n-\t\t\tdie \"$(eval_gettext \"unrecognised option: '\\$arg'\")\" ;;\n-\t\t*)\n-\t\t\trev=$(git rev-parse -q --verify \"$arg^{commit}\") || {\n-\t\t\t\ttest $has_double_dash -eq 1 &&\n-\t\t\t\tdie \"$(eval_gettext \"'\\$arg' does not appear to be a valid revision\")\"\n-\t\t\t\tbreak\n-\t\t\t}\n-\t\t\trevs=\"$revs $rev\"\n-\t\t\tshift\n-\t\t\t;;\n-\t\tesac\n-\tdone\n-\n-\tfor rev in $revs\n-\tdo\n-\t\t# The user ran \"git bisect start <sha1>\n-\t\t# <sha1>\", hence did not explicitly specify\n-\t\t# the terms, but we are already starting to\n-\t\t# set references named with the default terms,\n-\t\t# and won't be able to change afterwards.\n-\t\tmust_write_terms=1\n-\n-\t\tcase $bad_seen in\n-\t\t0) state=$TERM_BAD ; bad_seen=1 ;;\n-\t\t*) state=$TERM_GOOD ;;\n-\t\tesac\n-\t\teval=\"$eval git bisect--helper --bisect-write '$state' '$rev' '$TERM_GOOD' '$TERM_BAD' 'nolog' &&\"\n-\tdone\n-\t#\n-\t# Verify HEAD.\n-\t#\n-\thead=$(GIT_DIR=\"$GIT_DIR\" git symbolic-ref -q HEAD) ||\n-\thead=$(GIT_DIR=\"$GIT_DIR\" git rev-parse --verify HEAD) ||\n-\tdie \"$(gettext \"Bad HEAD - I need a HEAD\")\"\n-\n-\t#\n-\t# Check if we are bisecting.\n-\t#\n-\tstart_head=''\n-\tif test -s \"$GIT_DIR/BISECT_START\"\n-\tthen\n-\t\t# Reset to the rev from where we started.\n-\t\tstart_head=$(cat \"$GIT_DIR/BISECT_START\")\n-\t\tif test \"z$mode\" != \"z--no-checkout\"\n-\t\tthen\n-\t\t\tgit checkout \"$start_head\" -- ||\n-\t\t\tdie \"$(eval_gettext \"Checking out '\\$start_head' failed. Try 'git bisect reset <valid-branch>'.\")\"\n-\t\tfi\n-\telse\n-\t\t# Get rev from where we start.\n-\t\tcase \"$head\" in\n-\t\trefs/heads/*|$_x40)\n-\t\t\t# This error message should only be triggered by\n-\t\t\t# cogito usage, and cogito users should understand\n-\t\t\t# it relates to cg-seek.\n-\t\t\t[ -s \"$GIT_DIR/head-name\" ] &&\n-\t\t\t\tdie \"$(gettext \"won't bisect on cg-seek'ed tree\")\"\n-\t\t\tstart_head=\"${head#refs/heads/}\"\n-\t\t\t;;\n-\t\t*)\n-\t\t\tdie \"$(gettext \"Bad HEAD - strange symbolic ref\")\"\n-\t\t\t;;\n-\t\tesac\n-\tfi\n-\n-\t#\n-\t# Get rid of any old bisect state.\n-\t#\n-\tgit bisect--helper --bisect-clean-state || exit\n+\tgit bisect--helper --bisect-start $@ || exit\n \n \t#\n \t# Change state.\n@@ -197,24 +82,10 @@ bisect_start() {\n \t#\n \ttrap 'git bisect--helper --bisect-clean-state' 0\n \ttrap 'exit 255' 1 2 3 15\n-\n-\t#\n-\t# Write new start state.\n-\t#\n-\techo \"$start_head\" >\"$GIT_DIR/BISECT_START\" && {\n-\t\ttest \"z$mode\" != \"z--no-checkout\" ||\n-\t\tgit update-ref --no-deref BISECT_HEAD \"$start_head\"\n-\t} &&\n-\tgit rev-parse --sq-quote \"$@\" >\"$GIT_DIR/BISECT_NAMES\" &&\n-\teval \"$eval true\" &&\n-\tif test $must_write_terms -eq 1\n-\tthen\n-\t\tgit bisect--helper --write-terms \"$TERM_BAD\" \"$TERM_GOOD\"\n-\tfi &&\n-\techo \"git bisect start$orig_args\" >>\"$GIT_DIR/BISECT_LOG\" || exit\n \t#\n \t# Check if we can proceed to the next bisect state.\n \t#\n+\tget_terms\n \tbisect_auto_next\n \n \ttrap '-' 0\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299902","messageId":"01020156b73fe6ce-3b204354-849b-40fd-93ff-2ebcf77df91c-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 14/27] bisect--helper: `bisect_next` and `bisect_auto_next` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:01:02Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Reimplement the `bisect_next` and the `bisect_auto_next` shell function\nin C and add the subcommands to `git bisect--helper` to call it from\ngit-bisect.sh .\n\nAlong with this conversion of `bisect_start` has also finished and thus\nit has been fully ported to C.\n\nA lot of parts of bisect.c uses exit() and these signals are then\ntrapped in the `bisect_start` function. Since the shell script ceases\nits existence it would be necessary to convert those exit() calls to\nreturn statements so that errors can be reported efficiently in C code.\n\nAs more and more calls are happening to the subcommands in `git\nbisect--helper`, more specifically when `bisect_start $rev` is converted to\n`git bisect--helper --bisect-start $rev` it is necessary to dequote the\narguments because of shell to C conversion.\n\nUsing `--bisect-next` and `--bisect-auto-start` subcommands is a\ntemporary measure to port shell function to C so as to use the existing\ntest suite. As more functions are ported, this subcommand will be\nretired and will be called by some other methods.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n bisect.c                 |  80 ++++++++++++------\n builtin/bisect--helper.c | 206 ++++++++++++++++++++++++++++++++++++++++++-----\n git-bisect.sh            |  74 ++---------------\n 3 files changed, 249 insertions(+), 111 deletions(-)\n\ndiff --git a/bisect.c b/bisect.c\nindex 45d598d..68c583b 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -618,6 +618,12 @@ static void bisect_rev_setup(struct rev_info *revs, const char *prefix,\n \tstruct argv_array rev_argv = ARGV_ARRAY_INIT;\n \tint i;\n \n+\t/*\n+\t * Since the code is slowly being converted to C, there might be\n+\t * instances where the revisions were initialized before. Thus\n+\t * we first need to reset it.\n+\t */\n+\treset_revision_walk();\n \tinit_revisions(revs, prefix);\n \trevs->abbrev = 0;\n \trevs->commit_format = CMIT_FMT_UNSPECIFIED;\n@@ -644,11 +650,11 @@ static void bisect_common(struct rev_info *revs)\n \t\tmark_edges_uninteresting(revs, NULL);\n }\n \n-static void exit_if_skipped_commits(struct commit_list *tried,\n+static int exit_if_skipped_commits(struct commit_list *tried,\n \t\t\t\t    const struct object_id *bad)\n {\n \tif (!tried)\n-\t\treturn;\n+\t\treturn 0;\n \n \tprintf(\"There are only 'skip'ped commits left to test.\\n\"\n \t       \"The first %s commit could be any of:\\n\", term_bad);\n@@ -659,7 +665,7 @@ static void exit_if_skipped_commits(struct commit_list *tried,\n \tif (bad)\n \t\tprintf(\"%s\\n\", oid_to_hex(bad));\n \tprintf(_(\"We cannot bisect more!\\n\"));\n-\texit(2);\n+\treturn 2;\n }\n \n static int is_expected_rev(const struct object_id *oid)\n@@ -700,7 +706,7 @@ static int bisect_checkout(const unsigned char *bisect_rev, int no_checkout)\n \t\tint res;\n \t\tres = run_command_v_opt(argv_checkout, RUN_GIT_CMD);\n \t\tif (res)\n-\t\t\texit(res);\n+\t\t\treturn res;\n \t}\n \n \targv_show_branch[1] = bisect_rev_hex;\n@@ -729,7 +735,7 @@ static struct commit **get_bad_and_good_commits(int *rev_nr)\n \treturn rev;\n }\n \n-static void handle_bad_merge_base(void)\n+static int handle_bad_merge_base(void)\n {\n \tif (is_expected_rev(current_bad_oid)) {\n \t\tchar *bad_hex = oid_to_hex(current_bad_oid);\n@@ -750,17 +756,18 @@ static void handle_bad_merge_base(void)\n \t\t\t\t\"between %s and [%s].\\n\"),\n \t\t\t\tbad_hex, term_bad, term_good, bad_hex, good_hex);\n \t\t}\n-\t\texit(3);\n+\t\treturn 3;\n \t}\n \n \tfprintf(stderr, _(\"Some %s revs are not ancestor of the %s rev.\\n\"\n \t\t\"git bisect cannot work properly in this case.\\n\"\n \t\t\"Maybe you mistook %s and %s revs?\\n\"),\n \t\tterm_good, term_bad, term_good, term_bad);\n-\texit(1);\n+\tbisect_clean_state();\n+\treturn 1;\n }\n \n-static void handle_skipped_merge_base(const unsigned char *mb)\n+static int handle_skipped_merge_base(const unsigned char *mb)\n {\n \tchar *mb_hex = sha1_to_hex(mb);\n \tchar *bad_hex = oid_to_hex(current_bad_oid);\n@@ -773,6 +780,7 @@ static void handle_skipped_merge_base(const unsigned char *mb)\n \t\t\"We continue anyway.\"),\n \t\tbad_hex, good_hex, term_bad, mb_hex, bad_hex);\n \tfree(good_hex);\n+\treturn 0;\n }\n \n /*\n@@ -784,10 +792,10 @@ static void handle_skipped_merge_base(const unsigned char *mb)\n  * - If one is \"skipped\", we can't know but we should warn.\n  * - If we don't know, we should check it out and ask the user to test.\n  */\n-static void check_merge_bases(int no_checkout)\n+static int check_merge_bases(int no_checkout)\n {\n \tstruct commit_list *result;\n-\tint rev_nr;\n+\tint rev_nr, res = 0;\n \tstruct commit **rev = get_bad_and_good_commits(&rev_nr);\n \n \tresult = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1);\n@@ -795,19 +803,25 @@ static void check_merge_bases(int no_checkout)\n \tfor (; result; result = result->next) {\n \t\tconst unsigned char *mb = result->item->object.oid.hash;\n \t\tif (!hashcmp(mb, current_bad_oid->hash)) {\n-\t\t\thandle_bad_merge_base();\n+\t\t\tres = handle_bad_merge_base();\n+\t\t\tbreak;\n \t\t} else if (0 <= sha1_array_lookup(&good_revs, mb)) {\n \t\t\tcontinue;\n \t\t} else if (0 <= sha1_array_lookup(&skipped_revs, mb)) {\n-\t\t\thandle_skipped_merge_base(mb);\n+\t\t\tres = handle_skipped_merge_base(mb);\n+\t\t\tbreak;\n \t\t} else {\n \t\t\tprintf(_(\"Bisecting: a merge base must be tested\\n\"));\n-\t\t\texit(bisect_checkout(mb, no_checkout));\n+\t\t\tres = bisect_checkout(mb, no_checkout);\n+\t\t\tif (!res)\n+\t\t\t\texit(0);\n+\t\t\tbreak;\n \t\t}\n \t}\n \n \tfree(rev);\n \tfree_commit_list(result);\n+\treturn res;\n }\n \n static int check_ancestors(const char *prefix)\n@@ -845,11 +859,11 @@ static int check_ancestors(const char *prefix)\n  * If a merge base must be tested by the user, its source code will be\n  * checked out to be tested by the user and we will exit.\n  */\n-static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)\n+static int check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)\n {\n \tchar *filename = git_pathdup(\"BISECT_ANCESTORS_OK\");\n \tstruct stat st;\n-\tint fd;\n+\tint fd, res = 0;\n \n \tif (!current_bad_oid)\n \t\tdie(_(\"a %s revision is needed\"), term_bad);\n@@ -864,7 +878,10 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)\n \n \t/* Check if all good revs are ancestor of the bad rev. */\n \tif (check_ancestors(prefix))\n-\t\tcheck_merge_bases(no_checkout);\n+\t\tres = check_merge_bases(no_checkout);\n+\n+\tif (res)\n+\t\treturn res;\n \n \t/* Create file BISECT_ANCESTORS_OK. */\n \tfd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);\n@@ -873,8 +890,11 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)\n \t\t\t      filename);\n \telse\n \t\tclose(fd);\n+\n+\treturn 0;\n  done:\n \tfree(filename);\n+\treturn 0;\n }\n \n /*\n@@ -944,7 +964,7 @@ int bisect_next_all(const char *prefix, int no_checkout)\n {\n \tstruct rev_info revs;\n \tstruct commit_list *tried;\n-\tint reaches = 0, all = 0, nr, steps;\n+\tint reaches = 0, all = 0, nr, steps, res;\n \tconst unsigned char *bisect_rev;\n \tchar steps_msg[32];\n \n@@ -952,7 +972,9 @@ int bisect_next_all(const char *prefix, int no_checkout)\n \tif (read_bisect_refs())\n \t\tdie(_(\"reading bisect refs failed\"));\n \n-\tcheck_good_are_ancestors_of_bad(prefix, no_checkout);\n+\tres = check_good_are_ancestors_of_bad(prefix, no_checkout);\n+\tif (res)\n+\t\treturn res;\n \n \tbisect_rev_setup(&revs, prefix, \"%s\", \"^%s\", 1);\n \trevs.limited = 1;\n@@ -964,34 +986,40 @@ int bisect_next_all(const char *prefix, int no_checkout)\n \trevs.commits = managed_skipped(revs.commits, &tried);\n \n \tif (!revs.commits) {\n+\t\tint res;\n \t\t/*\n \t\t * We should exit here only if the \"bad\"\n \t\t * commit is also a \"skip\" commit.\n \t\t */\n-\t\texit_if_skipped_commits(tried, NULL);\n+\t\tres = exit_if_skipped_commits(tried, NULL);\n+\t\tif (res)\n+\t\t\treturn res;\n \n \t\tprintf(_(\"%s was both %s and %s\\n\"),\n \t\t       oid_to_hex(current_bad_oid),\n \t\t       term_good,\n \t\t       term_bad);\n-\t\texit(1);\n+\t\treturn 1;\n \t}\n \n \tif (!all) {\n \t\tfprintf(stderr, _(\"No testable commit found.\\n\"\n \t\t\t\"Maybe you started with bad path parameters?\\n\"));\n-\t\texit(4);\n+\t\treturn 4;\n \t}\n \n \tbisect_rev = revs.commits->item->object.oid.hash;\n \n \tif (!hashcmp(bisect_rev, current_bad_oid->hash)) {\n-\t\texit_if_skipped_commits(tried, current_bad_oid);\n+\t\tres = exit_if_skipped_commits(tried, current_bad_oid);\n+\t\tif (res)\n+\t\t\treturn res;\n+\n \t\tprintf(\"%s is the first %s commit\\n\", sha1_to_hex(bisect_rev),\n \t\t\tterm_bad);\n \t\tshow_diff_tree(prefix, revs.commits->item);\n \t\t/* This means the bisection process succeeded. */\n-\t\texit(10);\n+\t\treturn 10;\n \t}\n \n \tnr = all - reaches - 1;\n@@ -1005,7 +1033,11 @@ int bisect_next_all(const char *prefix, int no_checkout)\n \t\t  \"Bisecting: %d revisions left to test after this %s\\n\",\n \t\t  nr), nr, steps_msg);\n \n-\treturn bisect_checkout(bisect_rev, no_checkout);\n+\tres = bisect_checkout(bisect_rev, no_checkout);\n+\tif (res)\n+\t\tbisect_clean_state();\n+\n+\treturn res;\n }\n \n static inline int log2i(int n)\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex c64996a..ef7b3a1 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -8,6 +8,7 @@\n #include \"run-command.h\"\n #include \"prompt.h\"\n #include \"quote.h\"\n+#include \"revision.h\"\n \n static GIT_PATH_FUNC(git_path_bisect_terms, \"BISECT_TERMS\")\n static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXPECTED_REV\")\n@@ -29,6 +30,8 @@ static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]\"),\n \tN_(\"git bisect--helper --bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]\"\n \t\t\t\t\t      \"[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]\"),\n+\tN_(\"git bisect--helper --bisect-next\"),\n+\tN_(\"git bisect--helper --bisect-auto-next\"),\n \tNULL\n };\n \n@@ -396,6 +399,129 @@ static int bisect_terms(struct bisect_terms *terms, const char **argv, int argc)\n \treturn 0;\n }\n \n+static int register_good_ref(const char *refname,\n+\t\t\t     const struct object_id *oid, int flags,\n+\t\t\t     void *cb_data)\n+{\n+\tstruct string_list *good_refs = cb_data;\n+\tstring_list_append(good_refs, oid_to_hex(oid));\n+\treturn 0;\n+}\n+\n+static int bisect_next(struct bisect_terms *terms, const char *prefix)\n+{\n+\tint res, no_checkout;\n+\n+\t/* In case of mistaken revs or checkout error, or signals received,\n+\t * \"bisect_auto_next\" below may exit or misbehave.\n+\t * We have to trap this to be able to clean up using\n+\t * \"bisect_clean_state\".\n+\t */\n+\tif (bisect_next_check(terms, terms->term_good.buf))\n+\t\treturn -1;\n+\n+\tno_checkout = !is_empty_or_missing_file(git_path_bisect_head());\n+\n+\t/* Perform all bisection computation, display and checkout */\n+\tres = bisect_next_all(prefix , no_checkout);\n+\n+\tif (res == 10) {\n+\t\tFILE *fp;\n+\t\tunsigned char sha1[20];\n+\t\tstruct commit *commit;\n+\t\tstruct pretty_print_context pp = {0};\n+\t\tstruct strbuf commit_name = STRBUF_INIT;\n+\t\tchar *bad_ref = xstrfmt(\"refs/bisect/%s\",\n+\t\t\t\t\t      terms->term_bad.buf);\n+\t\tread_ref(bad_ref, sha1);\n+\t\tcommit = lookup_commit_reference(sha1);\n+\t\tformat_commit_message(commit, \"%s\", &commit_name, &pp);\n+\t\tfp = fopen(git_path_bisect_log(), \"a\");\n+\t\tif (!fp) {\n+\t\t\tfree(bad_ref);\n+\t\t\tstrbuf_release(&commit_name);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (fprintf(fp, \"# first %s commit: [%s] %s\\n\",\n+\t\t\t    terms->term_bad.buf, sha1_to_hex(sha1),\n+\t\t\t    commit_name.buf) < 1){\n+\t\t\tfree(bad_ref);\n+\t\t\tstrbuf_release(&commit_name);\n+\t\t\tfclose(fp);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tfree(bad_ref);\n+\t\tstrbuf_release(&commit_name);\n+\t\tfclose(fp);\n+\t\treturn 0;\n+\t}\n+\telse if (res == 2) {\n+\t\tFILE *fp;\n+\t\tstruct rev_info revs;\n+\t\tstruct argv_array rev_argv = ARGV_ARRAY_INIT;\n+\t\tstruct string_list good_revs = STRING_LIST_INIT_DUP;\n+\t\tstruct pretty_print_context pp = {0};\n+\t\tstruct commit *commit;\n+\t\tchar *term_good = xstrfmt(\"%s-*\", terms->term_good.buf);\n+\t\tint i;\n+\n+\t\tfp = fopen(git_path_bisect_log(), \"a\");\n+\t\tif (!fp) {\n+\t\t\tfree(term_good);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (fprintf(fp, \"# only skipped commits left to test\\n\") < 1) {\n+\t\t\tfree(term_good);\n+\t\t\tfclose(fp);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tfor_each_glob_ref_in(register_good_ref, term_good,\n+\t\t\t\t     \"refs/bisect/\", (void *) &good_revs);\n+\n+\t\tfree(term_good);\n+\t\targv_array_pushl(&rev_argv, \"skipped_commits\", \"refs/bisect/bad\", \"--not\", NULL);\n+\t\tfor (i = 0; i < good_revs.nr; i++)\n+\t\t\targv_array_push(&rev_argv, good_revs.items[i].string);\n+\n+\t\t/* It is important to reset the flags used by revision walks\n+\t\t * as the previous call to bisect_next_all() in turn\n+\t\t * setups a revision walk.\n+\t\t */\n+\t\treset_revision_walk();\n+\t\tinit_revisions(&revs, NULL);\n+\t\trev_argv.argc = setup_revisions(rev_argv.argc, rev_argv.argv, &revs, NULL);\n+\t\targv_array_clear(&rev_argv);\n+\t\tstring_list_clear(&good_revs, 0);\n+\t\tif (prepare_revision_walk(&revs)) {\n+\t\t\tdie(_(\"revision walk setup failed\\n\"));\n+\t\t}\n+\n+\t\twhile ((commit = get_revision(&revs)) != NULL) {\n+\t\t\tstruct strbuf commit_name = STRBUF_INIT;\n+\t\t\tformat_commit_message(commit, \"%s\",\n+\t\t\t\t\t      &commit_name, &pp);\n+\t\t\tfprintf(fp, \"# possible first %s commit: \"\n+\t\t\t\t    \"[%s] %s\\n\", terms->term_bad.buf,\n+\t\t\t\t    oid_to_hex(&commit->object.oid),\n+\t\t\t\t    commit_name.buf);\n+\t\t\tstrbuf_release(&commit_name);\n+\t\t}\n+\n+\t\tfclose(fp);\n+\t\treturn res;\n+\t}\n+\n+\treturn res;\n+}\n+\n+static int bisect_auto_next(struct bisect_terms *terms, const char *prefix)\n+{\n+\tif (!bisect_next_check(terms, NULL))\n+\t\treturn bisect_next(terms, prefix);\n+\n+\treturn 0;\n+}\n+\n static int bisect_start(struct bisect_terms *terms, int no_checkout,\n \t\t\tconst char **argv, int argc)\n {\n@@ -415,47 +541,67 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,\n \t\tno_checkout = 1;\n \n \tfor (i = 0; i < argc; i++) {\n-\t\tif (!strcmp(argv[i], \"--\")) {\n+\t\tconst char *arg;\n+\t\tif (starts_with(argv[i], \"'\"))\n+\t\t\targ = sq_dequote(xstrdup(argv[i]));\n+\t\telse\n+\t\t\targ = argv[i];\n+\t\tif (!strcmp(arg, \"--\")) {\n \t\t\thas_double_dash = 1;\n \t\t\tbreak;\n \t\t}\n \t}\n \n \tfor (i = 0; i < argc; i++) {\n-\t\tconst char *commit_id = xstrfmt(\"%s^{commit}\", argv[i]);\n+\t\tconst char *arg, *commit_id;\n+\t\tif (starts_with(argv[i], \"'\"))\n+\t\t\targ = sq_dequote(xstrdup(argv[i]));\n+\t\telse\n+\t\t\targ = argv[i];\n+\t\tcommit_id = xstrfmt(\"%s^{commit}\", arg);\n \t\tif (!strcmp(argv[i], \"--\")) {\n \t\t\thas_double_dash = 1;\n \t\t\tbreak;\n-\t\t} else if (!strcmp(argv[i], \"--no-checkout\"))\n+\t\t} else if (!strcmp(arg, \"--no-checkout\"))\n \t\t\tno_checkout = 1;\n-\t\telse if (!strcmp(argv[i], \"--term-good\") ||\n-\t\t\t !strcmp(argv[i], \"--term-old\")) {\n+\t\telse if (!strcmp(arg, \"--term-good\") ||\n+\t\t\t !strcmp(arg, \"--term-old\")) {\n+\t\t\tconst char *next_arg;\n+\t\t\tif (starts_with(argv[++i], \"'\"))\n+\t\t\t\tnext_arg = sq_dequote(xstrdup(argv[i]));\n+\t\t\telse\n+\t\t\t\tnext_arg = argv[i];\n \t\t\tmust_write_terms = 1;\n \t\t\tstrbuf_reset(&terms->term_good);\n-\t\t\tstrbuf_addstr(&terms->term_good, argv[++i]);\n-\t\t} else if (skip_prefix(argv[i], \"--term-good=\", &argv[i])) {\n+\t\t\tstrbuf_addstr(&terms->term_good, next_arg);\n+\t\t} else if (skip_prefix(arg, \"--term-good=\", &arg)) {\n \t\t\tmust_write_terms = 1;\n \t\t\tstrbuf_reset(&terms->term_good);\n-\t\t\tstrbuf_addstr(&terms->term_good, argv[i]);\n-\t\t} else if (skip_prefix(argv[i], \"--term-old=\", &argv[i])) {\n+\t\t\tstrbuf_addstr(&terms->term_good, arg);\n+\t\t} else if (skip_prefix(arg, \"--term-old=\", &arg)) {\n \t\t\tmust_write_terms = 1;\n \t\t\tstrbuf_reset(&terms->term_good);\n-\t\t\tstrbuf_addstr(&terms->term_good, argv[i]);\n-\t\t} else if (!strcmp(argv[i], \"--term-bad\") ||\n-\t\t\t !strcmp(argv[i], \"--term-new\")) {\n+\t\t\tstrbuf_addstr(&terms->term_good, arg);\n+\t\t} else if (!strcmp(arg, \"--term-bad\") ||\n+\t\t\t !strcmp(arg, \"--term-new\")) {\n+\t\t\tconst char *next_arg;\n+\t\t\tif (starts_with(argv[++i], \"'\"))\n+\t\t\t\tnext_arg = sq_dequote(xstrdup(argv[i]));\n+\t\t\telse\n+\t\t\t\tnext_arg = argv[i];\n \t\t\tmust_write_terms = 1;\n \t\t\tstrbuf_reset(&terms->term_bad);\n-\t\t\tstrbuf_addstr(&terms->term_bad, argv[++i]);\n-\t\t} else if (skip_prefix(argv[i], \"--term-bad=\", &argv[i])) {\n+\t\t\tstrbuf_addstr(&terms->term_bad, next_arg);\n+\t\t} else if (skip_prefix(arg, \"--term-bad=\", &arg)) {\n \t\t\tmust_write_terms = 1;\n \t\t\tstrbuf_reset(&terms->term_bad);\n-\t\t\tstrbuf_addstr(&terms->term_bad, argv[i]);\n-\t\t} else if (skip_prefix(argv[i], \"--term-new=\", &argv[i])) {\n+\t\t\tstrbuf_addstr(&terms->term_bad, arg);\n+\t\t} else if (skip_prefix(arg, \"--term-new=\", &arg)) {\n \t\t\tmust_write_terms = 1;\n \t\t\tstrbuf_reset(&terms->term_good);\n-\t\t\tstrbuf_addstr(&terms->term_good, argv[i]);\n-\t\t} else if (starts_with(argv[i], \"--\") &&\n-\t\t\t !one_of(argv[i], \"--term-good\", \"--term-bad\", NULL)) {\n+\t\t\tstrbuf_addstr(&terms->term_good, arg);\n+\t\t} else if (starts_with(arg, \"--\") &&\n+\t\t\t !one_of(arg, \"--term-good\", \"--term-bad\", NULL)) {\n \t\t\tstring_list_clear(&revs, 0);\n \t\t\tstring_list_clear(&states, 0);\n \t\t\tdie(_(\"unrecognised option: '%s'\"), argv[i]);\n@@ -613,7 +759,7 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,\n \t}\n \tfclose(fp);\n \n-\treturn 0;\n+\treturn bisect_auto_next(terms, NULL);\n }\n \n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n@@ -628,7 +774,9 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tCHECK_AND_SET_TERMS,\n \t\tBISECT_NEXT_CHECK,\n \t\tBISECT_TERMS,\n-\t\tBISECT_START\n+\t\tBISECT_START,\n+\t\tBISECT_NEXT,\n+\t\tBISECT_AUTO_NEXT,\n \t} cmdmode = 0;\n \tint no_checkout = 0, res = 0;\n \tstruct option options[] = {\n@@ -652,6 +800,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"print out the bisect terms\"), BISECT_TERMS),\n \t\tOPT_CMDMODE(0, \"bisect-start\", &cmdmode,\n \t\t\t N_(\"start the bisect session\"), BISECT_START),\n+\t\tOPT_CMDMODE(0, \"bisect-next\", &cmdmode,\n+\t\t\t N_(\"find the next bisection commit\"), BISECT_NEXT),\n+\t\tOPT_CMDMODE(0, \"bisect-auto-next\", &cmdmode,\n+\t\t\t N_(\"verify the next bisection state then find the next bisection state\"), BISECT_AUTO_NEXT),\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@@ -720,6 +872,18 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tstrbuf_addstr(&terms.term_bad, \"bad\");\n \t\tres = bisect_start(&terms, no_checkout, argv, argc);\n \t\tbreak;\n+\tcase BISECT_NEXT:\n+\t\tif (argc)\n+\t\t\tdie(_(\"--bisect-next requires 0 arguments\"));\n+\t\tget_terms(&terms);\n+\t\tres = bisect_next(&terms, prefix);\n+\t\tbreak;\n+\tcase BISECT_AUTO_NEXT:\n+\t\tif (argc)\n+\t\t\tdie(_(\"--bisect-auto-next requires 0 arguments\"));\n+\t\tget_terms(&terms);\n+\t\tres = bisect_auto_next(&terms, prefix);\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 f0896b3..d574c44 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -63,34 +63,13 @@ bisect_autostart() {\n \t\t\t[Nn]*)\n \t\t\t\texit ;;\n \t\t\tesac\n-\t\t\tbisect_start\n+\t\t\tgit bisect--helper --bisect-start\n \t\telse\n \t\t\texit 1\n \t\tfi\n \t}\n }\n \n-bisect_start() {\n-\tgit bisect--helper --bisect-start $@ || exit\n-\n-\t#\n-\t# Change state.\n-\t# In case of mistaken revs or checkout error, or signals received,\n-\t# \"bisect_auto_next\" below may exit or misbehave.\n-\t# We have to trap this to be able to clean up using\n-\t# \"bisect_clean_state\".\n-\t#\n-\ttrap 'git bisect--helper --bisect-clean-state' 0\n-\ttrap 'exit 255' 1 2 3 15\n-\t#\n-\t# Check if we can proceed to the next bisect state.\n-\t#\n-\tget_terms\n-\tbisect_auto_next\n-\n-\ttrap '-' 0\n-}\n-\n bisect_skip() {\n \tall=''\n \tfor arg in \"$@\"\n@@ -109,6 +88,7 @@ bisect_skip() {\n bisect_state() {\n \tbisect_autostart\n \tstate=$1\n+\tget_terms\n \tgit bisect--helper --check-and-set-terms $state $TERM_GOOD $TERM_BAD || exit\n \tget_terms\n \tcase \"$#,$state\" in\n@@ -139,45 +119,7 @@ bisect_state() {\n \t*)\n \t\tusage ;;\n \tesac\n-\tbisect_auto_next\n-}\n-\n-bisect_auto_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-\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-\tres=$?\n-\n-\t# Check if we should exit because bisection is finished\n-\tif test $res -eq 10\n-\tthen\n-\t\tbad_rev=$(git show-ref --hash --verify refs/bisect/$TERM_BAD)\n-\t\tbad_commit=$(git show-branch $bad_rev)\n-\t\techo \"# first $TERM_BAD commit: $bad_commit\" >>\"$GIT_DIR/BISECT_LOG\"\n-\t\texit 0\n-\telif test $res -eq 2\n-\tthen\n-\t\techo \"# only skipped commits left to test\" >>\"$GIT_DIR/BISECT_LOG\"\n-\t\tgood_revs=$(git for-each-ref --format=\"%(objectname)\" \"refs/bisect/$TERM_GOOD-*\")\n-\t\tfor skipped in $(git rev-list refs/bisect/$TERM_BAD --not $good_revs)\n-\t\tdo\n-\t\t\tskipped_commit=$(git show-branch $skipped)\n-\t\t\techo \"# possible first $TERM_BAD commit: $skipped_commit\" >>\"$GIT_DIR/BISECT_LOG\"\n-\t\tdone\n-\t\texit $res\n-\tfi\n-\n-\t# Check for an error in the bisection process\n-\ttest $res -ne 0 && exit $res\n-\n-\treturn 0\n+\tgit bisect--helper --bisect-auto-next || exit\n }\n \n bisect_visualize() {\n@@ -221,8 +163,7 @@ bisect_replay () {\n \t\tget_terms\n \t\tcase \"$command\" in\n \t\tstart)\n-\t\t\tcmd=\"bisect_start $rev\"\n-\t\t\teval \"$cmd\" ;;\n+\t\t\teval \"git bisect--helper --bisect-start $rev\" ;;\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@@ -231,7 +172,7 @@ bisect_replay () {\n \t\t\tdie \"$(gettext \"?? what are you talking about?\")\" ;;\n \t\tesac\n \tdone <\"$file\"\n-\tbisect_auto_next\n+\tgit bisect--helper --bisect-auto-next\n }\n \n bisect_run () {\n@@ -319,14 +260,15 @@ case \"$#\" in\n \thelp)\n \t\tgit bisect -h ;;\n \tstart)\n-\t\tbisect_start \"$@\" ;;\n+\t\tgit bisect--helper --bisect-start \"$@\" ;;\n \tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n \t\tbisect_state \"$cmd\" \"$@\" ;;\n \tskip)\n \t\tbisect_skip \"$@\" ;;\n \tnext)\n \t\t# Not sure we want \"next\" at the UI level anymore.\n-\t\tbisect_next \"$@\" ;;\n+\t\tget_terms\n+\t\tgit bisect--helper --bisect-next \"$@\" || exit ;;\n \tvisualize|view)\n \t\tbisect_visualize \"$@\" ;;\n \treset)\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299903","messageId":"01020156b73fe6cf-0e14441e-a8cf-4236-8da4-f6c0fd347ad5-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 16/27] bisect--helper: retire `--next-all` subcommand","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:01:12Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"The `--next-all` subcommand is no longer used in the shell script and\nthe function `bisect_next_all()` is called from the C implementation of\n`bisect_next()`.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 8 +-------\n 1 file changed, 1 insertion(+), 7 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex e351794..8cbcc3b 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -20,7 +20,6 @@ static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NAMES\")\n \n static const char * const git_bisect_helper_usage[] = {\n-\tN_(\"git bisect--helper --next-all [--no-checkout]\"),\n \tN_(\"git bisect--helper --write-terms <bad_term> <good_term>\"),\n \tN_(\"git bisect--helper --bisect-reset [<commit>]\"),\n \tN_(\"git bisect--helper --bisect-write <state> <revision> <TERM_GOOD> <TERM_BAD> [<nolog>]\"),\n@@ -764,8 +763,7 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n-\t\tNEXT_ALL = 1,\n-\t\tWRITE_TERMS,\n+\t\tWRITE_TERMS = 1,\n \t\tBISECT_RESET,\n \t\tCHECK_EXPECTED_REVS,\n \t\tBISECT_WRITE,\n@@ -778,8 +776,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t} cmdmode = 0;\n \tint no_checkout = 0, res = 0;\n \tstruct option options[] = {\n-\t\tOPT_CMDMODE(0, \"next-all\", &cmdmode,\n-\t\t\t N_(\"perform 'git bisect next'\"), NEXT_ALL),\n \t\tOPT_CMDMODE(0, \"write-terms\", &cmdmode,\n \t\t\t N_(\"write the terms to .git/BISECT_TERMS\"), WRITE_TERMS),\n \t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n@@ -816,8 +812,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \n \tswitch (cmdmode) {\n \tint nolog;\n-\tcase NEXT_ALL:\n-\t\treturn bisect_next_all(prefix, no_checkout);\n \tcase WRITE_TERMS:\n \t\tif (argc != 2)\n \t\t\tdie(_(\"--write-terms requires two arguments\"));\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299904","messageId":"01020156b73fe673-7ca3a15e-3a63-4ea9-9c8b-b57dc0ea2b0e-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 06/27] wrapper: move is_empty_file() and rename it as is_empty_or_missing_file()","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:01:15Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"is_empty_file() can help to refactor a lot of code. This will be very\nhelpful in porting \"git bisect\" to C.\n\nSuggested-by: Torsten Bögershausen <tboegi@web.de>\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/am.c | 20 ++------------------\n cache.h      |  3 +++\n wrapper.c    | 13 +++++++++++++\n 3 files changed, 18 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 739b34d..9e1e9d6 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -30,22 +30,6 @@\n #include \"mailinfo.h\"\n \n /**\n- * Returns 1 if the file is empty or does not exist, 0 otherwise.\n- */\n-static int is_empty_file(const char *filename)\n-{\n-\tstruct stat st;\n-\n-\tif (stat(filename, &st) < 0) {\n-\t\tif (errno == ENOENT)\n-\t\t\treturn 1;\n-\t\tdie_errno(_(\"could not stat %s\"), filename);\n-\t}\n-\n-\treturn !st.st_size;\n-}\n-\n-/**\n  * Returns the length of the first line of msg.\n  */\n static int linelen(const char *msg)\n@@ -1324,7 +1308,7 @@ static int parse_mail(struct am_state *state, const char *mail)\n \t\tgoto finish;\n \t}\n \n-\tif (is_empty_file(am_path(state, \"patch\"))) {\n+\tif (is_empty_or_missing_file(am_path(state, \"patch\"))) {\n \t\tprintf_ln(_(\"Patch is empty. Was it split wrong?\"));\n \t\tdie_user_resolve(state);\n \t}\n@@ -1896,7 +1880,7 @@ static void am_run(struct am_state *state, int resume)\n \t\tresume = 0;\n \t}\n \n-\tif (!is_empty_file(am_path(state, \"rewritten\"))) {\n+\tif (!is_empty_or_missing_file(am_path(state, \"rewritten\"))) {\n \t\tassert(state->rebasing);\n \t\tcopy_notes_for_rebase(state);\n \t\trun_post_rewrite_hook(state);\ndiff --git a/cache.h b/cache.h\nindex b780a91..49f214b 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1916,4 +1916,7 @@ void sleep_millisec(int millisec);\n  */\n void safe_create_dir(const char *dir, int share);\n \n+/* Return 1 if the file is empty or does not exists, 0 otherwise. */\n+extern int is_empty_or_missing_file(const char *filename);\n+\n #endif /* CACHE_H */\ndiff --git a/wrapper.c b/wrapper.c\nindex e7f1979..78f6431 100644\n--- a/wrapper.c\n+++ b/wrapper.c\n@@ -679,3 +679,16 @@ void sleep_millisec(int millisec)\n {\n \tpoll(NULL, 0, millisec);\n }\n+\n+int is_empty_or_missing_file(const char *filename)\n+{\n+\tstruct stat st;\n+\n+\tif (stat(filename, &st) < 0) {\n+\t\tif (errno == ENOENT)\n+\t\t\treturn 1;\n+\t\tdie_errno(_(\"could not stat %s\"), filename);\n+\t}\n+\n+\treturn !st.st_size;\n+}\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299905","messageId":"01020156b73fe6e4-d45cf1f7-03a3-4566-95d1-73788c5ab2f9-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 27/27] bisect--helper: remove the dequote in bisect_start()","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:01:16Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Dequoting the arguments was introduced in 25b48b5c to port the function\n`bisect_next()` but after the `bisect_replay()` porting, the dequoting\nis carried out itself when it passes the arguments to `bisect_start()`\nin a simpler way thus dequoting again isn't required. So remove the\nextra \"deqouting\" code introduced by the commit 25b48b5c.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 59 ++++++++++++++++--------------------------------\n 1 file changed, 20 insertions(+), 39 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 7577b69e..8bf495c 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -541,67 +541,48 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,\n \t\tno_checkout = 1;\n \n \tfor (i = 0; i < argc; i++) {\n-\t\tconst char *arg;\n-\t\tif (starts_with(argv[i], \"'\"))\n-\t\t\targ = sq_dequote(xstrdup(argv[i]));\n-\t\telse\n-\t\t\targ = argv[i];\n-\t\tif (!strcmp(arg, \"--\")) {\n+\t\tif (!strcmp(argv[i], \"--\")) {\n \t\t\thas_double_dash = 1;\n \t\t\tbreak;\n \t\t}\n \t}\n \n \tfor (i = 0; i < argc; i++) {\n-\t\tconst char *arg, *commit_id;\n-\t\tif (starts_with(argv[i], \"'\"))\n-\t\t\targ = sq_dequote(xstrdup(argv[i]));\n-\t\telse\n-\t\t\targ = argv[i];\n-\t\tcommit_id = xstrfmt(\"%s^{commit}\", arg);\n+\t\tconst char  *commit_id;\n+\t\tcommit_id = xstrfmt(\"%s^{commit}\", argv[i]);\n \t\tif (!strcmp(argv[i], \"--\")) {\n \t\t\thas_double_dash = 1;\n \t\t\tbreak;\n-\t\t} else if (!strcmp(arg, \"--no-checkout\"))\n+\t\t} else if (!strcmp(argv[i], \"--no-checkout\"))\n \t\t\tno_checkout = 1;\n-\t\telse if (!strcmp(arg, \"--term-good\") ||\n-\t\t\t !strcmp(arg, \"--term-old\")) {\n-\t\t\tconst char *next_arg;\n-\t\t\tif (starts_with(argv[++i], \"'\"))\n-\t\t\t\tnext_arg = sq_dequote(xstrdup(argv[i]));\n-\t\t\telse\n-\t\t\t\tnext_arg = argv[i];\n+\t\telse if (!strcmp(argv[i], \"--term-good\") ||\n+\t\t\t !strcmp(argv[i], \"--term-old\")) {\n \t\t\tmust_write_terms = 1;\n \t\t\tstrbuf_reset(&terms->term_good);\n-\t\t\tstrbuf_addstr(&terms->term_good, next_arg);\n-\t\t} else if (skip_prefix(arg, \"--term-good=\", &arg)) {\n+\t\t\tstrbuf_addstr(&terms->term_good, argv[++i]);\n+\t\t} else if (skip_prefix(argv[i], \"--term-good=\", &argv[i])) {\n \t\t\tmust_write_terms = 1;\n \t\t\tstrbuf_reset(&terms->term_good);\n-\t\t\tstrbuf_addstr(&terms->term_good, arg);\n-\t\t} else if (skip_prefix(arg, \"--term-old=\", &arg)) {\n+\t\t\tstrbuf_addstr(&terms->term_good, argv[i]);\n+\t\t} else if (skip_prefix(argv[i], \"--term-old=\", &argv[i])) {\n \t\t\tmust_write_terms = 1;\n \t\t\tstrbuf_reset(&terms->term_good);\n-\t\t\tstrbuf_addstr(&terms->term_good, arg);\n-\t\t} else if (!strcmp(arg, \"--term-bad\") ||\n-\t\t\t !strcmp(arg, \"--term-new\")) {\n-\t\t\tconst char *next_arg;\n-\t\t\tif (starts_with(argv[++i], \"'\"))\n-\t\t\t\tnext_arg = sq_dequote(xstrdup(argv[i]));\n-\t\t\telse\n-\t\t\t\tnext_arg = argv[i];\n+\t\t\tstrbuf_addstr(&terms->term_good, argv[i]);\n+\t\t} else if (!strcmp(argv[i], \"--term-bad\") ||\n+\t\t\t !strcmp(argv[i], \"--term-new\")) {\n \t\t\tmust_write_terms = 1;\n \t\t\tstrbuf_reset(&terms->term_bad);\n-\t\t\tstrbuf_addstr(&terms->term_bad, next_arg);\n-\t\t} else if (skip_prefix(arg, \"--term-bad=\", &arg)) {\n+\t\t\tstrbuf_addstr(&terms->term_bad, argv[++i]);\n+\t\t} else if (skip_prefix(argv[i], \"--term-bad=\", &argv[i])) {\n \t\t\tmust_write_terms = 1;\n \t\t\tstrbuf_reset(&terms->term_bad);\n-\t\t\tstrbuf_addstr(&terms->term_bad, arg);\n-\t\t} else if (skip_prefix(arg, \"--term-new=\", &arg)) {\n+\t\t\tstrbuf_addstr(&terms->term_bad, argv[i]);\n+\t\t} else if (skip_prefix(argv[i], \"--term-new=\", &argv[i])) {\n \t\t\tmust_write_terms = 1;\n \t\t\tstrbuf_reset(&terms->term_good);\n-\t\t\tstrbuf_addstr(&terms->term_good, arg);\n-\t\t} else if (starts_with(arg, \"--\") &&\n-\t\t\t !one_of(arg, \"--term-good\", \"--term-bad\", NULL)) {\n+\t\t\tstrbuf_addstr(&terms->term_good, argv[i]);\n+\t\t} else if (starts_with(argv[i], \"--\") &&\n+\t\t\t !one_of(argv[i], \"--term-good\", \"--term-bad\", NULL)) {\n \t\t\tstring_list_clear(&revs, 0);\n \t\t\tstring_list_clear(&states, 0);\n \t\t\tdie(_(\"unrecognised option: '%s'\"), argv[i]);\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299906","messageId":"01020156b73fe666-a66817f8-949c-46a0-9eb7-937c5ecd3629-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 05/27] t6030: explicitly test for bisection cleanup","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:01:42Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Add test to explicitly check that 'git bisect reset' is working as\nexpected. This is already covered implicitly by the test suite.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n\n---\nI faced this problem while converting `bisect_clean_state` and the tests\nwhere showing breakages but it wasn't clear as to where exactly are they\nbreaking. This will patch  will help in that. Also I tested the test\ncoverage of the test suite before this patch and it covers this (I did\nthis by purposely changing names of files in git-bisect.sh and running\nthe test suite).\n---\n t/t6030-bisect-porcelain.sh | 17 +++++++++++++++++\n 1 file changed, 17 insertions(+)\n\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex 5e5370f..18e7998 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -894,4 +894,21 @@ test_expect_success 'bisect start takes options and revs in any order' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'git bisect reset cleans bisection state properly' '\n+\tgit bisect reset &&\n+\tgit bisect start &&\n+\tgit bisect good $HASH1 &&\n+\tgit bisect bad $HASH4 &&\n+\tgit bisect reset &&\n+\ttest -z \"$(git for-each-ref \"refs/bisect/*\")\" &&\n+\ttest_path_is_missing \"$GIT_DIR/BISECT_EXPECTED_REV\" &&\n+\ttest_path_is_missing \"$GIT_DIR/BISECT_ANCESTORS_OK\" &&\n+\ttest_path_is_missing \"$GIT_DIR/BISECT_LOG\" &&\n+\ttest_path_is_missing \"$GIT_DIR/BISECT_RUN\" &&\n+\ttest_path_is_missing \"$GIT_DIR/BISECT_TERMS\" &&\n+\ttest_path_is_missing \"$GIT_DIR/head-name\" &&\n+\ttest_path_is_missing \"$GIT_DIR/BISECT_HEAD\" &&\n+\ttest_path_is_missing \"$GIT_DIR/BISECT_START\"\n+'\n+\n test_done\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299907","messageId":"01020156b73fe6d0-0e2c0b03-999c-4ce9-9432-8cf1a6858c48-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 19/27] bisect--helper: retire `--check-expected-revs` subcommand","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:01:45Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"The `--check-expected-revs` subcommand is no longer used in the shell\nscript and the function `check_expected_revs()` is called from the C\nimplementation of `bisect_next()`.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 6 ------\n 1 file changed, 6 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 861c07d..6cc990b 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -870,7 +870,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tenum {\n \t\tWRITE_TERMS = 1,\n \t\tBISECT_RESET,\n-\t\tCHECK_EXPECTED_REVS,\n \t\tBISECT_WRITE,\n \t\tCHECK_AND_SET_TERMS,\n \t\tBISECT_NEXT_CHECK,\n@@ -887,8 +886,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"write the terms to .git/BISECT_TERMS\"), WRITE_TERMS),\n \t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n \t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n-\t\tOPT_CMDMODE(0, \"check-expected-revs\", &cmdmode,\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@@ -933,9 +930,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"--bisect-reset requires either zero or one arguments\"));\n \t\tres = bisect_reset(argc ? argv[0] : NULL);\n \t\tbreak;\n-\tcase CHECK_EXPECTED_REVS:\n-\t\tres = check_expected_revs(argv, argc);\n-\t\tbreak;\n \tcase BISECT_WRITE:\n \t\tif (argc != 4 && argc != 5)\n \t\t\tdie(_(\"--bisect-write requires either 4 or 5 arguments\"));\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299908","messageId":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156a48144f8-c0e127c1-8cd9-4295-ac16-449a54315cac-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 01/27] bisect--helper: use OPT_CMDMODE instead of OPT_BOOL","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:01:46Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"`--next-all` is meant to be used as a subcommand to support multiple\n\"operation mode\" though the current implementation does not contain any\nother subcommand along side with `--next-all` but further commits will\ninclude some more subcommands.\n\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 17 +++++++++++------\n 1 file changed, 11 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 3324229..8111c91 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -10,11 +10,11 @@ static const char * const git_bisect_helper_usage[] = {\n \n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n-\tint next_all = 0;\n+\tenum { NEXT_ALL = 1 } cmdmode = 0;\n \tint no_checkout = 0;\n \tstruct option options[] = {\n-\t\tOPT_BOOL(0, \"next-all\", &next_all,\n-\t\t\t N_(\"perform 'git bisect next'\")),\n+\t\tOPT_CMDMODE(0, \"next-all\", &cmdmode,\n+\t\t\t N_(\"perform 'git bisect next'\"), NEXT_ALL),\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@@ -23,9 +23,14 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options,\n \t\t\t     git_bisect_helper_usage, 0);\n \n-\tif (!next_all)\n+\tif (!cmdmode)\n \t\tusage_with_options(git_bisect_helper_usage, options);\n \n-\t/* next-all */\n-\treturn bisect_next_all(prefix, no_checkout);\n+\tswitch (cmdmode) {\n+\tcase NEXT_ALL:\n+\t\treturn bisect_next_all(prefix, no_checkout);\n+\tdefault:\n+\t\tdie(\"BUG: unknown subcommand '%d'\", cmdmode);\n+\t}\n+\treturn 0;\n }\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299909","messageId":"01020156b73fe69a-13136cfb-4daa-4f5d-9b56-537adf2c6942-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 07/27] bisect--helper: `bisect_reset` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:01:51Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Reimplement `bisect_reset` shell function in C and add a `--bisect-reset`\nsubcommand to `git bisect--helper` to call it from git-bisect.sh .\n\nUsing `bisect_reset` subcommand is a temporary measure to port shell\nfunctions to C so as to use the existing test suite. As more functions\nare ported, this subcommand would be retired but its implementation will\nbe called by some other method.\n\nNote: --bisect-clean-state subcommand has not been retired as there are\nstill a function namely `bisect_start()` which still uses this\nsubcommand.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-\n git-bisect.sh            | 28 ++--------------------------\n 2 files changed, 49 insertions(+), 27 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex e50934c..9aba094 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -3,17 +3,22 @@\n #include \"parse-options.h\"\n #include \"bisect.h\"\n #include \"refs.h\"\n+#include \"dir.h\"\n+#include \"argv-array.h\"\n+#include \"run-command.h\"\n \n static GIT_PATH_FUNC(git_path_bisect_terms, \"BISECT_TERMS\")\n static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXPECTED_REV\")\n static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, \"BISECT_ANCESTORS_OK\")\n static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n+static GIT_PATH_FUNC(git_path_bisect_head, \"BISECT_HEAD\")\n \n static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --next-all [--no-checkout]\"),\n \tN_(\"git bisect--helper --write-terms <bad_term> <good_term>\"),\n \tN_(\"git bisect--helper --bisect-clean-state\"),\n+\tN_(\"git bisect--helper --bisect-reset [<commit>]\"),\n \tNULL\n };\n \n@@ -84,12 +89,47 @@ static int write_terms(const char *bad, const char *good)\n \treturn (res < 0) ? -1 : 0;\n }\n \n+static int bisect_reset(const char *commit)\n+{\n+\tstruct strbuf branch = STRBUF_INIT;\n+\n+\tif (!commit) {\n+\t\tif (strbuf_read_file(&branch, git_path_bisect_start(), 0) < 1) {\n+\t\t\tprintf(\"We are not bisecting.\\n\");\n+\t\t\treturn 0;\n+\t\t}\n+\t\tstrbuf_rtrim(&branch);\n+\t} else {\n+\t\tstruct object_id oid;\n+\t\tif (get_oid(commit, &oid))\n+\t\t\treturn error(_(\"'%s' is not a valid commit\"), commit);\n+\t\tstrbuf_addstr(&branch, commit);\n+\t}\n+\n+\tif (!file_exists(git_path_bisect_head())) {\n+\t\tstruct argv_array argv = ARGV_ARRAY_INIT;\n+\t\targv_array_pushl(&argv, \"checkout\", branch.buf, \"--\", NULL);\n+\t\tif (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {\n+\t\t\terror(_(\"Could not check out original HEAD '%s'. Try \"\n+\t\t\t\t\"'git bisect reset <commit>'.\"), branch.buf);\n+\t\t\tstrbuf_release(&branch);\n+\t\t\targv_array_clear(&argv);\n+\t\t\treturn -1;\n+\t\t}\n+\t\targv_array_clear(&argv);\n+\t}\n+\n+\tstrbuf_release(&branch);\n+\treturn bisect_clean_state();\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n \t\tNEXT_ALL = 1,\n \t\tWRITE_TERMS,\n-\t\tBISECT_CLEAN_STATE\n+\t\tBISECT_CLEAN_STATE,\n+\t\tBISECT_RESET\n \t} cmdmode = 0;\n \tint no_checkout = 0;\n \tstruct option options[] = {\n@@ -99,6 +139,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"write the terms to .git/BISECT_TERMS\"), WRITE_TERMS),\n \t\tOPT_CMDMODE(0, \"bisect-clean-state\", &cmdmode,\n \t\t\t N_(\"cleanup the bisection state\"), BISECT_CLEAN_STATE),\n+\t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n+\t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\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@@ -121,6 +163,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tif (argc != 0)\n \t\t\tdie(_(\"--bisect-clean-state requires no arguments\"));\n \t\treturn bisect_clean_state();\n+\tcase BISECT_RESET:\n+\t\tif (argc > 1)\n+\t\t\tdie(_(\"--bisect-reset requires either zero or one arguments\"));\n+\t\treturn bisect_reset(argc ? argv[0] : NULL);\n \tdefault:\n \t\tdie(\"BUG: unknown subcommand '%d'\", cmdmode);\n \t}\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex f1202df..442397b 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -409,35 +409,11 @@ bisect_visualize() {\n \teval '\"$@\"' --bisect -- $(cat \"$GIT_DIR/BISECT_NAMES\")\n }\n \n-bisect_reset() {\n-\ttest -s \"$GIT_DIR/BISECT_START\" || {\n-\t\tgettextln \"We are not bisecting.\"\n-\t\treturn\n-\t}\n-\tcase \"$#\" in\n-\t0) branch=$(cat \"$GIT_DIR/BISECT_START\") ;;\n-\t1) git rev-parse --quiet --verify \"$1^{commit}\" >/dev/null || {\n-\t\t\tinvalid=\"$1\"\n-\t\t\tdie \"$(eval_gettext \"'\\$invalid' is not a valid commit\")\"\n-\t\t}\n-\t\tbranch=\"$1\" ;;\n-\t*)\n-\t\tusage ;;\n-\tesac\n-\n-\tif ! test -f \"$GIT_DIR/BISECT_HEAD\" && ! git checkout \"$branch\" --\n-\tthen\n-\t\tdie \"$(eval_gettext \"Could not check out original HEAD '\\$branch'.\n-Try 'git bisect reset <commit>'.\")\"\n-\tfi\n-\tgit bisect--helper --bisect-clean-state || exit\n-}\n-\n bisect_replay () {\n \tfile=\"$1\"\n \ttest \"$#\" -eq 1 || die \"$(gettext \"No logfile given\")\"\n \ttest -r \"$file\" || die \"$(eval_gettext \"cannot read \\$file for replaying\")\"\n-\tbisect_reset\n+\tgit bisect--helper --bisect-reset || exit\n \twhile read git bisect command rev\n \tdo\n \t\ttest \"$git $bisect\" = \"git bisect\" || test \"$git\" = \"git-bisect\" || continue\n@@ -627,7 +603,7 @@ case \"$#\" in\n \tvisualize|view)\n \t\tbisect_visualize \"$@\" ;;\n \treset)\n-\t\tbisect_reset \"$@\" ;;\n+\t\tgit bisect--helper --bisect-reset \"$@\" ;;\n \treplay)\n \t\tbisect_replay \"$@\" ;;\n \tlog)\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299910","messageId":"01020156b73fe6c6-60f4f6c2-9c39-4840-bbbf-18902961d57f-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 15/27] bisect--helper: retire `--bisect-clean-state` subcommand","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:01:52Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"The `bisect-clean-state` subcommand is no longer used in the shell\nscript while the C code uses `bisect_clean_state()` thus remove the\nsubcommand.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 9 ---------\n 1 file changed, 9 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex ef7b3a1..e351794 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -22,7 +22,6 @@ static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NAMES\")\n static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --next-all [--no-checkout]\"),\n \tN_(\"git bisect--helper --write-terms <bad_term> <good_term>\"),\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-check-and-set-terms <command> <TERM_GOOD> <TERM_BAD>\"),\n@@ -767,7 +766,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tenum {\n \t\tNEXT_ALL = 1,\n \t\tWRITE_TERMS,\n-\t\tBISECT_CLEAN_STATE,\n \t\tBISECT_RESET,\n \t\tCHECK_EXPECTED_REVS,\n \t\tBISECT_WRITE,\n@@ -784,8 +782,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"perform 'git bisect next'\"), NEXT_ALL),\n \t\tOPT_CMDMODE(0, \"write-terms\", &cmdmode,\n \t\t\t N_(\"write the terms to .git/BISECT_TERMS\"), WRITE_TERMS),\n-\t\tOPT_CMDMODE(0, \"bisect-clean-state\", &cmdmode,\n-\t\t\t N_(\"cleanup the bisection state\"), BISECT_CLEAN_STATE),\n \t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n \t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n \t\tOPT_CMDMODE(0, \"check-expected-revs\", &cmdmode,\n@@ -827,11 +823,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"--write-terms requires two arguments\"));\n \t\tres = write_terms(argv[0], argv[1]);\n \t\tbreak;\n-\tcase BISECT_CLEAN_STATE:\n-\t\tif (argc != 0)\n-\t\t\tdie(_(\"--bisect-clean-state requires no arguments\"));\n-\t\tres = bisect_clean_state();\n-\t\tbreak;\n \tcase BISECT_RESET:\n \t\tif (argc > 1)\n \t\t\tdie(_(\"--bisect-reset requires either zero or one arguments\"));\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299911","messageId":"01020156b73fe6a7-2e9df745-e3f4-4830-a1af-4acae7964c11-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 09/27] bisect--helper: `bisect_write` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:01:54Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Reimplement the `bisect_write` shell function in C and add a\n`bisect-write` subcommand to `git bisect--helper` to call it from\ngit-bisect.sh\n\nUsing `--bisect-write` 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 but its implementation will\nbe called by some other methods.\n\nNote: bisect_write() uses two variables namely TERM_GOOD and TERM_BAD\nfrom the global shell script thus we need to pass it to the subcommand\nusing the arguments. We then store them in a struct bisect_terms and\npass the memory address around functions.\n\nThis patch also introduces new methods namely bisect_state_init() and\nbisect_terms_release() for easy memory management for the struct\nbisect_terms.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 97 ++++++++++++++++++++++++++++++++++++++++++++----\n git-bisect.sh            | 25 ++-----------\n 2 files changed, 94 insertions(+), 28 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 711be75..5364960 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -19,9 +19,27 @@ static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --write-terms <bad_term> <good_term>\"),\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 \tNULL\n };\n \n+struct bisect_terms {\n+\tstruct strbuf term_good;\n+\tstruct strbuf term_bad;\n+};\n+\n+static void bisect_terms_init(struct bisect_terms *terms)\n+{\n+\tstrbuf_init(&terms->term_good, 0);\n+\tstrbuf_init(&terms->term_bad, 0);\n+}\n+\n+static void bisect_terms_release(struct bisect_terms *terms)\n+{\n+\tstrbuf_release(&terms->term_good);\n+\tstrbuf_release(&terms->term_bad);\n+}\n+\n /*\n  * Check whether the string `term` belongs to the set of strings\n  * included in the variable arguments.\n@@ -149,6 +167,52 @@ static int check_expected_revs(const char **revs, int rev_nr)\n \treturn 0;\n }\n \n+static int bisect_write(const char *state, const char *rev,\n+\t\t\tconst struct bisect_terms *terms, int nolog)\n+{\n+\tstruct strbuf tag = STRBUF_INIT;\n+\tstruct strbuf commit_name = STRBUF_INIT;\n+\tstruct object_id oid;\n+\tstruct commit *commit;\n+\tstruct pretty_print_context pp = {0};\n+\tFILE *fp;\n+\n+\tif (!strcmp(state, terms->term_bad.buf))\n+\t\tstrbuf_addf(&tag, \"refs/bisect/%s\", state);\n+\telse if (one_of(state, terms->term_good.buf, \"skip\", NULL))\n+\t\tstrbuf_addf(&tag, \"refs/bisect/%s-%s\", state, rev);\n+\telse\n+\t\treturn error(_(\"Bad bisect_write argument: %s\"), state);\n+\n+\tif (get_oid(rev, &oid)) {\n+\t\tstrbuf_release(&tag);\n+\t\treturn error(_(\"couldn't get the oid of the rev '%s'\"), rev);\n+\t}\n+\n+\tif (update_ref(NULL, tag.buf, oid.hash, NULL, 0,\n+\t\t       UPDATE_REFS_MSG_ON_ERR)) {\n+\t\tstrbuf_release(&tag);\n+\t\treturn -1;\n+\t}\n+\tstrbuf_release(&tag);\n+\n+\tfp = fopen(git_path_bisect_log(), \"a\");\n+\tif (!fp)\n+\t\treturn error_errno(_(\"couldn't open the file '%s'\"), git_path_bisect_log());\n+\n+\tcommit = lookup_commit_reference(oid.hash);\n+\tformat_commit_message(commit, \"%s\", &commit_name, &pp);\n+\tfprintf(fp, \"# %s: [%s] %s\\n\", state, sha1_to_hex(oid.hash),\n+\t\tcommit_name.buf);\n+\tstrbuf_release(&commit_name);\n+\n+\tif (!nolog)\n+\t\tfprintf(fp, \"git bisect %s %s\\n\", state, rev);\n+\n+\tfclose(fp);\n+\treturn 0;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -156,9 +220,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tWRITE_TERMS,\n \t\tBISECT_CLEAN_STATE,\n \t\tBISECT_RESET,\n-\t\tCHECK_EXPECTED_REVS\n+\t\tCHECK_EXPECTED_REVS,\n+\t\tBISECT_WRITE\n \t} cmdmode = 0;\n-\tint no_checkout = 0;\n+\tint no_checkout = 0, res = 0;\n \tstruct option options[] = {\n \t\tOPT_CMDMODE(0, \"next-all\", &cmdmode,\n \t\t\t N_(\"perform 'git bisect next'\"), NEXT_ALL),\n@@ -170,10 +235,14 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n \t\tOPT_CMDMODE(0, \"check-expected-revs\", &cmdmode,\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_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 \t};\n+\tstruct bisect_terms terms;\n+\tbisect_terms_init(&terms);\n \n \targc = parse_options(argc, argv, prefix, options,\n \t\t\t     git_bisect_helper_usage, 0);\n@@ -182,24 +251,38 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(git_bisect_helper_usage, options);\n \n \tswitch (cmdmode) {\n+\tint nolog;\n \tcase NEXT_ALL:\n \t\treturn bisect_next_all(prefix, no_checkout);\n \tcase WRITE_TERMS:\n \t\tif (argc != 2)\n \t\t\tdie(_(\"--write-terms requires two arguments\"));\n-\t\treturn write_terms(argv[0], argv[1]);\n+\t\tres = write_terms(argv[0], argv[1]);\n+\t\tbreak;\n \tcase BISECT_CLEAN_STATE:\n \t\tif (argc != 0)\n \t\t\tdie(_(\"--bisect-clean-state requires no arguments\"));\n-\t\treturn bisect_clean_state();\n+\t\tres = bisect_clean_state();\n+\t\tbreak;\n \tcase BISECT_RESET:\n \t\tif (argc > 1)\n \t\t\tdie(_(\"--bisect-reset requires either zero or one arguments\"));\n-\t\treturn bisect_reset(argc ? argv[0] : NULL);\n+\t\tres = bisect_reset(argc ? argv[0] : NULL);\n+\t\tbreak;\n \tcase CHECK_EXPECTED_REVS:\n-\t\treturn check_expected_revs(argv, argc);\n+\t\tres = check_expected_revs(argv, argc);\n+\t\tbreak;\n+\tcase BISECT_WRITE:\n+\t\tif (argc != 4 && argc != 5)\n+\t\t\tdie(_(\"--bisect-write requires either 4 or 5 arguments\"));\n+\t\tnolog = (argc == 5) && !strcmp(argv[4], \"nolog\");\n+\t\tstrbuf_addstr(&terms.term_good, argv[2]);\n+\t\tstrbuf_addstr(&terms.term_bad, argv[3]);\n+\t\tres = bisect_write(argv[0], argv[1], &terms, nolog);\n+\t\tbreak;\n \tdefault:\n \t\tdie(\"BUG: unknown subcommand '%d'\", cmdmode);\n \t}\n-\treturn 0;\n+\tbisect_terms_release(&terms);\n+\treturn res;\n }\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex c3e43248..dfdec33 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -144,7 +144,7 @@ bisect_start() {\n \t\t0) state=$TERM_BAD ; bad_seen=1 ;;\n \t\t*) state=$TERM_GOOD ;;\n \t\tesac\n-\t\teval=\"$eval bisect_write '$state' '$rev' 'nolog' &&\"\n+\t\teval=\"$eval git bisect--helper --bisect-write '$state' '$rev' '$TERM_GOOD' '$TERM_BAD' 'nolog' &&\"\n \tdone\n \t#\n \t# Verify HEAD.\n@@ -220,23 +220,6 @@ bisect_start() {\n \ttrap '-' 0\n }\n \n-bisect_write() {\n-\tstate=\"$1\"\n-\trev=\"$2\"\n-\tnolog=\"$3\"\n-\tcase \"$state\" in\n-\t\t\"$TERM_BAD\")\n-\t\t\ttag=\"$state\" ;;\n-\t\t\"$TERM_GOOD\"|skip)\n-\t\t\ttag=\"$state\"-\"$rev\" ;;\n-\t\t*)\n-\t\t\tdie \"$(eval_gettext \"Bad bisect_write argument: \\$state\")\" ;;\n-\tesac\n-\tgit update-ref \"refs/bisect/$tag\" \"$rev\" || exit\n-\techo \"# $state: $(git show-branch $rev)\" >>\"$GIT_DIR/BISECT_LOG\"\n-\ttest -n \"$nolog\" || echo \"git bisect $state $rev\" >>\"$GIT_DIR/BISECT_LOG\"\n-}\n-\n bisect_skip() {\n \tall=''\n \tfor arg in \"$@\"\n@@ -263,7 +246,7 @@ bisect_state() {\n \t\tbisected_head=$(bisect_head)\n \t\trev=$(git rev-parse --verify \"$bisected_head\") ||\n \t\t\tdie \"$(eval_gettext \"Bad rev input: \\$bisected_head\")\"\n-\t\tbisect_write \"$state\" \"$rev\"\n+\t\tgit bisect--helper --bisect-write \"$state\" \"$rev\" \"$TERM_GOOD\" \"$TERM_BAD\" || exit\n \t\tgit bisect--helper --check-expected-revs \"$rev\" ;;\n \t2,\"$TERM_BAD\"|*,\"$TERM_GOOD\"|*,skip)\n \t\tshift\n@@ -276,7 +259,7 @@ bisect_state() {\n \t\tdone\n \t\tfor rev in $hash_list\n \t\tdo\n-\t\t\tbisect_write \"$state\" \"$rev\"\n+\t\t\tgit bisect--helper --bisect-write \"$state\" \"$rev\" \"$TERM_GOOD\" \"$TERM_BAD\" || exit\n \t\tdone\n \t\tgit bisect--helper --check-expected-revs $hash_list ;;\n \t*,\"$TERM_BAD\")\n@@ -413,7 +396,7 @@ bisect_replay () {\n \t\t\tcmd=\"bisect_start $rev\"\n \t\t\teval \"$cmd\" ;;\n \t\t\"$TERM_GOOD\"|\"$TERM_BAD\"|skip)\n-\t\t\tbisect_write \"$command\" \"$rev\" ;;\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*)\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299912","messageId":"01020156b73fe6d0-ae35967b-556e-4c72-9ae7-363aa1921e90-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 18/27] bisect--helper: `bisect_state` & `bisect_head` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:01:57Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Reimplement the `bisect_state` shell function in C and also add a\nsubcommand `--bisect-state` to `git-bisect--helper` to call it from\ngit-bisect.sh .\n\nUsing `--bisect-state` subcommand 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\n`bisect_head` is called from `bisect_state` thus its not required to\nintroduce another subcommand.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++\n git-bisect.sh            | 57 +++-----------------------------\n 2 files changed, 89 insertions(+), 52 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex a139592..861c07d 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -31,6 +31,8 @@ static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --bisect-next\"),\n \tN_(\"git bisect--helper --bisect-auto-next\"),\n \tN_(\"git bisect--helper --bisect-autostart\"),\n+\tN_(\"git bisect--helper --bisect-state (bad|new) [<rev>]\"),\n+\tN_(\"git bisect--helper --bisect-state (good|old) [<rev>...]\"),\n \tNULL\n };\n \n@@ -790,6 +792,79 @@ static int bisect_autostart(struct bisect_terms *terms)\n \treturn 0;\n }\n \n+static char *bisect_head(void)\n+{\n+\tif (is_empty_or_missing_file(git_path_bisect_head()))\n+\t\treturn \"HEAD\";\n+\telse\n+\t\treturn \"BISECT_HEAD\";\n+}\n+\n+static int bisect_state(struct bisect_terms *terms, const char **argv,\n+\t\t\tint argc)\n+{\n+\tconst char *state = argv[0];\n+\n+\tget_terms(terms);\n+\tif (check_and_set_terms(terms, state))\n+\t\treturn -1;\n+\n+\tif (!argc)\n+\t\tdie(_(\"Please call `--bisect-state` with at least one argument\"));\n+\n+\tif (argc == 1 && one_of(state, terms->term_good.buf,\n+\t    terms->term_bad.buf, \"skip\", NULL)) {\n+\t\tconst char *bisected_head = xstrdup(bisect_head());\n+\t\tconst char *hex[1];\n+\t\tunsigned char sha1[20];\n+\n+\t\tif (get_sha1(bisected_head, sha1))\n+\t\t\tdie(_(\"Bad rev input: %s\"), bisected_head);\n+\t\tif (bisect_write(state, sha1_to_hex(sha1), terms, 0))\n+\t\t\treturn -1;\n+\n+\t\t*hex = xstrdup(sha1_to_hex(sha1));\n+\t\tif (check_expected_revs(hex, 1))\n+\t\t\treturn -1;\n+\t\treturn bisect_auto_next(terms, NULL);\n+\t}\n+\n+\tif ((argc == 2 && !strcmp(state, terms->term_bad.buf)) ||\n+\t\t\tone_of(state, terms->term_good.buf, \"skip\", NULL)) {\n+\t\tint i;\n+\t\tstruct string_list hex = STRING_LIST_INIT_DUP;\n+\n+\t\tfor (i = 1; i < argc; i++) {\n+\t\t\tunsigned char sha1[20];\n+\n+\t\t\tif (get_sha1(argv[i], sha1)) {\n+\t\t\t\tstring_list_clear(&hex, 0);\n+\t\t\t\tdie(_(\"Bad rev input: %s\"), argv[i]);\n+\t\t\t}\n+\t\t\tstring_list_append(&hex, sha1_to_hex(sha1));\n+\t\t}\n+\t\tfor (i = 0; i < hex.nr; i++) {\n+\t\t\tconst char **hex_string = (const char **) &hex.items[i].string;\n+\t\t\tif(bisect_write(state, *hex_string, terms, 0)) {\n+\t\t\t\tstring_list_clear(&hex, 0);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tif (check_expected_revs(hex_string, 1)) {\n+\t\t\t\tstring_list_clear(&hex, 0);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t}\n+\t\tstring_list_clear(&hex, 0);\n+\t\treturn bisect_auto_next(terms, NULL);\n+\t}\n+\n+\tif (!strcmp(state, terms->term_bad.buf))\n+\t\tdie(_(\"'git bisect %s' can take only one argument.\"),\n+\t\t      terms->term_bad.buf);\n+\n+\treturn -1;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -804,6 +879,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tBISECT_NEXT,\n \t\tBISECT_AUTO_NEXT,\n \t\tBISECT_AUTOSTART,\n+\t\tBISECT_STATE\n \t} cmdmode = 0;\n \tint no_checkout = 0, res = 0;\n \tstruct option options[] = {\n@@ -829,6 +905,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"verify the next bisection state then find the next bisection state\"), BISECT_AUTO_NEXT),\n \t\tOPT_CMDMODE(0, \"bisect-autostart\", &cmdmode,\n \t\t\t N_(\"start the bisection if BISECT_START empty or missing\"), BISECT_AUTOSTART),\n+\t\tOPT_CMDMODE(0, \"bisect-state\", &cmdmode,\n+\t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\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@@ -909,6 +987,12 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tstrbuf_addstr(&terms.term_bad, \"bad\");\n \t\tres = bisect_autostart(&terms);\n \t\tbreak;\n+\tcase BISECT_STATE:\n+\t\tif (argc == 0)\n+\t\t\tdie(_(\"--bisect-state requires at least 1 argument\"));\n+\t\tget_terms(&terms);\n+\t\tres = bisect_state(&terms, argv, argc);\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 cd56551..a9eebbb 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -39,16 +39,6 @@ _x40=\"$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40\"\n TERM_BAD=bad\n TERM_GOOD=good\n \n-bisect_head()\n-{\n-\tif test -f \"$GIT_DIR/BISECT_HEAD\"\n-\tthen\n-\t\techo BISECT_HEAD\n-\telse\n-\t\techo HEAD\n-\tfi\n-}\n-\n bisect_skip() {\n \tall=''\n \tfor arg in \"$@\"\n@@ -61,44 +51,7 @@ bisect_skip() {\n \t\tesac\n \t\tall=\"$all $revs\"\n \tdone\n-\teval bisect_state 'skip' $all\n-}\n-\n-bisect_state() {\n-\tgit bisect--helper --bisect-autostart\n-\tstate=$1\n-\tget_terms\n-\tgit bisect--helper --check-and-set-terms $state $TERM_GOOD $TERM_BAD || exit\n-\tget_terms\n-\tcase \"$#,$state\" in\n-\t0,*)\n-\t\tdie \"Please call 'bisect_state' with at least one argument.\" ;;\n-\t1,\"$TERM_BAD\"|1,\"$TERM_GOOD\"|1,skip)\n-\t\tbisected_head=$(bisect_head)\n-\t\trev=$(git rev-parse --verify \"$bisected_head\") ||\n-\t\t\tdie \"$(eval_gettext \"Bad rev input: \\$bisected_head\")\"\n-\t\tgit bisect--helper --bisect-write \"$state\" \"$rev\" \"$TERM_GOOD\" \"$TERM_BAD\" || exit\n-\t\tgit bisect--helper --check-expected-revs \"$rev\" ;;\n-\t2,\"$TERM_BAD\"|*,\"$TERM_GOOD\"|*,skip)\n-\t\tshift\n-\t\thash_list=''\n-\t\tfor rev in \"$@\"\n-\t\tdo\n-\t\t\tsha=$(git rev-parse --verify \"$rev^{commit}\") ||\n-\t\t\t\tdie \"$(eval_gettext \"Bad rev input: \\$rev\")\"\n-\t\t\thash_list=\"$hash_list $sha\"\n-\t\tdone\n-\t\tfor rev in $hash_list\n-\t\tdo\n-\t\t\tgit bisect--helper --bisect-write \"$state\" \"$rev\" \"$TERM_GOOD\" \"$TERM_BAD\" || exit\n-\t\tdone\n-\t\tgit bisect--helper --check-expected-revs $hash_list ;;\n-\t*,\"$TERM_BAD\")\n-\t\tdie \"$(eval_gettext \"'git bisect \\$TERM_BAD' can take only one argument.\")\" ;;\n-\t*)\n-\t\tusage ;;\n-\tesac\n-\tgit bisect--helper --bisect-auto-next || exit\n+\teval git bisect--helper --bisect-state 'skip' $all\n }\n \n bisect_visualize() {\n@@ -184,8 +137,8 @@ exit code \\$res from '\\$command' is < 0 or >= 128\" >&2\n \t\t\tstate=\"$TERM_GOOD\"\n \t\tfi\n \n-\t\t# We have to use a subshell because \"bisect_state\" can exit.\n-\t\t( bisect_state $state >\"$GIT_DIR/BISECT_RUN\" )\n+\t\t# We have to use a subshell because \"--bisect-state\" can exit.\n+\t\t( git bisect--helper --bisect-state $state >\"$GIT_DIR/BISECT_RUN\" )\n \t\tres=$?\n \n \t\tcat \"$GIT_DIR/BISECT_RUN\"\n@@ -200,7 +153,7 @@ exit code \\$res from '\\$command' is < 0 or >= 128\" >&2\n \t\tif [ $res -ne 0 ]\n \t\tthen\n \t\t\teval_gettextln \"bisect run failed:\n-'bisect_state \\$state' exited with error code \\$res\" >&2\n+'git bisect--helper --bisect-state \\$state' exited with error code \\$res\" >&2\n \t\t\texit $res\n \t\tfi\n \n@@ -241,7 +194,7 @@ case \"$#\" in\n \tstart)\n \t\tgit bisect--helper --bisect-start \"$@\" ;;\n \tbad|good|new|old|\"$TERM_BAD\"|\"$TERM_GOOD\")\n-\t\tbisect_state \"$cmd\" \"$@\" ;;\n+\t\tgit bisect--helper --bisect-state \"$cmd\" \"$@\" ;;\n \tskip)\n \t\tbisect_skip \"$@\" ;;\n \tnext)\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299913","messageId":"01020156b73fe6d5-6a363195-eb91-48a0-9a3c-3159fba6d327-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 21/27] bisect--helper: `bisect_log` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:01:58Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Reimplement the `bisect_log` shell function in C and also add\n`--bisect-log` subcommand to `git bisect--helper` to call it from\ngit-bisect.sh .\n\nUsing `--bisect-log` subcommand 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 method.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 25 ++++++++++++++++++++++++-\n git-bisect.sh            |  7 +------\n 2 files changed, 25 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 1b6e5d8..b57b0c8 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -864,6 +864,21 @@ static int bisect_state(struct bisect_terms *terms, const char **argv,\n \treturn -1;\n }\n \n+static int bisect_log(void)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\n+\tif (strbuf_read_file(&buf, git_path_bisect_log(), 256) < 0) {\n+\t\tstrbuf_release(&buf);\n+\t\treturn error(_(\"We are not bisecting.\\n\"));\n+\t}\n+\n+\tprintf(\"%s\", buf.buf);\n+\tstrbuf_release(&buf);\n+\n+\treturn 0;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -876,7 +891,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tBISECT_NEXT,\n \t\tBISECT_AUTO_NEXT,\n \t\tBISECT_AUTOSTART,\n-\t\tBISECT_STATE\n+\t\tBISECT_STATE,\n+\t\tBISECT_LOG\n \t} cmdmode = 0;\n \tint no_checkout = 0, res = 0;\n \tstruct option options[] = {\n@@ -900,6 +916,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"start the bisection if BISECT_START empty or missing\"), BISECT_AUTOSTART),\n \t\tOPT_CMDMODE(0, \"bisect-state\", &cmdmode,\n \t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\n+\t\tOPT_CMDMODE(0, \"bisect-log\", &cmdmode,\n+\t\t\t N_(\"output the contents of BISECT_LOG\"), BISECT_LOG),\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@@ -978,6 +996,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tget_terms(&terms);\n \t\tres = bisect_state(&terms, argv, argc);\n \t\tbreak;\n+\tcase BISECT_LOG:\n+\t\tif (argc > 1)\n+\t\t\tdie(_(\"--bisect-log requires 0 arguments\"));\n+\t\tres = bisect_log();\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 a9eebbb..a47e3b5 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -166,11 +166,6 @@ exit code \\$res from '\\$command' is < 0 or >= 128\" >&2\n \tdone\n }\n \n-bisect_log () {\n-\ttest -s \"$GIT_DIR/BISECT_LOG\" || die \"$(gettext \"We are not bisecting.\")\"\n-\tcat \"$GIT_DIR/BISECT_LOG\"\n-}\n-\n get_terms () {\n \tif test -s \"$GIT_DIR/BISECT_TERMS\"\n \tthen\n@@ -208,7 +203,7 @@ case \"$#\" in\n \treplay)\n \t\tbisect_replay \"$@\" ;;\n \tlog)\n-\t\tbisect_log ;;\n+\t\tgit bisect--helper --bisect-log ;;\n \trun)\n \t\tbisect_run \"$@\" ;;\n \tterms)\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299914","messageId":"01020156b73fe6de-17b295fa-cf29-4b4d-a85d-b9b0176213e7-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 24/27] bisect--helper: retire `--check-and-set-terms` subcommand","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:01:59Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"The `--check-and-set-terms` subcommand is no longer used in the shell\nscript and the function `check_and_set_terms()` is called from the C\nimplementation.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 11 -----------\n 1 file changed, 11 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 4ab6488..8982f29 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -21,7 +21,6 @@ static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NAMES\")\n \n static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --bisect-reset [<commit>]\"),\n-\tN_(\"git bisect--helper --bisect-check-and-set-terms <command> <TERM_GOOD> <TERM_BAD>\"),\n \tN_(\"git bisect--helper --bisect-next-check [<term>] <TERM_GOOD> <TERM_BAD\"),\n \tN_(\"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]\"),\n \tN_(\"git bisect--helper --bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]\"\n@@ -970,7 +969,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n \t\tBISECT_RESET = 1,\n-\t\tCHECK_AND_SET_TERMS,\n \t\tBISECT_NEXT_CHECK,\n \t\tBISECT_TERMS,\n \t\tBISECT_START,\n@@ -985,8 +983,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tstruct option options[] = {\n \t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n \t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\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_CMDMODE(0, \"bisect-terms\", &cmdmode,\n@@ -1025,13 +1021,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"--bisect-reset requires either zero or one arguments\"));\n \t\tres = bisect_reset(argc ? argv[0] : NULL);\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(&terms.term_good, argv[1]);\n-\t\tstrbuf_addstr(&terms.term_bad, argv[2]);\n-\t\tres = check_and_set_terms(&terms, argv[0]);\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\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299915","messageId":"01020156b73fe6d7-8b80c663-7c77-469e-811f-40200ec6dbb1-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 17/27] bisect--helper: `bisect_autostart` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:02:03Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Reimplement the `bisect_autostart` shell function in C and add the\nC implementation from `bisect_next()` which was previously left\nuncovered. Also add a subcommand `--bisect-autostart` to\n`git bisect--helper` be called from `bisect_state()` from\ngit-bisect.sh .\n\nUsing `--bisect-autostart` subcommand is a temporary measure to port\nshell function to C so as to use the existing test suite. As more\nfunctions are ported, this subcommand will be retired and will be called\nby `bisect_state()`.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 40 ++++++++++++++++++++++++++++++++++++++++\n git-bisect.sh            | 23 +----------------------\n 2 files changed, 41 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 8cbcc3b..a139592 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -30,6 +30,7 @@ static const char * const git_bisect_helper_usage[] = {\n \t\t\t\t\t      \"[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]\"),\n \tN_(\"git bisect--helper --bisect-next\"),\n \tN_(\"git bisect--helper --bisect-auto-next\"),\n+\tN_(\"git bisect--helper --bisect-autostart\"),\n \tNULL\n };\n \n@@ -38,6 +39,8 @@ struct bisect_terms {\n \tstruct strbuf term_bad;\n };\n \n+static int bisect_autostart(struct bisect_terms *terms);\n+\n static void bisect_terms_init(struct bisect_terms *terms)\n {\n \tstrbuf_init(&terms->term_good, 0);\n@@ -410,6 +413,7 @@ static int bisect_next(struct bisect_terms *terms, const char *prefix)\n {\n \tint res, no_checkout;\n \n+\tbisect_autostart(terms);\n \t/* In case of mistaken revs or checkout error, or signals received,\n \t * \"bisect_auto_next\" below may exit or misbehave.\n \t * We have to trap this to be able to clean up using\n@@ -760,6 +764,32 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,\n \treturn bisect_auto_next(terms, NULL);\n }\n \n+static int bisect_autostart(struct bisect_terms *terms)\n+{\n+\tif (is_empty_or_missing_file(git_path_bisect_start())) {\n+\t\tconst char *yesno;\n+\t\tconst char *argv[] = {NULL};\n+\t\tfprintf(stderr, _(\"You need to start by \\\"git bisect \"\n+\t\t\t\t  \"start\\\"\\n\"));\n+\n+\t\tif (!isatty(0))\n+\t\t\treturn 1;\n+\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(_(\"Do you want me to do it for you \"\n+\t\t\t\t     \"[Y/n]? \"), PROMPT_ECHO);\n+\t\tif (starts_with(yesno, \"n\") || starts_with(yesno, \"N\"))\n+\t\t\texit(0);\n+\n+\t\treturn bisect_start(terms, 0, argv, 0);\n+\t}\n+\treturn 0;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -773,6 +803,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tBISECT_START,\n \t\tBISECT_NEXT,\n \t\tBISECT_AUTO_NEXT,\n+\t\tBISECT_AUTOSTART,\n \t} cmdmode = 0;\n \tint no_checkout = 0, res = 0;\n \tstruct option options[] = {\n@@ -796,6 +827,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"find the next bisection commit\"), BISECT_NEXT),\n \t\tOPT_CMDMODE(0, \"bisect-auto-next\", &cmdmode,\n \t\t\t N_(\"verify the next bisection state then find the next bisection state\"), BISECT_AUTO_NEXT),\n+\t\tOPT_CMDMODE(0, \"bisect-autostart\", &cmdmode,\n+\t\t\t N_(\"start the bisection if BISECT_START empty or missing\"), BISECT_AUTOSTART),\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@@ -869,6 +902,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tget_terms(&terms);\n \t\tres = bisect_auto_next(&terms, prefix);\n \t\tbreak;\n+\tcase BISECT_AUTOSTART:\n+\t\tif (argc)\n+\t\t\tdie(_(\"--bisect-autostart requires 0 arguments\"));\n+\t\tstrbuf_addstr(&terms.term_good, \"good\");\n+\t\tstrbuf_addstr(&terms.term_bad, \"bad\");\n+\t\tres = bisect_autostart(&terms);\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 d574c44..cd56551 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -49,27 +49,6 @@ bisect_head()\n \tfi\n }\n \n-bisect_autostart() {\n-\ttest -s \"$GIT_DIR/BISECT_START\" || {\n-\t\tgettextln \"You need to start by \\\"git bisect start\\\"\" >&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 \"Do you want me to do it for you [Y/n]? \" >&2\n-\t\t\tread yesno\n-\t\t\tcase \"$yesno\" in\n-\t\t\t[Nn]*)\n-\t\t\t\texit ;;\n-\t\t\tesac\n-\t\t\tgit bisect--helper --bisect-start\n-\t\telse\n-\t\t\texit 1\n-\t\tfi\n-\t}\n-}\n-\n bisect_skip() {\n \tall=''\n \tfor arg in \"$@\"\n@@ -86,7 +65,7 @@ bisect_skip() {\n }\n \n bisect_state() {\n-\tbisect_autostart\n+\tgit bisect--helper --bisect-autostart\n \tstate=$1\n \tget_terms\n \tgit bisect--helper --check-and-set-terms $state $TERM_GOOD $TERM_BAD || exit\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299916","messageId":"01020156b73fe6b3-3ccd9de5-604d-4e7d-919d-a3adae869ebf-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 12/27] bisect--helper: `get_terms` & `bisect_terms` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:02:07Z","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 but its implementation will\nbe called by some other methods.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++--\n git-bisect.sh            | 35 ++--------------------------\n 2 files changed, 59 insertions(+), 35 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex aca3908..44adf6b 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -23,6 +23,7 @@ static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --bisect-write <state> <revision> <TERM_GOOD> <TERM_BAD> [<nolog>]\"),\n \tN_(\"git bisect--helper --bisect-check-and-set-terms <command> <TERM_GOOD> <TERM_BAD>\"),\n \tN_(\"git bisect--helper --bisect-next-check [<term>] <TERM_GOOD> <TERM_BAD\"),\n+\tN_(\"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]\"),\n \tNULL\n };\n \n@@ -344,6 +345,52 @@ static int bisect_next_check(const struct bisect_terms *terms,\n \treturn 0;\n }\n \n+static int get_terms(struct bisect_terms *terms)\n+{\n+\tFILE *fp;\n+\tint res;\n+\tfp = fopen(git_path_bisect_terms(), \"r\");\n+\tif (!fp)\n+\t\treturn -1;\n+\n+\tbisect_terms_reset(terms);\n+\tres = strbuf_getline(&terms->term_bad, fp) == EOF ||\n+\t      strbuf_getline(&terms->term_good, fp) == EOF;\n+\n+\tfclose(fp);\n+\treturn res ? -1 : 0;\n+}\n+\n+static int bisect_terms(struct bisect_terms *terms, const char **argv, int argc)\n+{\n+\tint i;\n+\n+\tif (get_terms(terms)) {\n+\t\tfprintf(stderr, _(\"no terms defined\\n\"));\n+\t\treturn -1;\n+\t}\n+\tif (argc == 0) {\n+\t\tprintf(_(\"Your current terms are %s for the old state\\nand \"\n+\t\t       \"%s for the new state.\\n\"), terms->term_good.buf,\n+\t\t       terms->term_bad.buf);\n+\t\treturn 0;\n+\t}\n+\n+\tfor (i = 0; i < argc; i++) {\n+\t\tif (!strcmp(argv[i], \"--term-good\"))\n+\t\t\tprintf(\"%s\\n\", terms->term_good.buf);\n+\t\telse if (!strcmp(argv[i], \"--term-bad\"))\n+\t\t\tprintf(\"%s\\n\", terms->term_bad.buf);\n+\t\telse\n+\t\t\tprintf(_(\"invalid argument %s for 'git bisect \"\n+\t\t\t\t  \"terms'.\\nSupported options are: \"\n+\t\t\t\t  \"--term-good|--term-old and \"\n+\t\t\t\t  \"--term-bad|--term-new.\"), argv[i]);\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@@ -354,7 +401,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@@ -374,6 +422,8 @@ 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_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@@ -382,7 +432,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tbisect_terms_init(&terms);\n \n \targc = parse_options(argc, argv, prefix, options,\n-\t\t\t     git_bisect_helper_usage, 0);\n+\t\t\t     git_bisect_helper_usage, PARSE_OPT_KEEP_UNKNOWN);\n \n \tif (!cmdmode)\n \t\tusage_with_options(git_bisect_helper_usage, options);\n@@ -431,6 +481,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tstrbuf_addstr(&terms.term_bad, argv[1]);\n \t\tres = bisect_next_check(&terms, argc == 3 ? argv[2] : NULL);\n \t\tbreak;\n+\tcase BISECT_TERMS:\n+\t\tif (argc > 1)\n+\t\t\tdie(_(\"--bisect-terms requires 0 or 1 argument\"));\n+\t\tres = bisect_terms(&terms, argv, argc);\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 fe6c9d0..d6c8b5a 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  || exit;;\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 \"$@\" || exit;;\n \t*)\n \t\tusage ;;\n \tesac\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299917","messageId":"01020156b73fe66f-bfad6316-39d4-4577-8f75-d1b4b2031263-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 04/27] bisect--helper: `bisect_clean_state` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:02:09Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Reimplement `bisect_clean_state` shell function in C and add a\n`bisect-clean-state` subcommand to `git bisect--helper` to call it from\ngit-bisect.sh .\n\nUsing `--bisect-clean-state` subcommand is a 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 but its implementation  will\nbe called by bisect_reset() and bisect_start().\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n bisect.c                 | 43 +++++++++++++++++++++++++++++++++++++++++++\n bisect.h                 |  2 ++\n builtin/bisect--helper.c | 14 +++++++++++++-\n git-bisect.sh            | 26 +++-----------------------\n 4 files changed, 61 insertions(+), 24 deletions(-)\n\ndiff --git a/bisect.c b/bisect.c\nindex 6f512c2..45d598d 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -430,6 +430,12 @@ static int read_bisect_refs(void)\n \n static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NAMES\")\n static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXPECTED_REV\")\n+static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, \"BISECT_ANCESTORS_OK\")\n+static GIT_PATH_FUNC(git_path_bisect_run, \"BISECT_RUN\")\n+static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n+static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n+static GIT_PATH_FUNC(git_path_bisect_terms, \"BISECT_TERMS\")\n+static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n \n static void read_bisect_paths(struct argv_array *array)\n {\n@@ -1040,3 +1046,40 @@ int estimate_bisect_steps(int all)\n \n \treturn (e < 3 * x) ? n : n - 1;\n }\n+\n+static int mark_for_removal(const char *refname, const struct object_id *oid,\n+\t\t\t    int flag, void *cb_data)\n+{\n+\tstruct string_list *refs = cb_data;\n+\tchar *ref = xstrfmt(\"refs/bisect%s\", refname);\n+\tstring_list_append(refs, ref);\n+\treturn 0;\n+}\n+\n+int bisect_clean_state(void)\n+{\n+\tint result = 0;\n+\n+\t/* There may be some refs packed during bisection */\n+\tstruct string_list refs_for_removal = STRING_LIST_INIT_NODUP;\n+\tfor_each_ref_in(\"refs/bisect\", mark_for_removal, (void *) &refs_for_removal);\n+\tstring_list_append(&refs_for_removal, xstrdup(\"BISECT_HEAD\"));\n+\tresult = delete_refs(&refs_for_removal, REF_NODEREF);\n+\trefs_for_removal.strdup_strings = 1;\n+\tstring_list_clear(&refs_for_removal, 0);\n+\tunlink_or_warn(git_path_bisect_expected_rev());\n+\tunlink_or_warn(git_path_bisect_ancestors_ok());\n+\tunlink_or_warn(git_path_bisect_log());\n+\tunlink_or_warn(git_path_bisect_names());\n+\tunlink_or_warn(git_path_bisect_run());\n+\tunlink_or_warn(git_path_bisect_terms());\n+\t/* Cleanup head-name if it got left by an old version of git-bisect */\n+\tunlink_or_warn(git_path_head_name());\n+\t/*\n+\t * Cleanup BISECT_START last to support the --no-checkout option\n+\t * introduced in the commit 4796e823a.\n+\t */\n+\tunlink_or_warn(git_path_bisect_start());\n+\n+\treturn result;\n+}\ndiff --git a/bisect.h b/bisect.h\nindex acd12ef..0ae63d4 100644\n--- a/bisect.h\n+++ b/bisect.h\n@@ -28,4 +28,6 @@ extern int estimate_bisect_steps(int all);\n \n extern void read_bisect_terms(const char **bad, const char **good);\n \n+extern int bisect_clean_state(void);\n+\n #endif\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 30e1031..e50934c 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -5,10 +5,15 @@\n #include \"refs.h\"\n \n static GIT_PATH_FUNC(git_path_bisect_terms, \"BISECT_TERMS\")\n+static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXPECTED_REV\")\n+static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, \"BISECT_ANCESTORS_OK\")\n+static GIT_PATH_FUNC(git_path_bisect_log, \"BISECT_LOG\")\n+static GIT_PATH_FUNC(git_path_bisect_start, \"BISECT_START\")\n \n static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --next-all [--no-checkout]\"),\n \tN_(\"git bisect--helper --write-terms <bad_term> <good_term>\"),\n+\tN_(\"git bisect--helper --bisect-clean-state\"),\n \tNULL\n };\n \n@@ -83,7 +88,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n \t\tNEXT_ALL = 1,\n-\t\tWRITE_TERMS\n+\t\tWRITE_TERMS,\n+\t\tBISECT_CLEAN_STATE\n \t} cmdmode = 0;\n \tint no_checkout = 0;\n \tstruct option options[] = {\n@@ -91,6 +97,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"perform 'git bisect next'\"), NEXT_ALL),\n \t\tOPT_CMDMODE(0, \"write-terms\", &cmdmode,\n \t\t\t N_(\"write the terms to .git/BISECT_TERMS\"), WRITE_TERMS),\n+\t\tOPT_CMDMODE(0, \"bisect-clean-state\", &cmdmode,\n+\t\t\t N_(\"cleanup the bisection state\"), BISECT_CLEAN_STATE),\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@@ -109,6 +117,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tif (argc != 2)\n \t\t\tdie(_(\"--write-terms requires two arguments\"));\n \t\treturn write_terms(argv[0], argv[1]);\n+\tcase BISECT_CLEAN_STATE:\n+\t\tif (argc != 0)\n+\t\t\tdie(_(\"--bisect-clean-state requires no arguments\"));\n+\t\treturn bisect_clean_state();\n \tdefault:\n \t\tdie(\"BUG: unknown subcommand '%d'\", cmdmode);\n \t}\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 9ef6cb8..f1202df 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -186,7 +186,7 @@ bisect_start() {\n \t#\n \t# Get rid of any old bisect state.\n \t#\n-\tbisect_clean_state || exit\n+\tgit bisect--helper --bisect-clean-state || exit\n \n \t#\n \t# Change state.\n@@ -195,7 +195,7 @@ bisect_start() {\n \t# We have to trap this to be able to clean up using\n \t# \"bisect_clean_state\".\n \t#\n-\ttrap 'bisect_clean_state' 0\n+\ttrap 'git bisect--helper --bisect-clean-state' 0\n \ttrap 'exit 255' 1 2 3 15\n \n \t#\n@@ -430,27 +430,7 @@ bisect_reset() {\n \t\tdie \"$(eval_gettext \"Could not check out original HEAD '\\$branch'.\n Try 'git bisect reset <commit>'.\")\"\n \tfi\n-\tbisect_clean_state\n-}\n-\n-bisect_clean_state() {\n-\t# There may be some refs packed during bisection.\n-\tgit for-each-ref --format='%(refname) %(objectname)' refs/bisect/\\* |\n-\twhile read ref hash\n-\tdo\n-\t\tgit update-ref -d $ref $hash || exit\n-\tdone\n-\trm -f \"$GIT_DIR/BISECT_EXPECTED_REV\" &&\n-\trm -f \"$GIT_DIR/BISECT_ANCESTORS_OK\" &&\n-\trm -f \"$GIT_DIR/BISECT_LOG\" &&\n-\trm -f \"$GIT_DIR/BISECT_NAMES\" &&\n-\trm -f \"$GIT_DIR/BISECT_RUN\" &&\n-\trm -f \"$GIT_DIR/BISECT_TERMS\" &&\n-\t# Cleanup head-name if it got left by an old version of git-bisect\n-\trm -f \"$GIT_DIR/head-name\" &&\n-\tgit update-ref -d --no-deref BISECT_HEAD &&\n-\t# clean up BISECT_START last\n-\trm -f \"$GIT_DIR/BISECT_START\"\n+\tgit bisect--helper --bisect-clean-state || exit\n }\n \n bisect_replay () {\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299918","messageId":"01020156b73fe6d2-1815fb4e-50a2-4176-900e-9f22c5bfb9ec-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 20/27] bisect--helper: retire `--write-terms` subcommand","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:02:12Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"The `--write-terms` subcommand is no longer used in the shell script and\nthe function `write_terms()` is called from the C implementation of\n`set_terms()` and `bisect_start()`.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 11 +----------\n 1 file changed, 1 insertion(+), 10 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 6cc990b..1b6e5d8 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -20,7 +20,6 @@ static GIT_PATH_FUNC(git_path_head_name, \"head-name\")\n static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NAMES\")\n \n static const char * const git_bisect_helper_usage[] = {\n-\tN_(\"git bisect--helper --write-terms <bad_term> <good_term>\"),\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-check-and-set-terms <command> <TERM_GOOD> <TERM_BAD>\"),\n@@ -868,8 +867,7 @@ static int bisect_state(struct bisect_terms *terms, const char **argv,\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n-\t\tWRITE_TERMS = 1,\n-\t\tBISECT_RESET,\n+\t\tBISECT_RESET = 1,\n \t\tBISECT_WRITE,\n \t\tCHECK_AND_SET_TERMS,\n \t\tBISECT_NEXT_CHECK,\n@@ -882,8 +880,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t} cmdmode = 0;\n \tint no_checkout = 0, res = 0;\n \tstruct option options[] = {\n-\t\tOPT_CMDMODE(0, \"write-terms\", &cmdmode,\n-\t\t\t N_(\"write the terms to .git/BISECT_TERMS\"), WRITE_TERMS),\n \t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n \t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n \t\tOPT_CMDMODE(0, \"bisect-write\", &cmdmode,\n@@ -920,11 +916,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \n \tswitch (cmdmode) {\n \tint nolog;\n-\tcase WRITE_TERMS:\n-\t\tif (argc != 2)\n-\t\t\tdie(_(\"--write-terms requires two arguments\"));\n-\t\tres = write_terms(argv[0], argv[1]);\n-\t\tbreak;\n \tcase BISECT_RESET:\n \t\tif (argc > 1)\n \t\t\tdie(_(\"--bisect-reset requires either zero or one arguments\"));\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299919","messageId":"01020156b73fe6d8-0e494417-0873-4f57-894b-fece73e21124-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 23/27] bisect--helper: retire `--bisect-write` subcommand","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:02:13Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"The `--bisect-write` subcommand is no longer used in the shell script\nand the function `bisect_write()` is called from the C implementation.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 13 -------------\n 1 file changed, 13 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 9c1108d..4ab6488 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -21,7 +21,6 @@ static GIT_PATH_FUNC(git_path_bisect_names, \"BISECT_NAMES\")\n \n static const char * const git_bisect_helper_usage[] = {\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-check-and-set-terms <command> <TERM_GOOD> <TERM_BAD>\"),\n \tN_(\"git bisect--helper --bisect-next-check [<term>] <TERM_GOOD> <TERM_BAD\"),\n \tN_(\"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]\"),\n@@ -971,7 +970,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n \t\tBISECT_RESET = 1,\n-\t\tBISECT_WRITE,\n \t\tCHECK_AND_SET_TERMS,\n \t\tBISECT_NEXT_CHECK,\n \t\tBISECT_TERMS,\n@@ -987,8 +985,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tstruct option options[] = {\n \t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n \t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\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_CMDMODE(0, \"bisect-next-check\", &cmdmode,\n@@ -1024,20 +1020,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(git_bisect_helper_usage, options);\n \n \tswitch (cmdmode) {\n-\tint nolog;\n \tcase BISECT_RESET:\n \t\tif (argc > 1)\n \t\t\tdie(_(\"--bisect-reset requires either zero or one arguments\"));\n \t\tres = bisect_reset(argc ? argv[0] : NULL);\n \t\tbreak;\n-\tcase BISECT_WRITE:\n-\t\tif (argc != 4 && argc != 5)\n-\t\t\tdie(_(\"--bisect-write requires either 4 or 5 arguments\"));\n-\t\tnolog = (argc == 5) && !strcmp(argv[4], \"nolog\");\n-\t\tstrbuf_addstr(&terms.term_good, argv[2]);\n-\t\tstrbuf_addstr(&terms.term_bad, argv[3]);\n-\t\tres = bisect_write(argv[0], argv[1], &terms, 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\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299920","messageId":"01020156b73fe6ab-552239e5-6d82-4bef-80b6-06066bdd79c3-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 10/27] bisect--helper: `check_and_set_terms` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:02:37Z","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 but its\nimplementation will be called by 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_reset() to empty the contents of `term_good`\nand `term_bad` of `struct bisect_terms`.\n\nAlso introduce set_terms() to copy the `term_good` and `term_bad` into\n`struct bisect_terms` and write it out to the file BISECT_TERMS.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++-\n git-bisect.sh            | 36 ++++-----------------------------\n 2 files changed, 55 insertions(+), 33 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 5364960..450426c 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -20,6 +20,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-check-and-set-terms <command> <TERM_GOOD> <TERM_BAD>\"),\n \tNULL\n };\n \n@@ -40,6 +41,12 @@ static void bisect_terms_release(struct bisect_terms *terms)\n \tstrbuf_release(&terms->term_bad);\n }\n \n+static void bisect_terms_reset(struct bisect_terms *term)\n+{\n+\tstrbuf_reset(&term->term_good);\n+\tstrbuf_reset(&term->term_bad);\n+}\n+\n /*\n  * Check whether the string `term` belongs to the set of strings\n  * included in the variable arguments.\n@@ -213,6 +220,39 @@ static int bisect_write(const char *state, const char *rev,\n \treturn 0;\n }\n \n+static int set_terms(struct bisect_terms *terms, const char *bad,\n+\t\t     const char *good)\n+{\n+\tbisect_terms_reset(terms);\n+\tstrbuf_addstr(&terms->term_good, good);\n+\tstrbuf_addstr(&terms->term_bad, bad);\n+\treturn write_terms(terms->term_bad.buf, terms->term_good.buf);\n+}\n+\n+static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)\n+{\n+\tint has_term_file = !is_empty_or_missing_file(git_path_bisect_terms());\n+\n+\tif (one_of(cmd, \"skip\", \"start\", \"terms\", NULL))\n+\t\treturn 0;\n+\n+\tif (has_term_file &&\n+\t    strcmp(cmd, terms->term_bad.buf) &&\n+\t    strcmp(cmd, terms->term_good.buf))\n+\t\treturn error(_(\"Invalid command: you're currently in a \"\n+\t\t\t\t\"%s/%s bisect\"), terms->term_bad.buf,\n+\t\t\t\tterms->term_good.buf);\n+\n+\tif (!has_term_file) {\n+\t\tif (one_of(cmd, \"bad\", \"good\", NULL))\n+\t\t\treturn set_terms(terms, \"bad\", \"good\");\n+\t\tif (one_of(cmd, \"new\", \"old\", NULL))\n+\t\t\treturn set_terms(terms, \"new\", \"old\");\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@@ -221,7 +261,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@@ -237,6 +278,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@@ -280,6 +323,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tstrbuf_addstr(&terms.term_bad, argv[3]);\n \t\tres = bisect_write(argv[0], argv[1], &terms, 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(&terms.term_good, argv[1]);\n+\t\tstrbuf_addstr(&terms.term_bad, argv[2]);\n+\t\tres = check_and_set_terms(&terms, argv[0]);\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 dfdec33..bdf2227 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -238,7 +238,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 || exit\n+\tget_terms\n \tcase \"$#,$state\" in\n \t0,*)\n \t\tdie \"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\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299921","messageId":"01020156b73fe658-9c0fcb5f-3dc0-43e4-a1ac-2ef9de7b0ef6-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 03/27] bisect--helper: `write_terms` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:03:49Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Reimplement the `write_terms` shell function in C and add a `write-terms`\nsubcommand to `git bisect--helper` to call it from git-bisect.sh . Also\nremove the subcommand `--check-term-format` as it can now be called from\ninside the function write_terms() C implementation.\n\nAlso `|| exit` is added when calling write-terms subcommand from\ngit-bisect.sh so as to exit whenever there is an error.\n\nUsing `--write-terms` subcommand 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 its implementation will\nbe called by some other method.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 36 +++++++++++++++++++++++++++++-------\n git-bisect.sh            | 22 +++++++---------------\n 2 files changed, 36 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex a47f1f2..30e1031 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -4,9 +4,11 @@\n #include \"bisect.h\"\n #include \"refs.h\"\n \n+static GIT_PATH_FUNC(git_path_bisect_terms, \"BISECT_TERMS\")\n+\n static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --next-all [--no-checkout]\"),\n-\tN_(\"git bisect--helper --check-term-format <term> <orig_term>\"),\n+\tN_(\"git bisect--helper --write-terms <bad_term> <good_term>\"),\n \tNULL\n };\n \n@@ -57,18 +59,38 @@ static int check_term_format(const char *term, const char *orig_term)\n \treturn 0;\n }\n \n+static int write_terms(const char *bad, const char *good)\n+{\n+\tFILE *fp;\n+\tint res;\n+\n+\tif (!strcmp(bad, good))\n+\t\treturn error(_(\"please use two different terms\"));\n+\n+\tif (check_term_format(bad, \"bad\") || check_term_format(good, \"good\"))\n+\t\treturn -1;\n+\n+\tfp = fopen(git_path_bisect_terms(), \"w\");\n+\tif (!fp)\n+\t\treturn error_errno(_(\"could not open the file BISECT_TERMS\"));\n+\n+\tres = fprintf(fp, \"%s\\n%s\\n\", bad, good);\n+\tres |= fclose(fp);\n+\treturn (res < 0) ? -1 : 0;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n \t\tNEXT_ALL = 1,\n-\t\tCHECK_TERM_FMT\n+\t\tWRITE_TERMS\n \t} cmdmode = 0;\n \tint no_checkout = 0;\n \tstruct option options[] = {\n \t\tOPT_CMDMODE(0, \"next-all\", &cmdmode,\n \t\t\t N_(\"perform 'git bisect next'\"), NEXT_ALL),\n-\t\tOPT_CMDMODE(0, \"check-term-format\", &cmdmode,\n-\t\t\t N_(\"check format of the term\"), CHECK_TERM_FMT),\n+\t\tOPT_CMDMODE(0, \"write-terms\", &cmdmode,\n+\t\t\t N_(\"write the terms to .git/BISECT_TERMS\"), WRITE_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@@ -83,10 +105,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tswitch (cmdmode) {\n \tcase NEXT_ALL:\n \t\treturn bisect_next_all(prefix, no_checkout);\n-\tcase CHECK_TERM_FMT:\n+\tcase WRITE_TERMS:\n \t\tif (argc != 2)\n-\t\t\tdie(_(\"--check-term-format requires two arguments\"));\n-\t\treturn check_term_format(argv[0], argv[1]);\n+\t\t\tdie(_(\"--write-terms requires two arguments\"));\n+\t\treturn write_terms(argv[0], argv[1]);\n \tdefault:\n \t\tdie(\"BUG: unknown subcommand '%d'\", cmdmode);\n \t}\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex a727c59..9ef6cb8 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -209,7 +209,7 @@ bisect_start() {\n \teval \"$eval true\" &&\n \tif test $must_write_terms -eq 1\n \tthen\n-\t\twrite_terms \"$TERM_BAD\" \"$TERM_GOOD\"\n+\t\tgit bisect--helper --write-terms \"$TERM_BAD\" \"$TERM_GOOD\"\n \tfi &&\n \techo \"git bisect start$orig_args\" >>\"$GIT_DIR/BISECT_LOG\" || exit\n \t#\n@@ -557,18 +557,6 @@ get_terms () {\n \tfi\n }\n \n-write_terms () {\n-\tTERM_BAD=$1\n-\tTERM_GOOD=$2\n-\tif test \"$TERM_BAD\" = \"$TERM_GOOD\"\n-\tthen\n-\t\tdie \"$(gettext \"please use two different terms\")\"\n-\tfi\n-\tgit bisect--helper --check-term-format \"$TERM_BAD\" bad || exit\n-\tgit bisect--helper --check-term-format \"$TERM_GOOD\" good || exit\n-\tprintf '%s\\n%s\\n' \"$TERM_BAD\" \"$TERM_GOOD\" >\"$GIT_DIR/BISECT_TERMS\"\n-}\n-\n check_and_set_terms () {\n \tcmd=\"$1\"\n \tcase \"$cmd\" in\n@@ -582,13 +570,17 @@ check_and_set_terms () {\n \t\tbad|good)\n \t\t\tif ! test -s \"$GIT_DIR/BISECT_TERMS\"\n \t\t\tthen\n-\t\t\t\twrite_terms bad good\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\twrite_terms new old\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\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299922","messageId":"01020156b73fe6de-dee87e51-6e61-4869-898a-382d382f0366-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 26/27] bisect--helper: retire `--bisect-auto-next` subcommand","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:13:39Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"The `--bisect-auto-next` subcommand is no longer used in the shell\nscript and the function `bisect_auto_next` is called from the C\nimplementation.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 10 ----------\n 1 file changed, 10 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex a89e2f7..7577b69e 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -26,7 +26,6 @@ static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]\"\n \t\t\t\t\t      \"[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]\"),\n \tN_(\"git bisect--helper --bisect-next\"),\n-\tN_(\"git bisect--helper --bisect-auto-next\"),\n \tN_(\"git bisect--helper --bisect-state (bad|new) [<rev>]\"),\n \tN_(\"git bisect--helper --bisect-state (good|old) [<rev>...]\"),\n \tN_(\"git bisect--helper --bisect-replay <filename>\"),\n@@ -972,7 +971,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tBISECT_TERMS,\n \t\tBISECT_START,\n \t\tBISECT_NEXT,\n-\t\tBISECT_AUTO_NEXT,\n \t\tBISECT_STATE,\n \t\tBISECT_LOG,\n \t\tBISECT_REPLAY\n@@ -989,8 +987,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"start the bisect session\"), BISECT_START),\n \t\tOPT_CMDMODE(0, \"bisect-next\", &cmdmode,\n \t\t\t N_(\"find the next bisection commit\"), BISECT_NEXT),\n-\t\tOPT_CMDMODE(0, \"bisect-auto-next\", &cmdmode,\n-\t\t\t N_(\"verify the next bisection state then find the next bisection state\"), BISECT_AUTO_NEXT),\n \t\tOPT_CMDMODE(0, \"bisect-state\", &cmdmode,\n \t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\n \t\tOPT_CMDMODE(0, \"bisect-log\", &cmdmode,\n@@ -1040,12 +1036,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tget_terms(&terms);\n \t\tres = bisect_next(&terms, prefix);\n \t\tbreak;\n-\tcase BISECT_AUTO_NEXT:\n-\t\tif (argc)\n-\t\t\tdie(_(\"--bisect-auto-next requires 0 arguments\"));\n-\t\tget_terms(&terms);\n-\t\tres = bisect_auto_next(&terms, prefix);\n-\t\tbreak;\n \tcase BISECT_STATE:\n \t\tif (argc == 0)\n \t\t\tdie(_(\"--bisect-state requires at least 1 argument\"));\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299923","messageId":"01020156b73fe650-9ea6edbf-06df-45b3-ac65-848db7210cff-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 02/27] bisect: rewrite `check_term_format` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:22:59Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Reimplement the `check_term_format` shell function in C and add\na `--check-term-format` subcommand to `git bisect--helper` to call it\nfrom git-bisect.sh\n\nUsing `--check-term-format` subcommand is a temporary measure to port\nshell function to C so as to use the existing test suite. As more\nfunctions are ported, this subcommand will be retired and its\nimplementation will be called by some other method/subcommand. For\neg. In conversion of write_terms() of git-bisect.sh, the subcommand will\nbe removed and instead check_term_format() will be called in its C\nimplementation while a new subcommand will be introduced for write_terms().\n\nHelped-by: Johannes Schindelein <Johannes.Schindelein@gmx.de>\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++-\n git-bisect.sh            | 31 ++-----------------------\n 2 files changed, 61 insertions(+), 30 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 8111c91..a47f1f2 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -2,19 +2,73 @@\n #include \"cache.h\"\n #include \"parse-options.h\"\n #include \"bisect.h\"\n+#include \"refs.h\"\n \n static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --next-all [--no-checkout]\"),\n+\tN_(\"git bisect--helper --check-term-format <term> <orig_term>\"),\n \tNULL\n };\n \n+/*\n+ * Check whether the string `term` belongs to the set of strings\n+ * included in the variable arguments.\n+ */\n+LAST_ARG_MUST_BE_NULL\n+static int one_of(const char *term, ...)\n+{\n+\tint res = 0;\n+\tva_list matches;\n+\tconst char *match;\n+\n+\tva_start(matches, term);\n+\twhile (!res && (match = va_arg(matches, const char *)))\n+\t\tres = !strcmp(term, match);\n+\tva_end(matches);\n+\n+\treturn res;\n+}\n+\n+static int check_term_format(const char *term, const char *orig_term)\n+{\n+\tint res;\n+\tchar *new_term = xstrfmt(\"refs/bisect/%s\", term);\n+\n+\tres = check_refname_format(new_term, 0);\n+\tfree(new_term);\n+\n+\tif (res)\n+\t\treturn error(_(\"'%s' is not a valid term\"), term);\n+\n+\tif (one_of(term, \"help\", \"start\", \"skip\", \"next\", \"reset\",\n+\t\t\t\"visualize\", \"replay\", \"log\", \"run\", NULL))\n+\t\treturn error(_(\"can't use the builtin command '%s' as a term\"), term);\n+\n+\t/*\n+\t * In theory, nothing prevents swapping completely good and bad,\n+\t * but this situation could be confusing and hasn't been tested\n+\t * enough. Forbid it for now.\n+\t */\n+\n+\tif ((strcmp(orig_term, \"bad\") && one_of(term, \"bad\", \"new\", NULL)) ||\n+\t\t (strcmp(orig_term, \"good\") && one_of(term, \"good\", \"old\", NULL)))\n+\t\treturn error(_(\"can't change the meaning of the term '%s'\"), term);\n+\n+\treturn 0;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n-\tenum { NEXT_ALL = 1 } cmdmode = 0;\n+\tenum {\n+\t\tNEXT_ALL = 1,\n+\t\tCHECK_TERM_FMT\n+\t} cmdmode = 0;\n \tint no_checkout = 0;\n \tstruct option options[] = {\n \t\tOPT_CMDMODE(0, \"next-all\", &cmdmode,\n \t\t\t N_(\"perform 'git bisect next'\"), NEXT_ALL),\n+\t\tOPT_CMDMODE(0, \"check-term-format\", &cmdmode,\n+\t\t\t N_(\"check format of the term\"), CHECK_TERM_FMT),\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@@ -29,6 +83,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \tswitch (cmdmode) {\n \tcase NEXT_ALL:\n \t\treturn bisect_next_all(prefix, no_checkout);\n+\tcase CHECK_TERM_FMT:\n+\t\tif (argc != 2)\n+\t\t\tdie(_(\"--check-term-format requires two arguments\"));\n+\t\treturn check_term_format(argv[0], argv[1]);\n \tdefault:\n \t\tdie(\"BUG: unknown subcommand '%d'\", cmdmode);\n \t}\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex ae3cb01..a727c59 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -564,38 +564,11 @@ write_terms () {\n \tthen\n \t\tdie \"$(gettext \"please use two different terms\")\"\n \tfi\n-\tcheck_term_format \"$TERM_BAD\" bad\n-\tcheck_term_format \"$TERM_GOOD\" good\n+\tgit bisect--helper --check-term-format \"$TERM_BAD\" bad || exit\n+\tgit bisect--helper --check-term-format \"$TERM_GOOD\" good || exit\n \tprintf '%s\\n%s\\n' \"$TERM_BAD\" \"$TERM_GOOD\" >\"$GIT_DIR/BISECT_TERMS\"\n }\n \n-check_term_format () {\n-\tterm=$1\n-\tgit check-ref-format refs/bisect/\"$term\" ||\n-\tdie \"$(eval_gettext \"'\\$term' is not a valid term\")\"\n-\tcase \"$term\" in\n-\thelp|start|terms|skip|next|reset|visualize|replay|log|run)\n-\t\tdie \"$(eval_gettext \"can't use the builtin command '\\$term' as a term\")\"\n-\t\t;;\n-\tbad|new)\n-\t\tif test \"$2\" != bad\n-\t\tthen\n-\t\t\t# In theory, nothing prevents swapping\n-\t\t\t# completely good and bad, but this situation\n-\t\t\t# could be confusing and hasn't been tested\n-\t\t\t# enough. Forbid it for now.\n-\t\t\tdie \"$(eval_gettext \"can't change the meaning of term '\\$term'\")\"\n-\t\tfi\n-\t\t;;\n-\tgood|old)\n-\t\tif test \"$2\" != good\n-\t\tthen\n-\t\t\tdie \"$(eval_gettext \"can't change the meaning of term '\\$term'\")\"\n-\t\tfi\n-\t\t;;\n-\tesac\n-}\n-\n check_and_set_terms () {\n \tcmd=\"$1\"\n \tcase \"$cmd\" in\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299924","messageId":"01020156b73fe69f-6b734e3c-806c-431d-aa52-c96b3783f248-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 08/27] bisect--helper: `is_expected_rev` & `check_expected_revs` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:30:45Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Reimplement `is_expected_rev` & `check_expected_revs` shell function in\nC and add a `--check-expected-revs` subcommand to `git bisect--helper` to\ncall it from git-bisect.sh .\n\nUsing `--check-expected-revs` subcommand is a temporary measure to port\nshell functions to C so as to use the existing test suite. As more\nfunctions are ported, this subcommand would be retired but its\nimplementation will be called by some other method.\n\nHelped-by: Eric Sunshine <sunshine@sunshineco.com>\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 33 ++++++++++++++++++++++++++++++++-\n git-bisect.sh            | 20 ++------------------\n 2 files changed, 34 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 9aba094..711be75 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -123,13 +123,40 @@ static int bisect_reset(const char *commit)\n \treturn bisect_clean_state();\n }\n \n+static int is_expected_rev(const char *expected_hex)\n+{\n+\tstruct strbuf actual_hex = STRBUF_INIT;\n+\tint res = 0;\n+\tif (strbuf_read_file(&actual_hex, git_path_bisect_expected_rev(), 0) >= 0) {\n+\t\tstrbuf_trim(&actual_hex);\n+\t\tres = !strcmp(actual_hex.buf, expected_hex);\n+\t}\n+\tstrbuf_release(&actual_hex);\n+\treturn res;\n+}\n+\n+static int check_expected_revs(const char **revs, int rev_nr)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < rev_nr; i++) {\n+\t\tif (!is_expected_rev(revs[i])) {\n+\t\t\tunlink_or_warn(git_path_bisect_ancestors_ok());\n+\t\t\tunlink_or_warn(git_path_bisect_expected_rev());\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n \t\tNEXT_ALL = 1,\n \t\tWRITE_TERMS,\n \t\tBISECT_CLEAN_STATE,\n-\t\tBISECT_RESET\n+\t\tBISECT_RESET,\n+\t\tCHECK_EXPECTED_REVS\n \t} cmdmode = 0;\n \tint no_checkout = 0;\n \tstruct option options[] = {\n@@ -141,6 +168,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"cleanup the bisection state\"), BISECT_CLEAN_STATE),\n \t\tOPT_CMDMODE(0, \"bisect-reset\", &cmdmode,\n \t\t\t N_(\"reset the bisection state\"), BISECT_RESET),\n+\t\tOPT_CMDMODE(0, \"check-expected-revs\", &cmdmode,\n+\t\t\t N_(\"check for expected revs\"), CHECK_EXPECTED_REVS),\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@@ -167,6 +196,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tif (argc > 1)\n \t\t\tdie(_(\"--bisect-reset requires either zero or one arguments\"));\n \t\treturn bisect_reset(argc ? argv[0] : NULL);\n+\tcase CHECK_EXPECTED_REVS:\n+\t\treturn check_expected_revs(argv, argc);\n \tdefault:\n \t\tdie(\"BUG: unknown subcommand '%d'\", cmdmode);\n \t}\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex 442397b..c3e43248 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -237,22 +237,6 @@ bisect_write() {\n \ttest -n \"$nolog\" || echo \"git bisect $state $rev\" >>\"$GIT_DIR/BISECT_LOG\"\n }\n \n-is_expected_rev() {\n-\ttest -f \"$GIT_DIR/BISECT_EXPECTED_REV\" &&\n-\ttest \"$1\" = $(cat \"$GIT_DIR/BISECT_EXPECTED_REV\")\n-}\n-\n-check_expected_revs() {\n-\tfor _rev in \"$@\"; do\n-\t\tif ! is_expected_rev \"$_rev\"\n-\t\tthen\n-\t\t\trm -f \"$GIT_DIR/BISECT_ANCESTORS_OK\"\n-\t\t\trm -f \"$GIT_DIR/BISECT_EXPECTED_REV\"\n-\t\t\treturn\n-\t\tfi\n-\tdone\n-}\n-\n bisect_skip() {\n \tall=''\n \tfor arg in \"$@\"\n@@ -280,7 +264,7 @@ bisect_state() {\n \t\trev=$(git rev-parse --verify \"$bisected_head\") ||\n \t\t\tdie \"$(eval_gettext \"Bad rev input: \\$bisected_head\")\"\n \t\tbisect_write \"$state\" \"$rev\"\n-\t\tcheck_expected_revs \"$rev\" ;;\n+\t\tgit bisect--helper --check-expected-revs \"$rev\" ;;\n \t2,\"$TERM_BAD\"|*,\"$TERM_GOOD\"|*,skip)\n \t\tshift\n \t\thash_list=''\n@@ -294,7 +278,7 @@ bisect_state() {\n \t\tdo\n \t\t\tbisect_write \"$state\" \"$rev\"\n \t\tdone\n-\t\tcheck_expected_revs $hash_list ;;\n+\t\tgit bisect--helper --check-expected-revs $hash_list ;;\n \t*,\"$TERM_BAD\")\n \t\tdie \"$(eval_gettext \"'git bisect \\$TERM_BAD' can take only one argument.\")\" ;;\n \t*)\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299926","messageId":"01020156b73fe6d7-6cd42223-f46c-4e4c-a15f-516fc13a4521-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 22/27] bisect--helper: `bisect_replay` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T12:45:02Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Reimplement the `bisect_replay` shell function in C and also add\n`--bisect-replay` subcommand to `git bisect--helper` to call it from\ngit-bisect.sh\n\nUsing `--bisect-replay` subcommand 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 method.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++-\n git-bisect.sh            |  32 +--------------\n 2 files changed, 100 insertions(+), 32 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex b57b0c8..9c1108d 100644\n--- a/builtin/bisect--helper.c\n+++ b/builtin/bisect--helper.c\n@@ -32,6 +32,7 @@ static const char * const git_bisect_helper_usage[] = {\n \tN_(\"git bisect--helper --bisect-autostart\"),\n \tN_(\"git bisect--helper --bisect-state (bad|new) [<rev>]\"),\n \tN_(\"git bisect--helper --bisect-state (good|old) [<rev>...]\"),\n+\tN_(\"git bisect--helper --bisect-replay <filename>\"),\n \tNULL\n };\n \n@@ -879,6 +880,93 @@ static int bisect_log(void)\n \treturn 0;\n }\n \n+static int get_next_word(struct strbuf *line, struct strbuf *word)\n+{\n+\tint i;\n+\tfor (i = 0; line->buf[i] != ' ' && line->buf[i] != '\\0'; i++)\n+\t\tstrbuf_addch(word, line->buf[i]);\n+\n+\treturn 0;\n+}\n+\n+static int bisect_replay(struct bisect_terms *terms, const char *filename)\n+{\n+\tstruct strbuf line = STRBUF_INIT;\n+\tFILE *fp;\n+\n+\tif (is_empty_or_missing_file(filename))\n+\t\tdie(_(\"no such file with name '%s' exists\"), filename);\n+\n+\tif (bisect_reset(NULL))\n+\t\treturn -1;\n+\n+\tfp = fopen(filename, \"r\");\n+\n+\twhile (strbuf_getline(&line, fp) != EOF) {\n+\t\tstruct strbuf command = STRBUF_INIT;\n+\t\tif (starts_with(line.buf, \"git bisect \") ||\n+\t\t    starts_with(line.buf, \"git-bisect \"))\n+\t\t\tstrbuf_remove(&line, 0, 11);\n+\t\telse\n+\t\t\tcontinue;\n+\n+\t\tget_terms(terms);\n+\t\tget_next_word(&line, &command);\n+\t\tif (check_and_set_terms(terms, command.buf)) {\n+\t\t\tstrbuf_release(&line);\n+\t\t\tstrbuf_release(&command);\n+\t\t}\n+\n+\t\tif (line.buf[command.len] != '\\0')\n+\t\t\tstrbuf_remove(&line, 0, command.len + 1);\n+\t\telse\n+\t\t\tstrbuf_remove(&line, 0, command.len);\n+\n+\t\tif (!strcmp(command.buf, \"start\")) {\n+\t\t\tstruct argv_array argv = ARGV_ARRAY_INIT;\n+\t\t\tsq_dequote_to_argv_array(line.buf, &argv);\n+\t\t\tif (bisect_start(terms, 0, argv.argv, argv.argc)) {\n+\t\t\t\tstrbuf_release(&command);\n+\t\t\t\tstrbuf_release(&line);\n+\t\t\t\targv_array_clear(&argv);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\targv_array_clear(&argv);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (one_of(command.buf, terms->term_good.buf,\n+\t\t    terms->term_bad.buf, \"skip\", NULL)) {\n+\t\t\tif (bisect_write(command.buf, line.buf, terms, 0)) {\n+\t\t\t\tstrbuf_release(&command);\n+\t\t\t\tstrbuf_release(&line);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (!strcmp(command.buf, \"terms\")) {\n+\t\t\tstruct argv_array argv = ARGV_ARRAY_INIT;\n+\t\t\tsq_dequote_to_argv_array(line. buf, &argv);\n+\t\t\tif (bisect_terms(terms, argv.argv, argv.argc)) {\n+\t\t\t\tstrbuf_release(&command);\n+\t\t\t\tstrbuf_release(&line);\n+\t\t\t\targv_array_clear(&argv);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\targv_array_clear(&argv);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tstrbuf_release(&command);\n+\t\tstrbuf_release(&line);\n+\t\tdie(_(\"?? what are you talking about?\"));\n+\t}\n+\tstrbuf_release(&line);\n+\n+\treturn bisect_auto_next(terms, NULL);\n+}\n+\n int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n {\n \tenum {\n@@ -892,7 +980,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tBISECT_AUTO_NEXT,\n \t\tBISECT_AUTOSTART,\n \t\tBISECT_STATE,\n-\t\tBISECT_LOG\n+\t\tBISECT_LOG,\n+\t\tBISECT_REPLAY\n \t} cmdmode = 0;\n \tint no_checkout = 0, res = 0;\n \tstruct option options[] = {\n@@ -918,6 +1007,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"mark the state of ref (or refs)\"), BISECT_STATE),\n \t\tOPT_CMDMODE(0, \"bisect-log\", &cmdmode,\n \t\t\t N_(\"output the contents of BISECT_LOG\"), BISECT_LOG),\n+\t\tOPT_CMDMODE(0, \"bisect-replay\", &cmdmode,\n+\t\t\t N_(\"replay the bisection process from the given file\"), BISECT_REPLAY),\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@@ -1001,6 +1092,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"--bisect-log requires 0 arguments\"));\n \t\tres = bisect_log();\n \t\tbreak;\n+\tcase BISECT_REPLAY:\n+\t\tif (argc != 1)\n+\t\t\tdie(_(\"--bisect-replay requires 1 argument\"));\n+\t\tstrbuf_addstr(&terms.term_good, \"good\");\n+\t\tstrbuf_addstr(&terms.term_bad, \"bad\");\n+\t\tres = bisect_replay(&terms, argv[0]);\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 a47e3b5..bf66ee2 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -77,36 +77,6 @@ bisect_visualize() {\n \teval '\"$@\"' --bisect -- $(cat \"$GIT_DIR/BISECT_NAMES\")\n }\n \n-bisect_replay () {\n-\tfile=\"$1\"\n-\ttest \"$#\" -eq 1 || die \"$(gettext \"No logfile given\")\"\n-\ttest -r \"$file\" || die \"$(eval_gettext \"cannot read \\$file for replaying\")\"\n-\tgit bisect--helper --bisect-reset || exit\n-\twhile read git bisect command rev\n-\tdo\n-\t\ttest \"$git $bisect\" = \"git bisect\" || test \"$git\" = \"git-bisect\" || continue\n-\t\tif test \"$git\" = \"git-bisect\"\n-\t\tthen\n-\t\t\trev=\"$command\"\n-\t\t\tcommand=\"$bisect\"\n-\t\tfi\n-\t\tget_terms\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\teval \"git bisect--helper --bisect-start $rev\" ;;\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\tgit bisect--helper --bisect-terms $rev  || exit;;\n-\t\t*)\n-\t\t\tdie \"$(gettext \"?? what are you talking about?\")\" ;;\n-\t\tesac\n-\tdone <\"$file\"\n-\tgit bisect--helper --bisect-auto-next\n-}\n-\n bisect_run () {\n \tgit bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit\n \n@@ -201,7 +171,7 @@ case \"$#\" in\n \treset)\n \t\tgit bisect--helper --bisect-reset \"$@\" ;;\n \treplay)\n-\t\tbisect_replay \"$@\" ;;\n+\t\tgit bisect--helper --bisect-replay \"$@\" ;;\n \tlog)\n \t\tgit bisect--helper --bisect-log ;;\n \trun)\n\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299929","messageId":"01020156b73fe6ae-27df9d50-59b2-4ee2-8c5b-89e7e70a2dd0-000000@eu-west-1.amazonses.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"[PATCH v14 11/27] bisect--helper: `bisect_next_check` & bisect_voc shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T11:53:53Z","receivedAt":"2016-08-23T13:43:01Z","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\nAlso reimplement `bisect_voc` shell function in C and call it from\n`bisect_next_check` implementation in C.\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 but its implementation will\nbe called by some other methods.\n\nMentored-by: Lars Schneider <larsxschneider@gmail.com>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nSigned-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n---\n builtin/bisect--helper.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++-\n git-bisect.sh            |  60 ++-------------------------\n 2 files changed, 106 insertions(+), 57 deletions(-)\n\ndiff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\nindex 450426c..aca3908 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_terms, \"BISECT_TERMS\")\n static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXPECTED_REV\")\n@@ -21,6 +22,7 @@ static const char * const git_bisect_helper_usage[] = {\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-check-and-set-terms <command> <TERM_GOOD> <TERM_BAD>\"),\n+\tN_(\"git bisect--helper --bisect-next-check [<term>] <TERM_GOOD> <TERM_BAD\"),\n \tNULL\n };\n \n@@ -253,6 +255,95 @@ static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)\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 1;\n+}\n+\n+static char *bisect_voc(char *revision_type)\n+{\n+\tif (!strcmp(revision_type, \"bad\"))\n+\t\treturn \"bad|new\";\n+\tif (!strcmp(revision_type, \"good\"))\n+\t\treturn \"good|old\";\n+\n+\treturn NULL;\n+}\n+\n+static int bisect_next_check(const struct bisect_terms *terms,\n+\t\t\t     const char *current_term)\n+{\n+\tint missing_good = 1, missing_bad = 1;\n+\tchar *bad_ref = xstrfmt(\"refs/bisect/%s\", terms->term_bad.buf);\n+\tchar *good_glob = xstrfmt(\"%s-*\", terms->term_good.buf);\n+\tchar *bad_syn, *good_syn;\n+\n+\tif (ref_exists(bad_ref))\n+\t\tmissing_bad = 0;\n+\tfree(bad_ref);\n+\n+\tfor_each_glob_ref_in(mark_good, good_glob, \"refs/bisect/\",\n+\t\t\t     (void *) &missing_good);\n+\tfree(good_glob);\n+\n+\tif (!missing_good && !missing_bad)\n+\t\treturn 0;\n+\n+\tif (!current_term)\n+\t\treturn -1;\n+\n+\tif (missing_good && !missing_bad && current_term &&\n+\t    !strcmp(current_term, terms->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\tterms->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+\n+\t\treturn 0;\n+\t}\n+\tbad_syn = xstrdup(bisect_voc(\"bad\"));\n+\tgood_syn = xstrdup(bisect_voc(\"good\"));\n+\tif (!is_empty_or_missing_file(git_path_bisect_start())) {\n+\t\terror(_(\"You need to give me at least one %s and \"\n+\t\t\t\"%s revision. You can use \\\"git bisect %s\\\" \"\n+\t\t\t\"and \\\"git bisect %s\\\" for that. \\n\"),\n+\t\t\tbad_syn, good_syn, bad_syn, good_syn);\n+\t\tfree(bad_syn);\n+\t\tfree(good_syn);\n+\t\treturn -1;\n+\t}\n+\telse {\n+\t\terror(_(\"You need to start by \\\"git bisect start\\\". You \"\n+\t\t\t\"then need to give me at least one %s and %s \"\n+\t\t\t\"revision. You can use \\\"git bisect %s\\\" and \"\n+\t\t\t\"\\\"git bisect %s\\\" for that.\\n\"),\n+\t\t\tgood_syn, bad_syn, bad_syn, good_syn);\n+\t\tfree(bad_syn);\n+\t\tfree(good_syn);\n+\t\treturn -1;\n+\t}\n+\tfree(bad_syn);\n+\tfree(good_syn);\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 +353,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@@ -280,6 +372,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@@ -330,6 +424,13 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n \t\tstrbuf_addstr(&terms.term_bad, argv[2]);\n \t\tres = check_and_set_terms(&terms, argv[0]);\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(&terms.term_good, argv[0]);\n+\t\tstrbuf_addstr(&terms.term_bad, argv[1]);\n+\t\tres = bisect_next_check(&terms, argc == 3 ? argv[2] : 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 bdf2227..fe6c9d0 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\n--\nhttps://github.com/git/git/pull/287\n"},{"id":"299990","messageId":"CAFZEwPM6hDbiEVMbe_FakME4h_RNCopyzFcVLsF1PB=V=OheOA@mail.gmail.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH v14 01/27] bisect--helper: use OPT_CMDMODE instead of OPT_BOOL","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T21:24:12Z","receivedAt":"2016-08-23T21:36:06Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Hey everyone,\n\nSending a \"cover letter\" to this series.\n\nChanges with wrt v12[1] are:\n\n * Rebased on v2.10-rc0\n * Two function signatures had changed while the topic\n    develop so changed those.\n * Correct the \"mark for translation\" messages properly as\n    I had previously used N_() in some places but I had to\n    actually use _().\n * In the patch 04/27[2], bisect_clean_state() is put in bisect.c\n   rather than builtin/bisect--helper.c because I will need it\n   further when porting bisect_next() function.\n * The patches from 14th are completely new to the series.\n    They port even more functions and remove some then unused\n    subcommands.\n * 14th patch[3] is a tricky one as it changes a lot of things. I am\n    not sure whether to put this all in one patch or split it.\n\n[1]: http://public-inbox.org/git/010201567675adc1-17e27495-6b36-40d1-836d-814da029fcc4-000000@eu-west-1.amazonses.com/\n[2]: http://public-inbox.org/git/01020156b73fe66f-bfad6316-39d4-4577-8f75-d1b4b2031263-000000@eu-west-1.amazonses.com/\n[3]: http://public-inbox.org/git/01020156b73fe6ce-3b204354-849b-40fd-93ff-2ebcf77df91c-000000@eu-west-1.amazonses.com/\n\nRegards,\nPranit Bauva\n"},{"id":"299992","messageId":"xmqqmvk3ut4s.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"01020156b73fe5b4-5dc768ab-b73b-4a21-ab92-018e2a7aa6f7-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH v14 01/27] bisect--helper: use OPT_CMDMODE instead of OPT_BOOL","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-23T20:28:51Z","receivedAt":"2016-08-23T21:46:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n> `--next-all` is meant to be used as a subcommand to support multiple\n> \"operation mode\" though the current implementation does not contain any\n> other subcommand along side with `--next-all` but further commits will\n> include some more subcommands.\n>\n> Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n> Mentored-by: Lars Schneider <larsxschneider@gmail.com>\n> Mentored-by: Christian Couder <chriscool@tuxfamily.org>\n> Signed-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n> ---\n\nA series this size really needs a cover letter that describes what\nchanges were made relative to the previous round to help reviewers.\n\nI also noticed something curious.  All of your messages are dated\n\n    Date: Tue, 23 Aug 2016 11:53:53 +0000\n\nand I think that is the same as all the previous series, but how are\nyou sending your patches?  The reason why I ask is because this does\nnot allow readers to tell their mail reader to sort messages by the\nsender's timestamp in order to see the messages in order (as a\nmatter of fact, git-send-email knows that readers are helped by this\nfeature, and backdates the first message of 10 patch series by 10\nseconds, stamps the second message as later than the first by one\nsecond, etc. to help them).\n\n\n"},{"id":"299999","messageId":"CAFZEwPPUasJvZO=LHOzu85FwPAsg-OQo57wQckXJdiHTP4_34A@mail.gmail.com","threadId":"43909","inReplyTo":"xmqqmvk3ut4s.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v14 01/27] bisect--helper: use OPT_CMDMODE instead of OPT_BOOL","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-23T21:07:34Z","receivedAt":"2016-08-23T22:00:25Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Hey Junio,\n\nOn Wed, Aug 24, 2016 at 1:58 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Pranit Bauva <pranit.bauva@gmail.com> writes:\n>\n>> `--next-all` is meant to be used as a subcommand to support multiple\n>> \"operation mode\" though the current implementation does not contain any\n>> other subcommand along side with `--next-all` but further commits will\n>> include some more subcommands.\n>>\n>> Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n>> Mentored-by: Lars Schneider <larsxschneider@gmail.com>\n>> Mentored-by: Christian Couder <chriscool@tuxfamily.org>\n>> Signed-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n>> ---\n>\n> A series this size really needs a cover letter that describes what\n> changes were made relative to the previous round to help reviewers.\n\nI am actually using SubmitGit these days as I am back in my campus and\nIMAP/SMTP connections are blocked here. SubmitGit doesn't have the\noption to include a cover letter. Though I can describe the changes by\nincluding a separate email as a reply to 1st patch. I will send the\nchanges according to v12 since v13 wasn't commented on.\n\n> I also noticed something curious.  All of your messages are dated\n>\n>     Date: Tue, 23 Aug 2016 11:53:53 +0000\n>\n> and I think that is the same as all the previous series, but how are\n> you sending your patches?  The reason why I ask is because this does\n> not allow readers to tell their mail reader to sort messages by the\n> sender's timestamp in order to see the messages in order (as a\n> matter of fact, git-send-email knows that readers are helped by this\n> feature, and backdates the first message of 10 patch series by 10\n> seconds, stamps the second message as later than the first by one\n> second, etc. to help them).\n\nThis might be a bug in SubmitGit. I didn't notice this previously.\n\nRegards,\nPranit Bauva\n"},{"id":"300113","messageId":"xmqqd1kxq3yj.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"01020156b73fe66f-bfad6316-39d4-4577-8f75-d1b4b2031263-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH v14 04/27] bisect--helper: `bisect_clean_state` shell function in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-24T20:58:28Z","receivedAt":"2016-08-24T20:59:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n> Reimplement `bisect_clean_state` shell function in C and add a\n> `bisect-clean-state` subcommand to `git bisect--helper` to call it from\n> git-bisect.sh .\n>\n> Using `--bisect-clean-state` subcommand is a measure to port shell\n> function to C so as to use the existing test suite. As more functions\n> are ported, this subcommand will be retired but its implementation  will\n> be called by bisect_reset() and bisect_start().\n>\n> Mentored-by: Lars Schneider <larsxschneider@gmail.com>\n> Mentored-by: Christian Couder <chriscool@tuxfamily.org>\n> Signed-off-by: Pranit Bauva <pranit.bauva@gmail.com>\n> ---\n\nThis seems to be where this round diverges from the previous one.\nThis patch in this round has more stuff that used to be in\nbuiltin/bisect--helper.c in the previous one in bisect.c.  Because I\nam not sure if the distinction would make that much of a difference\n(after all, I do not think of a good reason why many bisect internals\nneed to be exposed to anything other than the eventual builtin/bisect.c\nthat retires git-bisect.sh), I am OK with the change to this patch\nbetween the previous round and this round.\n\n"},{"id":"300115","messageId":"xmqq4m69q3b2.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"01020156b73fe69a-13136cfb-4daa-4f5d-9b56-537adf2c6942-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH v14 07/27] bisect--helper: `bisect_reset` shell function in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-24T21:12:33Z","receivedAt":"2016-08-24T21:12:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n> +static int bisect_reset(const char *commit)\n> +{\n> +\tstruct strbuf branch = STRBUF_INIT;\n> +\n> +\tif (!commit) {\n> +\t\tif (strbuf_read_file(&branch, git_path_bisect_start(), 0) < 1) {\n\nHmm, tricky but correct to do the \"< 1\" comparison.  If the file\ndoes not exist, you'd get -1; if it fails to read it, you'd get -1;\nif it turns out to be empty, you'd get 0.\n\n> +\t\t\tprintf(\"We are not bisecting.\\n\");\n> +\t\t\treturn 0;\n> +\t\t}\n> +\t\tstrbuf_rtrim(&branch);\n> +\t} else {\n> +\t\tstruct object_id oid;\n> +\t\tif (get_oid(commit, &oid))\n> +\t\t\treturn error(_(\"'%s' is not a valid commit\"), commit);\n\nThe original is\n\n\trev-parse --quiet --verify \"$1^{commit}\"\n\nUnless the caller of this function already appended \"^{commit}\" to\nwhatever the user gave \"bisect--helper bisect-reset\", this\nconversion is not equivalent.  If you said\n\n    git bisect reset HEAD:\n\nget_oid() would tell you that the top-level tree object of the\ncurrent commit exists in the object store, but the original is\nmeant to catch \"That's not a commit, it's a tree!\" before attempting\nto run \"git checkout\" on it.\n\nI think get_sha1_committish() is what you want to use here.\n\n> +\t\tstrbuf_addstr(&branch, commit);\n> +\t}\n\nAlso this version fails to catch \"bisect reset a b c\" as an error, I\nsuspect.\n\n> @@ -627,7 +603,7 @@ case \"$#\" in\n>  \tvisualize|view)\n>  \t\tbisect_visualize \"$@\" ;;\n>  \treset)\n> -\t\tbisect_reset \"$@\" ;;\n> +\t\tgit bisect--helper --bisect-reset \"$@\" ;;\n>  \treplay)\n>  \t\tbisect_replay \"$@\" ;;\n>  \tlog)\n>\n> --\n> https://github.com/git/git/pull/287\n"},{"id":"300123","messageId":"xmqqlgzlolwa.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"01020156b73fe69f-6b734e3c-806c-431d-aa52-c96b3783f248-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH v14 08/27] bisect--helper: `is_expected_rev` & `check_expected_revs` shell function in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-24T22:13:57Z","receivedAt":"2016-08-24T22:15:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n> +static int is_expected_rev(const char *expected_hex)\n> +{\n> +\tstruct strbuf actual_hex = STRBUF_INIT;\n> +\tint res = 0;\n> +\tif (strbuf_read_file(&actual_hex, git_path_bisect_expected_rev(), 0) >= 0) {\n> +\t\tstrbuf_trim(&actual_hex);\n> +\t\tres = !strcmp(actual_hex.buf, expected_hex);\n\nIf it is known to have 40-hex:\n\n (1) accepting \">= 0\" seems way too lenient.  You only expect a\n     41-byte file (or 42 if somebody would write CRLF, but I do not\n     think anybody other than yourself is expected to write into\n     this file, and you do not write CRLF yourself);\n\n (2) strbuf_trim() is overly loose.  You only want to trim the\n     terimnating LF and it is an error to have other trailing\n     whitespaces.\n\nI think the latter is not a new problem and it is OK to leave it\nas-is; limiting (1) to >= 40 may still be a good change, though,\nbecause it makes the intention of the code clearer.\n\n"},{"id":"300125","messageId":"xmqqbn0hoko0.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"01020156b73fe6ae-27df9d50-59b2-4ee2-8c5b-89e7e70a2dd0-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH v14 11/27] bisect--helper: `bisect_next_check` & bisect_voc shell function in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-24T22:40:31Z","receivedAt":"2016-08-24T22:40:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\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 1;\n> +}\n> +\n> +static char *bisect_voc(char *revision_type)\n> +{\n> +\tif (!strcmp(revision_type, \"bad\"))\n> +\t\treturn \"bad|new\";\n> +\tif (!strcmp(revision_type, \"good\"))\n> +\t\treturn \"good|old\";\n> +\n> +\treturn NULL;\n> +}\n> +\n> +static int bisect_next_check(const struct bisect_terms *terms,\n> +\t\t\t     const char *current_term)\n> +{\n> +\tint missing_good = 1, missing_bad = 1;\n> +\tchar *bad_ref = xstrfmt(\"refs/bisect/%s\", terms->term_bad.buf);\n> +\tchar *good_glob = xstrfmt(\"%s-*\", terms->term_good.buf);\n> +\tchar *bad_syn, *good_syn;\n> +\n> +\tif (ref_exists(bad_ref))\n> +\t\tmissing_bad = 0;\n> +\tfree(bad_ref);\n> +\n> +\tfor_each_glob_ref_in(mark_good, good_glob, \"refs/bisect/\",\n> +\t\t\t     (void *) &missing_good);\n> +\tfree(good_glob);\n> +\n> +\tif (!missing_good && !missing_bad)\n> +\t\treturn 0;\n> +\n> +\tif (!current_term)\n> +\t\treturn -1;\n> +\n> +\tif (missing_good && !missing_bad && current_term &&\n> +\t    !strcmp(current_term, terms->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\tterms->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> +\n> +\t\treturn 0;\n> +\t}\n> +\tbad_syn = xstrdup(bisect_voc(\"bad\"));\n> +\tgood_syn = xstrdup(bisect_voc(\"good\"));\n> +\tif (!is_empty_or_missing_file(git_path_bisect_start())) {\n> +\t\terror(_(\"You need to give me at least one %s and \"\n> +\t\t\t\"%s revision. You can use \\\"git bisect %s\\\" \"\n> +\t\t\t\"and \\\"git bisect %s\\\" for that. \\n\"),\n> +\t\t\tbad_syn, good_syn, bad_syn, good_syn);\n> +\t\tfree(bad_syn);\n> +\t\tfree(good_syn);\n> +\t\treturn -1;\n> +\t}\n> +\telse {\n> +\t\terror(_(\"You need to start by \\\"git bisect start\\\". You \"\n> +\t\t\t\"then need to give me at least one %s and %s \"\n> +\t\t\t\"revision. You can use \\\"git bisect %s\\\" and \"\n> +\t\t\t\"\\\"git bisect %s\\\" for that.\\n\"),\n> +\t\t\tgood_syn, bad_syn, bad_syn, good_syn);\n> +\t\tfree(bad_syn);\n> +\t\tfree(good_syn);\n> +\t\treturn -1;\n> +\t}\n> +\tfree(bad_syn);\n> +\tfree(good_syn);\n> +\n> +\treturn 0;\n\nThis one looks OK, but I think the same \"Wouldn't it become cleaner\nto have a 'finish:' label at the end and jump there?\" comment\napplies to this implementation, too.\n\n"},{"id":"300126","messageId":"xmqqfuptol4h.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"01020156b73fe6a7-2e9df745-e3f4-4830-a1af-4acae7964c11-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH v14 09/27] bisect--helper: `bisect_write` shell function in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-24T22:30:38Z","receivedAt":"2016-08-24T22:45:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n> +struct bisect_terms {\n> +\tstruct strbuf term_good;\n> +\tstruct strbuf term_bad;\n> +};\n\nI think \"struct strbuf\" is overrated.  For things like this, where\nthese fields will never change once it is set (and setting it is\ndone atomically, not incrementally), there is no good reason to use\ndefine the fields as strbuf.\n\nOnly because you chose to use strbuf for these two fields, you have\nto make unnecessarily copies of argv[] in the command parser, and\nyou have to remember to discard these copies later.\n\nI think you can just say \"const char *\" in this case.  \n\n> +static int bisect_write(const char *state, const char *rev,\n> +\t\t\tconst struct bisect_terms *terms, int nolog)\n> +{\n> +\tstruct strbuf tag = STRBUF_INIT;\n> +\tstruct strbuf commit_name = STRBUF_INIT;\n> +\tstruct object_id oid;\n> +\tstruct commit *commit;\n> +\tstruct pretty_print_context pp = {0};\n> +\tFILE *fp;\n> +\n> +\tif (!strcmp(state, terms->term_bad.buf))\n> +\t\tstrbuf_addf(&tag, \"refs/bisect/%s\", state);\n> +\telse if (one_of(state, terms->term_good.buf, \"skip\", NULL))\n> +\t\tstrbuf_addf(&tag, \"refs/bisect/%s-%s\", state, rev);\n> +\telse\n> +\t\treturn error(_(\"Bad bisect_write argument: %s\"), state);\n\nOK.\n\n> +\tif (get_oid(rev, &oid)) {\n> +\t\tstrbuf_release(&tag);\n> +\t\treturn error(_(\"couldn't get the oid of the rev '%s'\"), rev);\n> +\t}\n> +\n> +\tif (update_ref(NULL, tag.buf, oid.hash, NULL, 0,\n> +\t\t       UPDATE_REFS_MSG_ON_ERR)) {\n> +\t\tstrbuf_release(&tag);\n> +\t\treturn -1;\n> +\t}\n> +\tstrbuf_release(&tag);\n> +\n> +\tfp = fopen(git_path_bisect_log(), \"a\");\n> +\tif (!fp)\n> +\t\treturn error_errno(_(\"couldn't open the file '%s'\"), git_path_bisect_log());\n> +\n> +\tcommit = lookup_commit_reference(oid.hash);\n> +\tformat_commit_message(commit, \"%s\", &commit_name, &pp);\n> +\tfprintf(fp, \"# %s: [%s] %s\\n\", state, sha1_to_hex(oid.hash),\n> +\t\tcommit_name.buf);\n> +\tstrbuf_release(&commit_name);\n> +\n> +\tif (!nolog)\n> +\t\tfprintf(fp, \"git bisect %s %s\\n\", state, rev);\n> +\n> +\tfclose(fp);\n> +\treturn 0;\n\nYou seem to be _release()ing tag all over the place.\n\nWould it make sense to have a single clean-up label at the end of\nfunction, introduce a \"int retval\" variable and set it to -1 (or\nwhatever) when an error is detected and \"goto\" to the label?  It may\nmake it harder to make such a leak.  That is, to end the function\nmore like:\n\n\tfinish:\n        \tif (fp)\n                \tfclose(fp);\n\t\tstrbuf_release(&tag);\n                strbuf_release(&commit_name);\n\t\treturn retval;\n\t}\n\nand have sites with potential errors do something like this:\n\n\tif (update_ref(...)) {\n        \tretval = -1;\n                goto finish;\n\t}\n\n> +\tstruct bisect_terms terms;\n> +\tbisect_terms_init(&terms);\n\nWith the type of \"struct bisect_terms\" members corrected, you do not\neven need the _init() function.\n\n> @@ -182,24 +251,38 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>  \t\tusage_with_options(git_bisect_helper_usage, options);\n>  \n>  \tswitch (cmdmode) {\n> +\tint nolog;\n>  \tcase NEXT_ALL:\n>  \t\treturn bisect_next_all(prefix, no_checkout);\n>  \tcase WRITE_TERMS:\n>  \t\tif (argc != 2)\n>  \t\t\tdie(_(\"--write-terms requires two arguments\"));\n> -\t\treturn write_terms(argv[0], argv[1]);\n> +\t\tres = write_terms(argv[0], argv[1]);\n> +\t\tbreak;\n>  \tcase BISECT_CLEAN_STATE:\n>  \t\tif (argc != 0)\n>  \t\t\tdie(_(\"--bisect-clean-state requires no arguments\"));\n> -\t\treturn bisect_clean_state();\n> +\t\tres = bisect_clean_state();\n> +\t\tbreak;\n>  \tcase BISECT_RESET:\n>  \t\tif (argc > 1)\n>  \t\t\tdie(_(\"--bisect-reset requires either zero or one arguments\"));\n> -\t\treturn bisect_reset(argc ? argv[0] : NULL);\n> +\t\tres = bisect_reset(argc ? argv[0] : NULL);\n> +\t\tbreak;\n>  \tcase CHECK_EXPECTED_REVS:\n> -\t\treturn check_expected_revs(argv, argc);\n> +\t\tres = check_expected_revs(argv, argc);\n> +\t\tbreak;\n> +\tcase BISECT_WRITE:\n> +\t\tif (argc != 4 && argc != 5)\n> +\t\t\tdie(_(\"--bisect-write requires either 4 or 5 arguments\"));\n> +\t\tnolog = (argc == 5) && !strcmp(argv[4], \"nolog\");\n> +\t\tstrbuf_addstr(&terms.term_good, argv[2]);\n> +\t\tstrbuf_addstr(&terms.term_bad, argv[3]);\n\nHere,\n\n\tterms.term_good = argv[2];\n\tterms.term_bad = argv[3];\n\nand then you do not need bisect_terms_release() at all.\n\n> +\t\tres = bisect_write(argv[0], argv[1], &terms, nolog);\n> +\t\tbreak;\n>  \tdefault:\n>  \t\tdie(\"BUG: unknown subcommand '%d'\", cmdmode);\n>  \t}\n> -\treturn 0;\n> +\tbisect_terms_release(&terms);\n> +\treturn res;\n>  }\n"},{"id":"300180","messageId":"xmqqmvk0n2pl.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"01020156b73fe6b3-3ccd9de5-604d-4e7d-919d-a3adae869ebf-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH v14 12/27] bisect--helper: `get_terms` & `bisect_terms` shell function in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-25T18:05:58Z","receivedAt":"2016-08-25T18:15:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n> +static int bisect_terms(struct bisect_terms *terms, const char **argv, int argc)\n> +{\n> +\tint i;\n> +\n> +\tif (get_terms(terms)) {\n> +\t\tfprintf(stderr, _(\"no terms defined\\n\"));\n> +\t\treturn -1;\n> +\t}\n> +\tif (argc == 0) {\n> +\t\tprintf(_(\"Your current terms are %s for the old state\\nand \"\n> +\t\t       \"%s for the new state.\\n\"), terms->term_good.buf,\n> +\t\t       terms->term_bad.buf);\n> +\t\treturn 0;\n> +\t}\n> +\n> +\tfor (i = 0; i < argc; i++) {\n> +\t\tif (!strcmp(argv[i], \"--term-good\"))\n> +\t\t\tprintf(\"%s\\n\", terms->term_good.buf);\n> +\t\telse if (!strcmp(argv[i], \"--term-bad\"))\n> +\t\t\tprintf(\"%s\\n\", terms->term_bad.buf);\n> +\t\telse\n> +\t\t\tprintf(_(\"invalid argument %s for 'git bisect \"\n> +\t\t\t\t  \"terms'.\\nSupported options are: \"\n> +\t\t\t\t  \"--term-good|--term-old and \"\n> +\t\t\t\t  \"--term-bad|--term-new.\"), argv[i]);\n> +\t}\n\nThe original took only one and gave one answer (and errored out when\nthe user asked for more), but this one loops.  I can see either way\nis OK and do not think of a good reason to favor one over the other;\nunless there is a strong reason why you need this extended behaviour\nthat allows users to ask multiple questions, I'd say we should keep\nthe original behaviour.\n\n"},{"id":"300186","messageId":"xmqqd1kwn035.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"01020156b73fe6b9-5e500c96-9bc3-4a6b-beb9-b5988dc9ee85-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH v14 13/27] bisect--helper: `bisect_start` shell function partially in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-25T19:02:38Z","receivedAt":"2016-08-25T19:04:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n> +static int bisect_start(struct bisect_terms *terms, int no_checkout,\n> +\t\t\tconst char **argv, int argc)\n> +{\n> +\tint i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;\n> +\tint flags, pathspec_pos;\n> +\tstruct string_list revs = STRING_LIST_INIT_DUP;\n> +\tstruct string_list states = STRING_LIST_INIT_DUP;\n\nThe original has a single state, not states.  Let's see if there is\na reason behind the name change....\n\n> +\tunsigned char sha1[20];\n> +\tstruct object_id oid;\n\nMore on these below...\n\n> + ...\n> +\tfor (i = 0; i < argc; i++) {\n> +\t\tconst char *commit_id = xstrfmt(\"%s^{commit}\", argv[i]);\n> +\t\tif (!strcmp(argv[i], \"--\")) {\n> +\t\t\thas_double_dash = 1;\n> +\t\t\tbreak;\n> +\t\t} else if (!strcmp(argv[i], \"--no-checkout\"))\n> +\t\t\tno_checkout = 1;\n> +\t\telse if (!strcmp(argv[i], \"--term-good\") ||\n> + ...\n> +\t\t} else if (starts_with(argv[i], \"--\") &&\n> +\t\t\t !one_of(argv[i], \"--term-good\", \"--term-bad\", NULL)) {\n> +\t\t\tstring_list_clear(&revs, 0);\n> +\t\t\tstring_list_clear(&states, 0);\n> +\t\t\tdie(_(\"unrecognised option: '%s'\"), argv[i]);\n> +\t\t} else if (get_oid(commit_id, &oid) && has_double_dash) {\n> +\t\t\tstring_list_clear(&revs, 0);\n> +\t\t\tstring_list_clear(&states, 0);\n> +\t\t\tdie(_(\"'%s' does not appear to be a valid revision\"), argv[i]);\n> +\t\t} else {\n> +\t\t\tstring_list_append(&revs, oid_to_hex(&oid));\n> +\t\t}\n> +\t}\n\nWhat I do not understand is clearing the string list \"states\" inside\nthis loop.  It may have been INIT_DUPed, but nothing in this loop\nadds anything to it.  Because \"revs\" does get extended in the loop,\nit is understandable if you wanted to clear it before dying, but \"if\nyou are dying anyway why bother clearing?\" is also a valid stance to\ntake.\n\nThe same \"perhaps want to use the 'retval' with goto 'finish:' pattern?\"\ncomment applies here, too.\n\n> +\tpathspec_pos = i;\n> +\n> +\t/*\n> +\t * The user ran \"git bisect start <sha1> <sha1>\", hence did not\n> +\t * explicitly specify the terms, but we are already starting to\n> +\t * set references named with the default terms, and won't be able\n> +\t * to change afterwards.\n> +\t */\n> +\tmust_write_terms |= !!revs.nr;\n> +\tfor (i = 0; i < revs.nr; i++) {\n> +\t\tif (bad_seen)\n> +\t\t\tstring_list_append(&states, terms->term_good.buf);\n> +\t\telse {\n> +\t\t\tbad_seen = 1;\n> +\t\t\tstring_list_append(&states, terms->term_bad.buf);\n> +\t\t}\n> +\t}\n\nThis is certainly different from the original.  We used to do one\n\"bisect_write\" per element in revs in the loop; we no longer do that\nand instead collect them in states list.  Each element in these two\nlists, i.e. revs.item[i] and states.item[i], corresponds to each\nother.\n\nThat explains why the variable is renamed to states.  We haven't\nseen enough to say if this behaviour change is a good idea or not.\n\n> +\t/*\n> +\t * Verify HEAD\n> +\t */\n> +\thead = resolve_ref_unsafe(\"HEAD\", 0, sha1, &flags);\n> +\tif (!head) {\n> +\t\tif (get_sha1(\"HEAD\", sha1)) {\n> +\t\t\tstring_list_clear(&revs, 0);\n> +\t\t\tstring_list_clear(&states, 0);\n> +\t\t\tdie(_(\"Bad HEAD - I need a HEAD\"));\n> +\t\t}\n> +\t}\n> +\tif (!is_empty_or_missing_file(git_path_bisect_start())) {\n> +\t\t/* Reset to the rev from where we started */\n> +\t\tstrbuf_read_file(&start_head, git_path_bisect_start(), 0);\n> +\t\tstrbuf_trim(&start_head);\n> +\t\tif (!no_checkout) {\n> +\t\t\tstruct argv_array argv = ARGV_ARRAY_INIT;\n> +\t\t\targv_array_pushl(&argv, \"checkout\", start_head.buf,\n> +\t\t\t\t\t \"--\", NULL);\n> +\t\t\tif (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {\n> +\t\t\t\terror(_(\"checking out '%s' failed. Try 'git \"\n> +\t\t\t\t\t\"bisect start <valid-branch>'.\"),\n> +\t\t\t\t      start_head.buf);\n> +\t\t\t\tstrbuf_release(&start_head);\n> +\t\t\t\tstring_list_clear(&revs, 0);\n> +\t\t\t\tstring_list_clear(&states, 0);\n> +\t\t\t\treturn -1;\n\nThe original died here, but you expect the caller to respond to a\nnegative return.  I haven't read enough to judge if that is a good\nidea, but doesn't it make sense to do the same throughout the\nfunction consistently?  I saw a few die()'s already in the command\nline parsing loop--shouldn't they also return -1?\n\nThe original has called bisect_write already when we attempt this\ncheckout and the user will see the states in the filesystem.  This\nrewrite does not.  What effect does this behaviour change have to\nthe end-user experience?  The error message tells the end user to\nrun another \"git bisect start\" with a valid commit, and when that\nhappens, hopefully she will give us something we can check out, and\nthen we will hit the bisect_clean_state() call we see below before\nstarting to do anything meaningful, so I am guessing it won't, but\nI just want to make sure that you thought about the ramifications\nof the change above to delay calls to bisect_write.\n\n> +\t\t\t}\n> +\t\t}\n> +\t} else {\n> +\t\tif (starts_with(head, \"refs/heads/\") ||\n> +\t\t    !get_oid_hex(head, &oid) || ref_exists(head)) {\n\nThis ref_exists() check is new, and I think it should not be there.\nIn the original, if .git/HEAD pointed at refs/tags/v1.0, we would\nhave diagnosed it as a strange symbolic ref.  This no longer does.\n\nIf you wanted to make sure that the branch exists, it should have\nbeen\n\n\tif ((starts_with(head, \"refs/heads/\") && ref_exists(head)) ||\n\t    !get_oid_hex(head, &oid)) {\n\nanyway.\n\nAlso, why do you use get_oid_hex() here?  You used get_sha1(\"HEAD\",\nsha1) in the early part of \"Verify HEAD\" above, which seems to be\nperfectly adequate.  That sha1 taken from get_sha1() is what you end\nup using in the code below anyway.  If you can stick to one or the\nother, please do so.\n\n> +\t\t\t/*\n> +\t\t\t * This error message should only be triggered by\n> +\t\t\t * cogito usage, and cogito users should understand\n> +\t\t\t * it relates to cg-seek.\n> +\t\t\t */\n> +\t\t\tif (!is_empty_or_missing_file(git_path_head_name())) {\n> +\t\t\t\tstrbuf_release(&start_head);\n> +\t\t\t\tstring_list_clear(&revs, 0);\n> +\t\t\t\tstring_list_clear(&states, 0);\n> +\t\t\t\tdie(_(\"won't bisect on cg-seek'ed tree\"));\n> +\t\t\t}\n\nNot to be done as part of this series, but it probably is safe to\nretire this part by now.  Cogito has been dead for how many years?\n\n> +\t\t\tif (starts_with(head, \"refs/heads/\")) {\n> +\t\t\t\tstrbuf_reset(&start_head);\n> +\t\t\t\tstrbuf_addstr(&start_head, head + 11);\n\nskip_prefix?\n\n> +\t\t\t}\n> +\t\t\telse {\n> +\t\t\t\tstrbuf_reset(&start_head);\n> +\t\t\t\tstrbuf_addstr(&start_head, sha1_to_hex(sha1));\n> +\t\t\t}\n> +\t\t} else {\n> +\t\t\tstrbuf_release(&start_head);\n> +\t\t\tstring_list_clear(&revs, 0);\n> +\t\t\tstring_list_clear(&states, 0);\n> +\t\t\tdie(_(\"Bad HEAD - strange symbolic ref\"));\n> +\t\t}\n> +\t}\n\nI wonder the whole thing above is better restructured to avoid\nrepeated checks of the same thing.\n\n\tif (is it 40-hex, i.e. detached?) {\n\t\tstuff it to start_head;\n\t} else if (skip_prefix(head, \"refs/heads/\", &branchname)) {\n        \tdo the \"cogito\" check;\n                stuff it to start_head;\n\t} else {\n        \tthat's a strange symbolic ref HEAD you have there;\n\t}\n\n> +\t/*\n> +\t * Get rid of any old bisect state.\n> +\t */\n> +\tif (bisect_clean_state()) {\n> +\t\treturn -1;\n> +\t}\n\nIf we are going to get a lot more code inside {} in later patches,\nthen this single \"return -1\" enclosed inside a {} pair is\njustifiable (but in that case we'd prefer an empty line after it to\nseparate it from the next comment block).  Otherwise lose the {}.\n\n> +\t/*\n> +\t * In case of mistaken revs or checkout error, or signals received,\n> +\t * \"bisect_auto_next\" below may exit or misbehave.\n> +\t * We have to trap this to be able to clean up using\n> +\t * \"bisect_clean_state\".\n> +\t */\n\nThat explains the \"trap\" statements in the original.  Does it apply\nto this code here?\n\n> +\t/*\n> +\t * Write new start state\n> +\t */\n> +\twrite_file(git_path_bisect_start(), \"%s\\n\", start_head.buf);\n> +\n> +\tif (no_checkout) {\n> +\t\tget_oid(start_head.buf, &oid);\n> +\t\tif (update_ref(NULL, \"BISECT_HEAD\", oid.hash, NULL, 0,\n> +\t\t\t       UPDATE_REFS_MSG_ON_ERR)) {\n> +\t\t\tstrbuf_release(&start_head);\n> +\t\t\tstring_list_clear(&revs, 0);\n> +\t\t\tstring_list_clear(&states, 0);\n> +\t\t\treturn -1;\n> +\t\t}\n> +\t}\n> +\tstrbuf_release(&start_head);\n> +\n> +\tif (pathspec_pos < argc - 1)\n> +\t\tsq_quote_argv(&bisect_names, argv + pathspec_pos, 0);\n> +\twrite_file(git_path_bisect_names(), \"%s\\n\", bisect_names.buf);\n> +\tstrbuf_release(&bisect_names);\n> +\n> +\tfor (i = 0; i < states.nr; i++) {\n> +\t\tif (bisect_write(states.items[i].string,\n> +\t\t\t\t  revs.items[i].string, terms, 1)) {\n> +\t\t\tstring_list_clear(&revs, 0);\n> +\t\t\tstring_list_clear(&states, 0);\n> +\t\t\treturn -1;\n> +\t\t}\n> +\t}\n\nHmph.  I do not particuarly see why doing this in a separate loop\nhere, instead of doing it just like in the original, i.e. inside the\nloop we already saw, is an improvement.  It seems to me that the\nonly effect of this change is to make the code more complex by\nforcing you to maintain (and clear) another string list \"states\" and\nhave a separate loop here.\n\nUnless there is a reason why delaying calls to bisect_write() is a\ngood thing and I am not seeing it, that is.\n\n> diff --git a/git-bisect.sh b/git-bisect.sh\n> index d6c8b5a..f0896b3 100755\n> --- a/git-bisect.sh\n> +++ b/git-bisect.sh\n> @@ -71,122 +71,7 @@ bisect_autostart() {\n>  }\n>  \n>  bisect_start() {\n> -...\n> +\tgit bisect--helper --bisect-start $@ || exit\n>  ...\n> +\tget_terms\n\nUnderstandable.  As the handling of the terms is done in the helper,\nyou need to read the terms it left in the filesystem.  OK.\n\n>  \tbisect_auto_next\n\n"},{"id":"300189","messageId":"xmqq8tvkmy7b.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"xmqqd1kwn035.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v14 13/27] bisect--helper: `bisect_start` shell function partially in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-25T19:43:20Z","receivedAt":"2016-08-25T19:51:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n>> +\tfor (i = 0; i < revs.nr; i++) {\n>> +\t\tif (bad_seen)\n>> +\t\t\tstring_list_append(&states, terms->term_good.buf);\n>> +\t\telse {\n>> +\t\t\tbad_seen = 1;\n>> +\t\t\tstring_list_append(&states, terms->term_bad.buf);\n>> +\t\t}\n>> +\t}\n>\n> This is certainly different from the original.  We used to do one\n> \"bisect_write\" per element in revs in the loop; we no longer do that\n> and instead collect them in states list.  Each element in these two\n> lists, i.e. revs.item[i] and states.item[i], corresponds to each\n> other.\n>\n> That explains why the variable is renamed to states.  We haven't\n> seen enough to say if this behaviour change is a good idea or not.\n\nAhh, I misread the original.  It accumulates the writes to be\nexecuted in $eval and does so at the end.  So there is no change in\nbehaviour.\n\nSo please ignore that point in the previous message.  That leaves\nonly the following points:\n\n * Perhaps 'retval' with 'goto finish' pattern?\n\n * ref_exists()?  Perhaps use skip_prefix(head, \"refs/heads/, &branch)?\n\n * if (clean-state) { return -1 }?\n\n * Is comment on trap relevant here?\n\nSorry, and thanks.\n"},{"id":"300191","messageId":"xmqq37lsmw15.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"01020156b73fe6ce-3b204354-849b-40fd-93ff-2ebcf77df91c-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH v14 14/27] bisect--helper: `bisect_next` and `bisect_auto_next` shell function in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-25T20:30:14Z","receivedAt":"2016-08-25T20:30:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n> A lot of parts of bisect.c uses exit() and these signals are then\n> trapped in the `bisect_start` function. Since the shell script ceases\n> its existence it would be necessary to convert those exit() calls to\n> return statements so that errors can be reported efficiently in C code.\n\nIs efficiency really an issue?  I think the real reason is that it\nwould make it impossible for the callers to handle errors, if you do\nnot convert and let the error codepaths exit().\n\n> @@ -729,7 +735,7 @@ static struct commit **get_bad_and_good_commits(int *rev_nr)\n>  \treturn rev;\n>  }\n>  \n> -static void handle_bad_merge_base(void)\n> +static int handle_bad_merge_base(void)\n>  {\n>  \tif (is_expected_rev(current_bad_oid)) {\n>  \t\tchar *bad_hex = oid_to_hex(current_bad_oid);\n> @@ -750,17 +756,18 @@ static void handle_bad_merge_base(void)\n>  \t\t\t\t\"between %s and [%s].\\n\"),\n>  \t\t\t\tbad_hex, term_bad, term_good, bad_hex, good_hex);\n>  \t\t}\n> -\t\texit(3);\n> +\t\treturn 3;\n>  \t}\n>  \n>  \tfprintf(stderr, _(\"Some %s revs are not ancestor of the %s rev.\\n\"\n>  \t\t\"git bisect cannot work properly in this case.\\n\"\n>  \t\t\"Maybe you mistook %s and %s revs?\\n\"),\n>  \t\tterm_good, term_bad, term_good, term_bad);\n> -\texit(1);\n> +\tbisect_clean_state();\n> +\treturn 1;\n\nWhat is the logic behind this function sometimes clean the state,\nand some other times do not, when it makes an error-return?  We see\nabove that \"return 3\" codepath leaves the state behind.\n\nEither you forgot a necessary clean_state in \"return 3\" codepath,\nor you forgot to document why the distinction exists in the in-code\ncomment for the function.  I cannot tell which, but I am leaning\ntowards guessing that it is the former.\n\n> -static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)\n> +static int check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)\n>  {\n>  \tchar *filename = git_pathdup(\"BISECT_ANCESTORS_OK\");\n>  \tstruct stat st;\n> -\tint fd;\n> +\tint fd, res = 0;\n>  \n>  \tif (!current_bad_oid)\n>  \t\tdie(_(\"a %s revision is needed\"), term_bad);\n\nCan you let it die yere?\n\n> @@ -873,8 +890,11 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)\n>  \t\t\t      filename);\n>  \telse\n>  \t\tclose(fd);\n> +\n> +\treturn 0;\n>   done:\n>  \tfree(filename);\n> +\treturn 0;\n>  }\n\nWho owns \"filename\"?  The first \"return 0\" leaves it unfreed, and\nwhen \"goto done\" is done, it is freed.\n\nThe above two may indicate that \"perhaps 'retval + goto finish'\npattern?\" is a really relevant suggestion for the earlier steps in\nthis series.\n\n>  \tif (!all) {\n>  \t\tfprintf(stderr, _(\"No testable commit found.\\n\"\n>  \t\t\t\"Maybe you started with bad path parameters?\\n\"));\n> -\t\texit(4);\n> +\t\treturn 4;\n>  \t}\n>  \n>  \tbisect_rev = revs.commits->item->object.oid.hash;\n>  \n>  \tif (!hashcmp(bisect_rev, current_bad_oid->hash)) {\n> -\t\texit_if_skipped_commits(tried, current_bad_oid);\n> +\t\tres = exit_if_skipped_commits(tried, current_bad_oid);\n> +\t\tif (res)\n> +\t\t\treturn res;\n> +\n>  \t\tprintf(\"%s is the first %s commit\\n\", sha1_to_hex(bisect_rev),\n>  \t\t\tterm_bad);\n>  \t\tshow_diff_tree(prefix, revs.commits->item);\n>  \t\t/* This means the bisection process succeeded. */\n> -\t\texit(10);\n> +\t\treturn 10;\n>  \t}\n>  \n>  \tnr = all - reaches - 1;\n> @@ -1005,7 +1033,11 @@ int bisect_next_all(const char *prefix, int no_checkout)\n>  \t\t  \"Bisecting: %d revisions left to test after this %s\\n\",\n>  \t\t  nr), nr, steps_msg);\n>  \n> -\treturn bisect_checkout(bisect_rev, no_checkout);\n> +\tres = bisect_checkout(bisect_rev, no_checkout);\n> +\tif (res)\n> +\t\tbisect_clean_state();\n> +\n> +\treturn res;\n>  }\n\nThere were tons of \"exit_if\" that was converted to \"if (res) return\nres\" above, instead of jumping here to cause clean_state to be\ncalled.  I cannot tell if this new call to clean_state() is wrong,\nor all the earlier \"return res\" should come here.  I am guessing the\nlatter.\n\n> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n> index c64996a..ef7b3a1 100644\n> --- a/builtin/bisect--helper.c\n> +++ b/builtin/bisect--helper.c\n> @@ -8,6 +8,7 @@\n>  #include \"run-command.h\"\n>  #include \"prompt.h\"\n>  #include \"quote.h\"\n> +#include \"revision.h\"\n>  \n>  static GIT_PATH_FUNC(git_path_bisect_terms, \"BISECT_TERMS\")\n>  static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXPECTED_REV\")\n> @@ -29,6 +30,8 @@ static const char * const git_bisect_helper_usage[] = {\n>  \tN_(\"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]\"),\n>  \tN_(\"git bisect--helper --bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]\"\n>  \t\t\t\t\t      \"[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]\"),\n> +\tN_(\"git bisect--helper --bisect-next\"),\n> +\tN_(\"git bisect--helper --bisect-auto-next\"),\n>  \tNULL\n>  };\n>  \n> @@ -396,6 +399,129 @@ static int bisect_terms(struct bisect_terms *terms, const char **argv, int argc)\n>  \treturn 0;\n>  }\n>  \n> +static int register_good_ref(const char *refname,\n> +\t\t\t     const struct object_id *oid, int flags,\n> +\t\t\t     void *cb_data)\n> +{\n> +\tstruct string_list *good_refs = cb_data;\n> +\tstring_list_append(good_refs, oid_to_hex(oid));\n> +\treturn 0;\n> +}\n> +\n> +static int bisect_next(struct bisect_terms *terms, const char *prefix)\n> +{\n> +\tint res, no_checkout;\n> +\n> +\t/* In case of mistaken revs or checkout error, or signals received,\n\nThat's an unbalanced comment.  You end the block with \"*/\" on its\nown line, so you should start the block with \"/*\" on its own line.\nThere seems to be at least one more such comment in this patch but I\nwon't repeat.\n\n> +\t * \"bisect_auto_next\" below may exit or misbehave.\n> +\t * We have to trap this to be able to clean up using\n> +\t * \"bisect_clean_state\".\n> +\t */\n\n\"exit\" meaning \"call exit() to terminate the process\", or something\nelse?  If the latter, don't say \"exit\", but say \"return error\".\n\n> +\tif (bisect_next_check(terms, terms->term_good.buf))\n> +\t\treturn -1;\n\nMental note.  The \"autostart\" in the original is gone.  Perhaps it\nis done by next_check in this code, but we haven't seen that yet.\n\n> +\tno_checkout = !is_empty_or_missing_file(git_path_bisect_head());\n> +\n> +\t/* Perform all bisection computation, display and checkout */\n> +\tres = bisect_next_all(prefix , no_checkout);\n> +\n> +\tif (res == 10) {\n> +\t\tFILE *fp;\n> +\t\tunsigned char sha1[20];\n> +\t\tstruct commit *commit;\n> +\t\tstruct pretty_print_context pp = {0};\n> +\t\tstruct strbuf commit_name = STRBUF_INIT;\n> +\t\tchar *bad_ref = xstrfmt(\"refs/bisect/%s\",\n> +\t\t\t\t\t      terms->term_bad.buf);\n> +\t\tread_ref(bad_ref, sha1);\n> +\t\tcommit = lookup_commit_reference(sha1);\n> +\t\tformat_commit_message(commit, \"%s\", &commit_name, &pp);\n> +\t\tfp = fopen(git_path_bisect_log(), \"a\");\n> +\t\tif (!fp) {\n> +\t\t\tfree(bad_ref);\n> +\t\t\tstrbuf_release(&commit_name);\n> +\t\t\treturn -1;\n> +\t\t}\n> +\t\tif (fprintf(fp, \"# first %s commit: [%s] %s\\n\",\n> +\t\t\t    terms->term_bad.buf, sha1_to_hex(sha1),\n> +\t\t\t    commit_name.buf) < 1){\n> +\t\t\tfree(bad_ref);\n> +\t\t\tstrbuf_release(&commit_name);\n> +\t\t\tfclose(fp);\n> +\t\t\treturn -1;\n> +\t\t}\n> +\t\tfree(bad_ref);\n> +\t\tstrbuf_release(&commit_name);\n> +\t\tfclose(fp);\n> +\t\treturn 0;\n\nDoesn't it bother you that you have to write free(bad_ref)...fclose(fp)\nrepeatedly?\n\n> +\t}\n> +\telse if (res == 2) {\n> +\t\tFILE *fp;\n> +\t\tstruct rev_info revs;\n> +\t\tstruct argv_array rev_argv = ARGV_ARRAY_INIT;\n> +\t\tstruct string_list good_revs = STRING_LIST_INIT_DUP;\n> +\t\tstruct pretty_print_context pp = {0};\n> +\t\tstruct commit *commit;\n> +\t\tchar *term_good = xstrfmt(\"%s-*\", terms->term_good.buf);\n> +\t\tint i;\n> +\n> +\t\tfp = fopen(git_path_bisect_log(), \"a\");\n> +\t\tif (!fp) {\n> +\t\t\tfree(term_good);\n> +\t\t\treturn -1;\n> +\t\t}\n> +\t\tif (fprintf(fp, \"# only skipped commits left to test\\n\") < 1) {\n> +\t\t\tfree(term_good);\n> +\t\t\tfclose(fp);\n> +\t\t\treturn -1;\n> +\t\t}\n> +\t\tfor_each_glob_ref_in(register_good_ref, term_good,\n> +\t\t\t\t     \"refs/bisect/\", (void *) &good_revs);\n> +\n> +\t\tfree(term_good);\n\nDoesn't it bother you that you have to write free(term_good) repeatedly?\n\n> +\t\targv_array_pushl(&rev_argv, \"skipped_commits\", \"refs/bisect/bad\", \"--not\", NULL);\n> +\t\tfor (i = 0; i < good_revs.nr; i++)\n> +\t\t\targv_array_push(&rev_argv, good_revs.items[i].string);\n> +\n> +\t\t/* It is important to reset the flags used by revision walks\n> +\t\t * as the previous call to bisect_next_all() in turn\n> +\t\t * setups a revision walk.\n> +\t\t */\n> +\t\treset_revision_walk();\n> +\t\tinit_revisions(&revs, NULL);\n> +\t\trev_argv.argc = setup_revisions(rev_argv.argc, rev_argv.argv, &revs, NULL);\n> +\t\targv_array_clear(&rev_argv);\n> +\t\tstring_list_clear(&good_revs, 0);\n\nAre you sure that the revision walking machinery is prepared to see\nthe argv[] and elements in it you have given to setup_revisions()\ngets cleared before it starts doing the real work in\nprepare_revision_walk()?  I am reasonably sure that the machinery\nborrows strings like pathspec elements from the caller and expects\nthem to stay during revision traversal.\n\nYou seem to have acquired a habit of freeing and clearing things\nearly, which is bad.  Instead, make it a habit of free/clear at the\nend, and make sure all error paths go through that central freeing\nsite.  That tends to future-proof your code better from leaking even\nwhen later other people change it.\n\n> +\t\tif (prepare_revision_walk(&revs)) {\n> +\t\t\tdie(_(\"revision walk setup failed\\n\"));\n> +\t\t}\n\nThis one is still allowed to die, without clean_state?\n\n> +\t\twhile ((commit = get_revision(&revs)) != NULL) {\n> +\t\t\tstruct strbuf commit_name = STRBUF_INIT;\n> +\t\t\tformat_commit_message(commit, \"%s\",\n> +\t\t\t\t\t      &commit_name, &pp);\n> +\t\t\tfprintf(fp, \"# possible first %s commit: \"\n> +\t\t\t\t    \"[%s] %s\\n\", terms->term_bad.buf,\n> +\t\t\t\t    oid_to_hex(&commit->object.oid),\n> +\t\t\t\t    commit_name.buf);\n> +\t\t\tstrbuf_release(&commit_name);\n> +\t\t}\n> +\n> +\t\tfclose(fp);\n> +\t\treturn res;\n> +\t}\n> +\n> +\treturn res;\n> +}\n\n> @@ -415,47 +541,67 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,\n>  \t\tno_checkout = 1;\n>  \n>  \tfor (i = 0; i < argc; i++) {\n> -\t\tif (!strcmp(argv[i], \"--\")) {\n> +\t\tconst char *arg;\n> +\t\tif (starts_with(argv[i], \"'\"))\n> +\t\t\targ = sq_dequote(xstrdup(argv[i]));\n> +\t\telse\n> +\t\t\targ = argv[i];\n> +\t\tif (!strcmp(arg, \"--\")) {\n>  \t\t\thas_double_dash = 1;\n>  \t\t\tbreak;\n>  \t\t}\n>  \t}\n\nThis is really bad; you are blindly assuming that anything that\nbegins with \"'\" begins with \"'\" because \"git-bisect.sh\" sq-quoted\nand it never directly came from the command line that _wanted_ to\ngive you something that begins with a \"'\".\n\nI suspect that you should be able to dequote on the calling script\nside.  Then all these ugliness would disappear.\n\n>  \tfor (i = 0; i < argc; i++) {\n> -\t\tconst char *commit_id = xstrfmt(\"%s^{commit}\", argv[i]);\n> +\t\tconst char *arg, *commit_id;\n> +\t\tif (starts_with(argv[i], \"'\"))\n> +\t\t\targ = sq_dequote(xstrdup(argv[i]));\n> +\t\telse\n> +\t\t\targ = argv[i];\n\nLikewise.\n\n> +\t\tcommit_id = xstrfmt(\"%s^{commit}\", arg);\n\nIn any case, I think a separate \"const char *arg\" that is an alias\nto argv[i] in the loop is a very good idea to do from the very\nbeginning (i.e. should be done in a much much earlier patch in this\nseries).\n"},{"id":"300241","messageId":"CAFZEwPPfXvLUtcBR6cYAP2dT8FAePFPjDSnVm8BhpLN9cfR1uw@mail.gmail.com","threadId":"43909","inReplyTo":"xmqq4m69q3b2.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v14 07/27] bisect--helper: `bisect_reset` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-26T13:46:56Z","receivedAt":"2016-08-26T13:47:10Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Hey Junio,\n\nOn Thu, Aug 25, 2016 at 2:42 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Pranit Bauva <pranit.bauva@gmail.com> writes:\n>\n> > +static int bisect_reset(const char *commit)\n> > +{\n> > +     struct strbuf branch = STRBUF_INIT;\n> > +\n> > +     if (!commit) {\n> > +             if (strbuf_read_file(&branch, git_path_bisect_start(), 0) < 1) {\n>\n> Hmm, tricky but correct to do the \"< 1\" comparison.  If the file\n> does not exist, you'd get -1; if it fails to read it, you'd get -1;\n> if it turns out to be empty, you'd get 0.\n>\n> > +                     printf(\"We are not bisecting.\\n\");\n> > +                     return 0;\n> > +             }\n> > +             strbuf_rtrim(&branch);\n> > +     } else {\n> > +             struct object_id oid;\n> > +             if (get_oid(commit, &oid))\n> > +                     return error(_(\"'%s' is not a valid commit\"), commit);\n>\n> The original is\n>\n>         rev-parse --quiet --verify \"$1^{commit}\"\n>\n> Unless the caller of this function already appended \"^{commit}\" to\n> whatever the user gave \"bisect--helper bisect-reset\", this\n> conversion is not equivalent.  If you said\n>\n>     git bisect reset HEAD:\n>\n> get_oid() would tell you that the top-level tree object of the\n> current commit exists in the object store, but the original is\n> meant to catch \"That's not a commit, it's a tree!\" before attempting\n> to run \"git checkout\" on it.\n>\n> I think get_sha1_committish() is what you want to use here.\n>\n> > +             strbuf_addstr(&branch, commit);\n> > +     }\n>\n\nYa! get_sha1_committish() would be better. Thanks!\n\n>\n> Also this version fails to catch \"bisect reset a b c\" as an error, I\n> suspect.\n\nIt didn't when I tried it right now. Could you please elaborate on why\nyou think it can fail? There might be a thing which I haven't tested.\n\nRegards,\nPranit Bauva\n"},{"id":"300263","messageId":"xmqqshtrijdn.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"CAFZEwPPfXvLUtcBR6cYAP2dT8FAePFPjDSnVm8BhpLN9cfR1uw@mail.gmail.com","subject":"Re: [PATCH v14 07/27] bisect--helper: `bisect_reset` shell function in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-26T16:29:24Z","receivedAt":"2016-08-26T16:29:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n>> Also this version fails to catch \"bisect reset a b c\" as an error, I\n>> suspect.\n>\n> It didn't when I tried it right now. Could you please elaborate on why\n> you think it can fail? There might be a thing which I haven't tested.\n\nMy bad.  I just compared your bisect_reset() implementation that had\n\n    if (no specific commit) {\n    \treset to the branch\n    } else {\n\treset to the commit\n    }\n\nwith the original\n\n    case $# in\n    0)\treset to the branch ;;\n    1)  reset to the commit ;;\n    *)  give usage and die ;;\n    esac\n\nand took the difference and reacted \"ah, excess parameters are not\ndiagnosed in this function\".\n\nYour caller does complain about excess parameters without giving\nusage, and that is what I missed.\n\nI am not sure if you intended to change the behaviour in this case\nto avoid giving the usage string; I tend to think it is a good\nchange, but I didn't see it mentioned in the proposed commit log,\nwhich also contributed to my not noticing the test in the caller.\n\n"},{"id":"300304","messageId":"xmqq37lrfdvf.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"01020156b73fe6c6-60f4f6c2-9c39-4840-bbbf-18902961d57f-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH v14 15/27] bisect--helper: retire `--bisect-clean-state` subcommand","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-26T20:56:36Z","receivedAt":"2016-08-26T21:00:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n> The `bisect-clean-state` subcommand is no longer used in the shell\n> script while the C code uses `bisect_clean_state()` thus remove the\n> subcommand.\n\nGood.\n"},{"id":"300306","messageId":"xmqqy43jdyos.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"01020156b73fe6d7-8b80c663-7c77-469e-811f-40200ec6dbb1-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH v14 17/27] bisect--helper: `bisect_autostart` shell function in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-26T21:09:55Z","receivedAt":"2016-08-26T21:14:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n> @@ -410,6 +413,7 @@ static int bisect_next(struct bisect_terms *terms, const char *prefix)\n>  {\n>  \tint res, no_checkout;\n>  \n> +\tbisect_autostart(terms);\n>  \t/* In case of mistaken revs or checkout error, or signals received,\n>  \t * \"bisect_auto_next\" below may exit or misbehave.\n>  \t * We have to trap this to be able to clean up using\n\nThis change is extremely hard to reason about.\n\nWhy wasn't auto-start done at the very beginning of this function\nbefore?  Why does this start calling it all of a sudden?  Before\nautostart was rewritten in C in this step, who made sure the shell\nversion of autostart was called before bisect_next is called (which\nmust have become unnecessary with this step, and I fully expected a\nremoval of such a call in the shell version, but I didn't find such\na change in this patch)?\n\nOr is this series simply broken by lossage of autostart feature in\n\"bisect next\" between the step where bisect_next is rewritten in C\nand this step?\n\n"},{"id":"300317","messageId":"xmqqbn0fdt9e.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"01020156b73fe6d5-6a363195-eb91-48a0-9a3c-3159fba6d327-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH v14 21/27] bisect--helper: `bisect_log` shell function in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-26T23:07:09Z","receivedAt":"2016-08-26T23:07:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n> +static int bisect_log(void)\n> +{\n> +\tstruct strbuf buf = STRBUF_INIT;\n> +\n> +\tif (strbuf_read_file(&buf, git_path_bisect_log(), 256) < 0) {\n> +\t\tstrbuf_release(&buf);\n> +\t\treturn error(_(\"We are not bisecting.\\n\"));\n> +\t}\n> +\n> +\tprintf(\"%s\", buf.buf);\n> +\tstrbuf_release(&buf);\n> +\n> +\treturn 0;\n> +}\n\nHmph, is it really necessary to slurp everything in a strbuf before\nsending it out to the standard output?  Wouldn't it be sufficient to\nopen a file descriptor for reading on the log file and then hand it\nover to copy.c::copy_fd()?\n\n"},{"id":"300319","messageId":"xmqq7fb3dsg9.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"01020156b73fe6d7-6cd42223-f46c-4e4c-a15f-516fc13a4521-000000@eu-west-1.amazonses.com","subject":"Re: [PATCH v14 22/27] bisect--helper: `bisect_replay` shell function in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-26T23:24:38Z","receivedAt":"2016-08-26T23:30:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n> +static int get_next_word(struct strbuf *line, struct strbuf *word)\n> +{\n> +\tint i;\n> +\tfor (i = 0; line->buf[i] != ' ' && line->buf[i] != '\\0'; i++)\n> +\t\tstrbuf_addch(word, line->buf[i]);\n> +\n> +\treturn 0;\n> +}\n\nThis looks like a very non-standard way to use a string buffer.  The\nfunction does not even have to take line as a whole strbuf, because\nthe logic does not even look at line->len and relies on line->buf[]\nto be NUL terminated, which means the first parameter should instead\nbe \"const char *buf\", and the caller would feed then line.buf to the\nfunction.\n\nAnd I highly suspect that this is a very suboptimal interface, if\nthe caller then has to compute up to which byte in the line.buf to\nsplice away to get to the \"next word\" again.\n\nA better alternative with higher level of abstraction would instead\nbe to keep the two strbuf parameters as-is, but have this function\nresponsible for \"moving\" the first word of \"line\" strbuf into \"word\"\nstrbuf.  Then the caller can repeatedly call this function to get\neach word in \"word\" strbuf until \"line\" becomes empty if it wants to\nimplement \"a word at a time\" operation.\n\nIf that higher level of abstraction is too limiting for the caller\n(and also that would be just as inefficient as the patch under\ndiscussion), another alternative would be to have the caller\nmaintain \"the current byte position in the input\" and\ndo something like:\n\n\tint pos = 0;\n\n\twhile (pos < line.len) {\n                strbuf_reset(&word);\n                get_next_word(line.buf, pos, word);\n                pos += word.len;\n\t\tdo a thing on \"word\";\n\t}\n\nto implement \"a word at a time\" operation.  For this to work,\nget_next_word() would need to skip the leading blanks itself, of\ncourse.\n\nIn any case, I won't comment on the body of the function too deeply;\nit will probably become a lot cleaner if you employed the \"retval +\ngoto finish:\" pattern for error handling.  Use of dequote seems\ncorrect from the cursory look, too.\n\n"},{"id":"300327","messageId":"CAFZEwPP2j-+C=J-hiWEiW4wa=Yso27-M-QUABCTyd4WYieeezw@mail.gmail.com","threadId":"43909","inReplyTo":"xmqqlgzlolwa.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v14 08/27] bisect--helper: `is_expected_rev` & `check_expected_revs` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-27T09:14:04Z","receivedAt":"2016-08-27T09:15:51Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Hey Junio,\n\nOn Thu, Aug 25, 2016 at 3:43 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Pranit Bauva <pranit.bauva@gmail.com> writes:\n>\n>> +static int is_expected_rev(const char *expected_hex)\n>> +{\n>> +     struct strbuf actual_hex = STRBUF_INIT;\n>> +     int res = 0;\n>> +     if (strbuf_read_file(&actual_hex, git_path_bisect_expected_rev(), 0) >= 0) {\n>> +             strbuf_trim(&actual_hex);\n>> +             res = !strcmp(actual_hex.buf, expected_hex);\n>\n> If it is known to have 40-hex:\n>\n>  (1) accepting \">= 0\" seems way too lenient.  You only expect a\n>      41-byte file (or 42 if somebody would write CRLF, but I do not\n>      think anybody other than yourself is expected to write into\n>      this file, and you do not write CRLF yourself);\n>\n>  (2) strbuf_trim() is overly loose.  You only want to trim the\n>      terimnating LF and it is an error to have other trailing\n>      whitespaces.\n>\n> I think the latter is not a new problem and it is OK to leave it\n> as-is; limiting (1) to >= 40 may still be a good change, though,\n> because it makes the intention of the code clearer.\n\nI can do the first change. Since this wasn't present in the shell\ncode, I will also mention it in the commit message.\n\nRegards,\nPranit Bauva\n"},{"id":"300328","messageId":"CAFZEwPMcUf-Tm_ijJbEG1Bh7F+7ML2fw6Vw2Gt94B9gyoGL1FQ@mail.gmail.com","threadId":"43909","inReplyTo":"xmqqfuptol4h.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v14 09/27] bisect--helper: `bisect_write` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-27T09:33:57Z","receivedAt":"2016-08-27T09:34:04Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Hey Junio,\n\nOn Thu, Aug 25, 2016 at 4:00 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Pranit Bauva <pranit.bauva@gmail.com> writes:\n>\n>> +struct bisect_terms {\n>> +     struct strbuf term_good;\n>> +     struct strbuf term_bad;\n>> +};\n>\n> I think \"struct strbuf\" is overrated.  For things like this, where\n> these fields will never change once it is set (and setting it is\n> done atomically, not incrementally), there is no good reason to use\n> define the fields as strbuf.\n>\n> Only because you chose to use strbuf for these two fields, you have\n> to make unnecessarily copies of argv[] in the command parser, and\n> you have to remember to discard these copies later.\n>\n> I think you can just say \"const char *\" in this case.\n\nUsing struct strbuf is not really overrated but in fact required. But\nyes, for this patch it might seem as overrated. In the shell code\ninitally TERM_GOOD is set to \"good\" while TERM_BAD is set to \"bad\".\nNow there are a lot of instances (one of which is bisect_start()\nfunction) where this can change. So if we keep it as \"const char *\",\nit would be right to change the value of it after wards. And we cannot\nkeep it as \"char []\" because we don't know its size before hand.\n\n>> +static int bisect_write(const char *state, const char *rev,\n>> +                     const struct bisect_terms *terms, int nolog)\n>> +{\n>> +     struct strbuf tag = STRBUF_INIT;\n>> +     struct strbuf commit_name = STRBUF_INIT;\n>> +     struct object_id oid;\n>> +     struct commit *commit;\n>> +     struct pretty_print_context pp = {0};\n>> +     FILE *fp;\n>> +\n>> +     if (!strcmp(state, terms->term_bad.buf))\n>> +             strbuf_addf(&tag, \"refs/bisect/%s\", state);\n>> +     else if (one_of(state, terms->term_good.buf, \"skip\", NULL))\n>> +             strbuf_addf(&tag, \"refs/bisect/%s-%s\", state, rev);\n>> +     else\n>> +             return error(_(\"Bad bisect_write argument: %s\"), state);\n>\n> OK.\n>\n>> +     if (get_oid(rev, &oid)) {\n>> +             strbuf_release(&tag);\n>> +             return error(_(\"couldn't get the oid of the rev '%s'\"), rev);\n>> +     }\n>> +\n>> +     if (update_ref(NULL, tag.buf, oid.hash, NULL, 0,\n>> +                    UPDATE_REFS_MSG_ON_ERR)) {\n>> +             strbuf_release(&tag);\n>> +             return -1;\n>> +     }\n>> +     strbuf_release(&tag);\n>> +\n>> +     fp = fopen(git_path_bisect_log(), \"a\");\n>> +     if (!fp)\n>> +             return error_errno(_(\"couldn't open the file '%s'\"), git_path_bisect_log());\n>> +\n>> +     commit = lookup_commit_reference(oid.hash);\n>> +     format_commit_message(commit, \"%s\", &commit_name, &pp);\n>> +     fprintf(fp, \"# %s: [%s] %s\\n\", state, sha1_to_hex(oid.hash),\n>> +             commit_name.buf);\n>> +     strbuf_release(&commit_name);\n>> +\n>> +     if (!nolog)\n>> +             fprintf(fp, \"git bisect %s %s\\n\", state, rev);\n>> +\n>> +     fclose(fp);\n>> +     return 0;\n>\n> You seem to be _release()ing tag all over the place.\n>\n> Would it make sense to have a single clean-up label at the end of\n> function, introduce a \"int retval\" variable and set it to -1 (or\n> whatever) when an error is detected and \"goto\" to the label?  It may\n> make it harder to make such a leak.  That is, to end the function\n> more like:\n\nI think I could use goto for this function.\n\n>         finish:\n>                 if (fp)\n>                         fclose(fp);\n>                 strbuf_release(&tag);\n>                 strbuf_release(&commit_name);\n>                 return retval;\n>         }\n>\n> and have sites with potential errors do something like this:\n>\n>         if (update_ref(...)) {\n>                 retval = -1;\n>                 goto finish;\n>         }\n>\n>> +     struct bisect_terms terms;\n>> +     bisect_terms_init(&terms);\n>\n> With the type of \"struct bisect_terms\" members corrected, you do not\n> even need the _init() function.\n\nDiscussed above.\n\n>> @@ -182,24 +251,38 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)\n>>               usage_with_options(git_bisect_helper_usage, options);\n>>\n>>       switch (cmdmode) {\n>> +     int nolog;\n>>       case NEXT_ALL:\n>>               return bisect_next_all(prefix, no_checkout);\n>>       case WRITE_TERMS:\n>>               if (argc != 2)\n>>                       die(_(\"--write-terms requires two arguments\"));\n>> -             return write_terms(argv[0], argv[1]);\n>> +             res = write_terms(argv[0], argv[1]);\n>> +             break;\n>>       case BISECT_CLEAN_STATE:\n>>               if (argc != 0)\n>>                       die(_(\"--bisect-clean-state requires no arguments\"));\n>> -             return bisect_clean_state();\n>> +             res = bisect_clean_state();\n>> +             break;\n>>       case BISECT_RESET:\n>>               if (argc > 1)\n>>                       die(_(\"--bisect-reset requires either zero or one arguments\"));\n>> -             return bisect_reset(argc ? argv[0] : NULL);\n>> +             res = bisect_reset(argc ? argv[0] : NULL);\n>> +             break;\n>>       case CHECK_EXPECTED_REVS:\n>> -             return check_expected_revs(argv, argc);\n>> +             res = check_expected_revs(argv, argc);\n>> +             break;\n>> +     case BISECT_WRITE:\n>> +             if (argc != 4 && argc != 5)\n>> +                     die(_(\"--bisect-write requires either 4 or 5 arguments\"));\n>> +             nolog = (argc == 5) && !strcmp(argv[4], \"nolog\");\n>> +             strbuf_addstr(&terms.term_good, argv[2]);\n>> +             strbuf_addstr(&terms.term_bad, argv[3]);\n>\n> Here,\n>\n>         terms.term_good = argv[2];\n>         terms.term_bad = argv[3];\n>\n> and then you do not need bisect_terms_release() at all.\n\nDiscussed above.\n\n>> +             res = bisect_write(argv[0], argv[1], &terms, nolog);\n>> +             break;\n>>       default:\n>>               die(\"BUG: unknown subcommand '%d'\", cmdmode);\n>>       }\n>> -     return 0;\n>> +     bisect_terms_release(&terms);\n>> +     return res;\n>>  }\n"},{"id":"300329","messageId":"CAFZEwPOf=UBo9iCAQ+DfFmZTjSJuQ+v8KayUKpb+G19bUC+pmQ@mail.gmail.com","threadId":"43909","inReplyTo":"xmqqbn0hoko0.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v14 11/27] bisect--helper: `bisect_next_check` & bisect_voc shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-27T09:35:06Z","receivedAt":"2016-08-27T09:35:12Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Hey Junio,\n\nOn Thu, Aug 25, 2016 at 4:10 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Pranit Bauva <pranit.bauva@gmail.com> writes:\n>\n>> +static int mark_good(const char *refname, const struct object_id *oid,\n>> +                  int flag, void *cb_data)\n>> +{\n>> +     int *m_good = (int *)cb_data;\n>> +     *m_good = 0;\n>> +     return 1;\n>> +}\n>> +\n>> +static char *bisect_voc(char *revision_type)\n>> +{\n>> +     if (!strcmp(revision_type, \"bad\"))\n>> +             return \"bad|new\";\n>> +     if (!strcmp(revision_type, \"good\"))\n>> +             return \"good|old\";\n>> +\n>> +     return NULL;\n>> +}\n>> +\n>> +static int bisect_next_check(const struct bisect_terms *terms,\n>> +                          const char *current_term)\n>> +{\n>> +     int missing_good = 1, missing_bad = 1;\n>> +     char *bad_ref = xstrfmt(\"refs/bisect/%s\", terms->term_bad.buf);\n>> +     char *good_glob = xstrfmt(\"%s-*\", terms->term_good.buf);\n>> +     char *bad_syn, *good_syn;\n>> +\n>> +     if (ref_exists(bad_ref))\n>> +             missing_bad = 0;\n>> +     free(bad_ref);\n>> +\n>> +     for_each_glob_ref_in(mark_good, good_glob, \"refs/bisect/\",\n>> +                          (void *) &missing_good);\n>> +     free(good_glob);\n>> +\n>> +     if (!missing_good && !missing_bad)\n>> +             return 0;\n>> +\n>> +     if (!current_term)\n>> +             return -1;\n>> +\n>> +     if (missing_good && !missing_bad && current_term &&\n>> +         !strcmp(current_term, terms->term_good.buf)) {\n>> +             char *yesno;\n>> +             /*\n>> +              * have bad (or new) but not good (or old). We could bisect\n>> +              * although this is less optimum.\n>> +              */\n>> +             fprintf(stderr, _(\"Warning: bisecting only with a %s commit\\n\"),\n>> +                     terms->term_bad.buf);\n>> +             if (!isatty(0))\n>> +                     return 0;\n>> +             /*\n>> +              * TRANSLATORS: Make sure to include [Y] and [n] in your\n>> +              * translation. The program will only accept English input\n>> +              * at this point.\n>> +              */\n>> +             yesno = git_prompt(_(\"Are you sure [Y/n]? \"), PROMPT_ECHO);\n>> +             if (starts_with(yesno, \"N\") || starts_with(yesno, \"n\"))\n>> +                     return -1;\n>> +\n>> +             return 0;\n>> +     }\n>> +     bad_syn = xstrdup(bisect_voc(\"bad\"));\n>> +     good_syn = xstrdup(bisect_voc(\"good\"));\n>> +     if (!is_empty_or_missing_file(git_path_bisect_start())) {\n>> +             error(_(\"You need to give me at least one %s and \"\n>> +                     \"%s revision. You can use \\\"git bisect %s\\\" \"\n>> +                     \"and \\\"git bisect %s\\\" for that. \\n\"),\n>> +                     bad_syn, good_syn, bad_syn, good_syn);\n>> +             free(bad_syn);\n>> +             free(good_syn);\n>> +             return -1;\n>> +     }\n>> +     else {\n>> +             error(_(\"You need to start by \\\"git bisect start\\\". You \"\n>> +                     \"then need to give me at least one %s and %s \"\n>> +                     \"revision. You can use \\\"git bisect %s\\\" and \"\n>> +                     \"\\\"git bisect %s\\\" for that.\\n\"),\n>> +                     good_syn, bad_syn, bad_syn, good_syn);\n>> +             free(bad_syn);\n>> +             free(good_syn);\n>> +             return -1;\n>> +     }\n>> +     free(bad_syn);\n>> +     free(good_syn);\n>> +\n>> +     return 0;\n>\n> This one looks OK, but I think the same \"Wouldn't it become cleaner\n> to have a 'finish:' label at the end and jump there?\" comment\n> applies to this implementation, too.\n\nFor this goto can simply things. Will do!\n\nRegards,\nPranit Bauva\n"},{"id":"300330","messageId":"CAFZEwPNTkgbFz-tcnLiaW9qvRSUoHgeNMzjnCjx7EwMHG71Niw@mail.gmail.com","threadId":"43909","inReplyTo":"xmqqmvk0n2pl.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v14 12/27] bisect--helper: `get_terms` & `bisect_terms` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-27T09:48:14Z","receivedAt":"2016-08-27T09:49:09Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Hey Junio,\n\nOn Thu, Aug 25, 2016 at 11:35 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Pranit Bauva <pranit.bauva@gmail.com> writes:\n>\n>> +static int bisect_terms(struct bisect_terms *terms, const char **argv, int argc)\n>> +{\n>> +     int i;\n>> +\n>> +     if (get_terms(terms)) {\n>> +             fprintf(stderr, _(\"no terms defined\\n\"));\n>> +             return -1;\n>> +     }\n>> +     if (argc == 0) {\n>> +             printf(_(\"Your current terms are %s for the old state\\nand \"\n>> +                    \"%s for the new state.\\n\"), terms->term_good.buf,\n>> +                    terms->term_bad.buf);\n>> +             return 0;\n>> +     }\n>> +\n>> +     for (i = 0; i < argc; i++) {\n>> +             if (!strcmp(argv[i], \"--term-good\"))\n>> +                     printf(\"%s\\n\", terms->term_good.buf);\n>> +             else if (!strcmp(argv[i], \"--term-bad\"))\n>> +                     printf(\"%s\\n\", terms->term_bad.buf);\n>> +             else\n>> +                     printf(_(\"invalid argument %s for 'git bisect \"\n>> +                               \"terms'.\\nSupported options are: \"\n>> +                               \"--term-good|--term-old and \"\n>> +                               \"--term-bad|--term-new.\"), argv[i]);\n>> +     }\n>\n> The original took only one and gave one answer (and errored out when\n> the user asked for more), but this one loops.  I can see either way\n> is OK and do not think of a good reason to favor one over the other;\n> unless there is a strong reason why you need this extended behaviour\n> that allows users to ask multiple questions, I'd say we should keep\n> the original behaviour.\n\nTrue! I can just use return error() instead of printf. Also I noticed\nthat this is printing to stdout while the original printed it to\nstderr. Thanks!\n\nRegards,\nPranit Bauva\n"},{"id":"300332","messageId":"CAFZEwPMBy0Ovcq-pUJkhoLiVF+uvm5fC0PD0RGPKobZ83Ciy3A@mail.gmail.com","threadId":"43909","inReplyTo":"xmqqshtrijdn.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v14 07/27] bisect--helper: `bisect_reset` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-27T10:52:23Z","receivedAt":"2016-08-27T10:52:29Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Hey Junio,\n\nOn Fri, Aug 26, 2016 at 9:59 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Pranit Bauva <pranit.bauva@gmail.com> writes:\n>\n>>> Also this version fails to catch \"bisect reset a b c\" as an error, I\n>>> suspect.\n>>\n>> It didn't when I tried it right now. Could you please elaborate on why\n>> you think it can fail? There might be a thing which I haven't tested.\n>\n> My bad.  I just compared your bisect_reset() implementation that had\n>\n>     if (no specific commit) {\n>         reset to the branch\n>     } else {\n>         reset to the commit\n>     }\n>\n> with the original\n>\n>     case $# in\n>     0)  reset to the branch ;;\n>     1)  reset to the commit ;;\n>     *)  give usage and die ;;\n>     esac\n>\n> and took the difference and reacted \"ah, excess parameters are not\n> diagnosed in this function\".\n>\n> Your caller does complain about excess parameters without giving\n> usage, and that is what I missed.\n>\n> I am not sure if you intended to change the behaviour in this case\n> to avoid giving the usage string; I tend to think it is a good\n> change, but I didn't see it mentioned in the proposed commit log,\n> which also contributed to my not noticing the test in the caller.\n\nI could include this in the commit message. Its not really something\nwhich we would want to test in the function because to the function,\nwe are not passing the raw arguments. Since we are removing that check\nfrom the function but including it in cmd_bisect__helper(), I will\ntalk about it in the commit message.\n\nRegards,\nPranit Bauva\n"},{"id":"300353","messageId":"CAFZEwPMotQ1k0EZN-buEt9MhJUKhXLS8eB5zV5A3Qr-j=DEwfQ@mail.gmail.com","threadId":"43909","inReplyTo":"xmqqd1kwn035.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v14 13/27] bisect--helper: `bisect_start` shell function partially in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-27T19:47:10Z","receivedAt":"2016-08-27T19:47:25Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Hey Junio,\n\nOn Fri, Aug 26, 2016 at 12:32 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Pranit Bauva <pranit.bauva@gmail.com> writes:\n>\n>> +static int bisect_start(struct bisect_terms *terms, int no_checkout,\n>> +                     const char **argv, int argc)\n>> +{\n>> +     int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;\n>> +     int flags, pathspec_pos;\n>> +     struct string_list revs = STRING_LIST_INIT_DUP;\n>> +     struct string_list states = STRING_LIST_INIT_DUP;\n>\n> The original has a single state, not states.  Let's see if there is\n> a reason behind the name change....\n>\n>> +     unsigned char sha1[20];\n>> +     struct object_id oid;\n>\n> More on these below...\n>\n>> + ...\n>> +     for (i = 0; i < argc; i++) {\n>> +             const char *commit_id = xstrfmt(\"%s^{commit}\", argv[i]);\n>> +             if (!strcmp(argv[i], \"--\")) {\n>> +                     has_double_dash = 1;\n>> +                     break;\n>> +             } else if (!strcmp(argv[i], \"--no-checkout\"))\n>> +                     no_checkout = 1;\n>> +             else if (!strcmp(argv[i], \"--term-good\") ||\n>> + ...\n>> +             } else if (starts_with(argv[i], \"--\") &&\n>> +                      !one_of(argv[i], \"--term-good\", \"--term-bad\", NULL)) {\n>> +                     string_list_clear(&revs, 0);\n>> +                     string_list_clear(&states, 0);\n>> +                     die(_(\"unrecognised option: '%s'\"), argv[i]);\n>> +             } else if (get_oid(commit_id, &oid) && has_double_dash) {\n>> +                     string_list_clear(&revs, 0);\n>> +                     string_list_clear(&states, 0);\n>> +                     die(_(\"'%s' does not appear to be a valid revision\"), argv[i]);\n>> +             } else {\n>> +                     string_list_append(&revs, oid_to_hex(&oid));\n>> +             }\n>> +     }\n>\n> What I do not understand is clearing the string list \"states\" inside\n> this loop.  It may have been INIT_DUPed, but nothing in this loop\n> adds anything to it.  Because \"revs\" does get extended in the loop,\n> it is understandable if you wanted to clear it before dying, but \"if\n> you are dying anyway why bother clearing?\" is also a valid stance to\n> take.\n\nI think I should probably use return here instead of die().\n\n> The same \"perhaps want to use the 'retval' with goto 'finish:' pattern?\"\n> comment applies here, too.\n\nOkay sure could do that.\n\n>> +     pathspec_pos = i;\n>> +\n>> +     /*\n>> +      * The user ran \"git bisect start <sha1> <sha1>\", hence did not\n>> +      * explicitly specify the terms, but we are already starting to\n>> +      * set references named with the default terms, and won't be able\n>> +      * to change afterwards.\n>> +      */\n>> +     must_write_terms |= !!revs.nr;\n>> +     for (i = 0; i < revs.nr; i++) {\n>> +             if (bad_seen)\n>> +                     string_list_append(&states, terms->term_good.buf);\n>> +             else {\n>> +                     bad_seen = 1;\n>> +                     string_list_append(&states, terms->term_bad.buf);\n>> +             }\n>> +     }\n>\n> This is certainly different from the original.  We used to do one\n> \"bisect_write\" per element in revs in the loop; we no longer do that\n> and instead collect them in states list.  Each element in these two\n> lists, i.e. revs.item[i] and states.item[i], corresponds to each\n> other.\n>\n> That explains why the variable is renamed to states.  We haven't\n> seen enough to say if this behaviour change is a good idea or not.\n>\n>> +     /*\n>> +      * Verify HEAD\n>> +      */\n>> +     head = resolve_ref_unsafe(\"HEAD\", 0, sha1, &flags);\n>> +     if (!head) {\n>> +             if (get_sha1(\"HEAD\", sha1)) {\n>> +                     string_list_clear(&revs, 0);\n>> +                     string_list_clear(&states, 0);\n>> +                     die(_(\"Bad HEAD - I need a HEAD\"));\n>> +             }\n>> +     }\n>> +     if (!is_empty_or_missing_file(git_path_bisect_start())) {\n>> +             /* Reset to the rev from where we started */\n>> +             strbuf_read_file(&start_head, git_path_bisect_start(), 0);\n>> +             strbuf_trim(&start_head);\n>> +             if (!no_checkout) {\n>> +                     struct argv_array argv = ARGV_ARRAY_INIT;\n>> +                     argv_array_pushl(&argv, \"checkout\", start_head.buf,\n>> +                                      \"--\", NULL);\n>> +                     if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {\n>> +                             error(_(\"checking out '%s' failed. Try 'git \"\n>> +                                     \"bisect start <valid-branch>'.\"),\n>> +                                   start_head.buf);\n>> +                             strbuf_release(&start_head);\n>> +                             string_list_clear(&revs, 0);\n>> +                             string_list_clear(&states, 0);\n>> +                             return -1;\n>\n> The original died here, but you expect the caller to respond to a\n> negative return.  I haven't read enough to judge if that is a good\n> idea, but doesn't it make sense to do the same throughout the\n> function consistently?  I saw a few die()'s already in the command\n> line parsing loop--shouldn't they also return -1?\n\nYes they should use return rather than die().\n\n> The original has called bisect_write already when we attempt this\n> checkout and the user will see the states in the filesystem.  This\n> rewrite does not.  What effect does this behaviour change have to\n> the end-user experience?  The error message tells the end user to\n> run another \"git bisect start\" with a valid commit, and when that\n> happens, hopefully she will give us something we can check out, and\n> then we will hit the bisect_clean_state() call we see below before\n> starting to do anything meaningful, so I am guessing it won't, but\n> I just want to make sure that you thought about the ramifications\n> of the change above to delay calls to bisect_write.\n>\n>> +                     }\n>> +             }\n>> +     } else {\n>> +             if (starts_with(head, \"refs/heads/\") ||\n>> +                 !get_oid_hex(head, &oid) || ref_exists(head)) {\n>\n> This ref_exists() check is new, and I think it should not be there.\n> In the original, if .git/HEAD pointed at refs/tags/v1.0, we would\n> have diagnosed it as a strange symbolic ref.  This no longer does.\n>\n> If you wanted to make sure that the branch exists, it should have\n> been\n>\n>         if ((starts_with(head, \"refs/heads/\") && ref_exists(head)) ||\n>             !get_oid_hex(head, &oid)) {\n>\n> anyway.\n\nI forgot to consider about tags. Thanks for reminding.\n\n> Also, why do you use get_oid_hex() here?  You used get_sha1(\"HEAD\",\n> sha1) in the early part of \"Verify HEAD\" above, which seems to be\n> perfectly adequate.  That sha1 taken from get_sha1() is what you end\n> up using in the code below anyway.  If you can stick to one or the\n> other, please do so.\n\nI should use get_sha1().\n\n>> +                     /*\n>> +                      * This error message should only be triggered by\n>> +                      * cogito usage, and cogito users should understand\n>> +                      * it relates to cg-seek.\n>> +                      */\n>> +                     if (!is_empty_or_missing_file(git_path_head_name())) {\n>> +                             strbuf_release(&start_head);\n>> +                             string_list_clear(&revs, 0);\n>> +                             string_list_clear(&states, 0);\n>> +                             die(_(\"won't bisect on cg-seek'ed tree\"));\n>> +                     }\n>\n> Not to be done as part of this series, but it probably is safe to\n> retire this part by now.  Cogito has been dead for how many years?\n\nBeen around 10 years. Last update seemed around 2006. Here is the link[1].\n\n>> +                     if (starts_with(head, \"refs/heads/\")) {\n>> +                             strbuf_reset(&start_head);\n>> +                             strbuf_addstr(&start_head, head + 11);\n>\n> skip_prefix?\n\nYa sure! That's a better way to go.\n\n>> +                     }\n>> +                     else {\n>> +                             strbuf_reset(&start_head);\n>> +                             strbuf_addstr(&start_head, sha1_to_hex(sha1));\n>> +                     }\n>> +             } else {\n>> +                     strbuf_release(&start_head);\n>> +                     string_list_clear(&revs, 0);\n>> +                     string_list_clear(&states, 0);\n>> +                     die(_(\"Bad HEAD - strange symbolic ref\"));\n>> +             }\n>> +     }\n>\n> I wonder the whole thing above is better restructured to avoid\n> repeated checks of the same thing.\n>\n>         if (is it 40-hex, i.e. detached?) {\n>                 stuff it to start_head;\n>         } else if (skip_prefix(head, \"refs/heads/\", &branchname)) {\n>                 do the \"cogito\" check;\n>                 stuff it to start_head;\n>         } else {\n>                 that's a strange symbolic ref HEAD you have there;\n>         }\n\nI guess it changes the behaviour. Its a strange symbolic ref if it\ndoes not start with \"refs/heads\".\n\n>> +     /*\n>> +      * Get rid of any old bisect state.\n>> +      */\n>> +     if (bisect_clean_state()) {\n>> +             return -1;\n>> +     }\n>\n> If we are going to get a lot more code inside {} in later patches,\n> then this single \"return -1\" enclosed inside a {} pair is\n> justifiable (but in that case we'd prefer an empty line after it to\n> separate it from the next comment block).  Otherwise lose the {}.\n\nI had thought initially that I would need to keep something after\nbisect_next() conversion. But it turns out that I actually don't.\n\n>> +     /*\n>> +      * In case of mistaken revs or checkout error, or signals received,\n>> +      * \"bisect_auto_next\" below may exit or misbehave.\n>> +      * We have to trap this to be able to clean up using\n>> +      * \"bisect_clean_state\".\n>> +      */\n>\n> That explains the \"trap\" statements in the original.  Does it apply\n> to this code here?\n>\n>> +     /*\n>> +      * Write new start state\n>> +      */\n>> +     write_file(git_path_bisect_start(), \"%s\\n\", start_head.buf);\n>> +\n>> +     if (no_checkout) {\n>> +             get_oid(start_head.buf, &oid);\n>> +             if (update_ref(NULL, \"BISECT_HEAD\", oid.hash, NULL, 0,\n>> +                            UPDATE_REFS_MSG_ON_ERR)) {\n>> +                     strbuf_release(&start_head);\n>> +                     string_list_clear(&revs, 0);\n>> +                     string_list_clear(&states, 0);\n>> +                     return -1;\n>> +             }\n>> +     }\n>> +     strbuf_release(&start_head);\n>> +\n>> +     if (pathspec_pos < argc - 1)\n>> +             sq_quote_argv(&bisect_names, argv + pathspec_pos, 0);\n>> +     write_file(git_path_bisect_names(), \"%s\\n\", bisect_names.buf);\n>> +     strbuf_release(&bisect_names);\n>> +\n>> +     for (i = 0; i < states.nr; i++) {\n>> +             if (bisect_write(states.items[i].string,\n>> +                               revs.items[i].string, terms, 1)) {\n>> +                     string_list_clear(&revs, 0);\n>> +                     string_list_clear(&states, 0);\n>> +                     return -1;\n>> +             }\n>> +     }\n>\n> Hmph.  I do not particuarly see why doing this in a separate loop\n> here, instead of doing it just like in the original, i.e. inside the\n> loop we already saw, is an improvement.  It seems to me that the\n> only effect of this change is to make the code more complex by\n> forcing you to maintain (and clear) another string list \"states\" and\n> have a separate loop here.\n>\n> Unless there is a reason why delaying calls to bisect_write() is a\n> good thing and I am not seeing it, that is.\n>\n>> diff --git a/git-bisect.sh b/git-bisect.sh\n>> index d6c8b5a..f0896b3 100755\n>> --- a/git-bisect.sh\n>> +++ b/git-bisect.sh\n>> @@ -71,122 +71,7 @@ bisect_autostart() {\n>>  }\n>>\n>>  bisect_start() {\n>> -...\n>> +     git bisect--helper --bisect-start $@ || exit\n>>  ...\n>> +     get_terms\n>\n> Understandable.  As the handling of the terms is done in the helper,\n> you need to read the terms it left in the filesystem.  OK.\n>\n>>       bisect_auto_next\n\n\nRegards,\nPranit Bauva\n"},{"id":"300355","messageId":"CAFZEwPMWjyEzV7WsMynTOBhkgAT14eyoHdEmauAU8npq8mu0gg@mail.gmail.com","threadId":"43909","inReplyTo":"xmqqbn0fdt9e.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v14 21/27] bisect--helper: `bisect_log` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-27T20:16:45Z","receivedAt":"2016-08-27T20:17:21Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Hey Junio,\n\nOn Sat, Aug 27, 2016 at 4:37 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Pranit Bauva <pranit.bauva@gmail.com> writes:\n>\n>> +static int bisect_log(void)\n>> +{\n>> +     struct strbuf buf = STRBUF_INIT;\n>> +\n>> +     if (strbuf_read_file(&buf, git_path_bisect_log(), 256) < 0) {\n>> +             strbuf_release(&buf);\n>> +             return error(_(\"We are not bisecting.\\n\"));\n>> +     }\n>> +\n>> +     printf(\"%s\", buf.buf);\n>> +     strbuf_release(&buf);\n>> +\n>> +     return 0;\n>> +}\n>\n> Hmph, is it really necessary to slurp everything in a strbuf before\n> sending it out to the standard output?  Wouldn't it be sufficient to\n> open a file descriptor for reading on the log file and then hand it\n> over to copy.c::copy_fd()?\n\nThat is actually much better. Thanks!\n\nRegards,\nPranit Bauva\n"},{"id":"300356","messageId":"xmqqzinyc4s6.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"CAFZEwPMotQ1k0EZN-buEt9MhJUKhXLS8eB5zV5A3Qr-j=DEwfQ@mail.gmail.com","subject":"Re: [PATCH v14 13/27] bisect--helper: `bisect_start` shell function partially in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-27T20:53:29Z","receivedAt":"2016-08-27T20:53:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n>> I wonder the whole thing above is better restructured to avoid\n>> repeated checks of the same thing.\n>>\n>>         if (is it 40-hex, i.e. detached?) {\n>>                 stuff it to start_head;\n>>         } else if (skip_prefix(head, \"refs/heads/\", &branchname)) {\n>>                 do the \"cogito\" check;\n>>                 stuff it to start_head;\n>>         } else {\n>>                 that's a strange symbolic ref HEAD you have there;\n>>         }\n>\n> I guess it changes the behaviour. Its a strange symbolic ref if it\n> does not start with \"refs/heads\".\n\nI did not think my suggestion would change the behaviour at all.  It\nwould change the code structure a bit to make it more readable, though.\n"},{"id":"300357","messageId":"xmqqtwe5di02.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"CAFZEwPMcUf-Tm_ijJbEG1Bh7F+7ML2fw6Vw2Gt94B9gyoGL1FQ@mail.gmail.com","subject":"Re: [PATCH v14 09/27] bisect--helper: `bisect_write` shell function in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-27T21:22:37Z","receivedAt":"2016-08-27T21:22:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n>>> +struct bisect_terms {\n>>> +     struct strbuf term_good;\n>>> +     struct strbuf term_bad;\n>>> +};\n>>\n>> I think \"struct strbuf\" is overrated.  ...\n>> I think you can just say \"const char *\" in this case.\n>\n> Using struct strbuf is not really overrated but in fact required. But\n\nNothing is required.\n\nI can make your life easier by requiring you to never use struct\nstrbuf as a structure field type, though.  You will almost never\nneed it unless you are building something exotic anyway.\n\nStep back and think what \"strbuf\" is good for.  It holds a pointer\nto a piece of memory the field owns, over-allocates and knows the\nsize of allocation and usage.  That is good if you need to\n\n (1) frequently find out the length of the string; without a\n     separate .len member you would have to run strlen().\n\n (2) incrementally add to the string in-place; as it overallocates,\n     appending to the string would not have to involve realloc()\n     every time and the cost of it is amortized.\n\n (3) make complex operations like splicing another string in,\n     trimming substring out, etc.\n\nYou need to do none of the above to these fields.  term.term_good is\neither taken from an argv[] element, or you read from a line from a\nfile and set it.  You may do some trivial computation and set it to\nthe result, like \"the other field uses 'old', so this one need to be\nset to 'new'\".  The user of the field either has the string and sets\nit there, or reads the field's value as a whole string.  No string\nmanipulation in the field in-place is needed.\n\n> yes, for this patch it might seem as overrated. In the shell code\n> initally TERM_GOOD is set to \"good\" while TERM_BAD is set to \"bad\".\n> Now there are a lot of instances (one of which is bisect_start()\n> function) where this can change. So if we keep it as \"const char *\",\n> it would be right to change the value of it after wards. And we cannot\n> keep it as \"char []\" because we don't know its size before hand.\n\nYou are not making sense.  Nobody would suggest to use a fixed-size\nchar array in this structure.  That wouldn't even work in the case\nwhere you are stuffing what comes in an argv[] element in there,\ne.g.\n\n    terms.term_good = argv[3];\n\nAnd you can of course support changing the value of the field\nwithout using strbuf.  Just update the pointer to point at the piece\nof memory that holds the new value.\n\nIn short, I do not see any good reason why the term_good field has\nto be anything other than \"char *term_good\" or \"const char *term_good\".\n\nNow, what you need to consider choosing between the two depends on\nwhere these strings can come from.  If they are known to be always\nunchanging between the time you set it til the end of the program\n(e.g. using an element in argv[]), you can just assign without\nmaking any copy and you can use \"const char *term_good\".  All other\ncases, the structure needs to take the ownership, and you would need\nto make a copy if you don't have the ownership, e.g.\n\n\tterms.term_good = xstrdup(argv[3]);\n\nYou may be reading from a file, a line at a time and you may have a\nline's content in a strbuf.  You do not (yet) own the buffer after\nreading it, e.g.\n\n\tstrbuf_getline(&buf, fp);\n\tterms.term_good = strbuf_detach(&buf, NULL);\n\nOf course, if you need to take ownership of the memory, you would\nneed to free(3) it as needed, which means the pattern to set the\nfield would become\n\n\tfree(terms.term_good);\n        terms.term_good = ... some new value ...;\n\nUsing strbuf as a local variable is good.  It gives a higher level\nof abstraction when you are actually performing string operations.\nIn most applications, however, a field in a struct is where the\nresult of a step of computation is kept, not a scratch-pad to\nperform steps of computation in.  When you are ready to update the\nvalue of a field, you _have_ a completed string, and you can just\nuse \"char *\" field to point at it.  There is no need for strbuf in\nthe field.\n\nDon't look at the data structure used in trailer.[ch] as a model; it\nis an example of a terribly bad implementation taste, a pattern that\nshould not be followed.  Print it, not read it and burn it as a good\nsymbolic gesture.\n\n\n"},{"id":"300464","messageId":"xmqqpoorcxnd.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"CAFZEwPMBy0Ovcq-pUJkhoLiVF+uvm5fC0PD0RGPKobZ83Ciy3A@mail.gmail.com","subject":"Re: [PATCH v14 07/27] bisect--helper: `bisect_reset` shell function in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-29T17:06:46Z","receivedAt":"2016-08-29T17:07:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n>> with the original\n>>\n>>     case $# in\n>>     0)  reset to the branch ;;\n>>     1)  reset to the commit ;;\n>>     *)  give usage and die ;;\n>>     esac\n>>\n>> and took the difference and reacted \"ah, excess parameters are not\n>> diagnosed in this function\".\n>>\n>> Your caller does complain about excess parameters without giving\n>> usage, and that is what I missed.\n>>\n>> I am not sure if you intended to change the behaviour in this case\n>> to avoid giving the usage string; I tend to think it is a good\n>> change, but I didn't see it mentioned in the proposed commit log,\n>> which also contributed to my not noticing the test in the caller.\n>\n> I could include this in the commit message.\n\nNah, it was something anybody could notice with 2 more minutes of\nreading and pondering from the patch text alone.  Not worth spending\nmore time on the log message on this one.\n\nThanks.\n"},{"id":"300465","messageId":"xmqqk2ezcx96.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"CAFZEwPNTkgbFz-tcnLiaW9qvRSUoHgeNMzjnCjx7EwMHG71Niw@mail.gmail.com","subject":"Re: [PATCH v14 12/27] bisect--helper: `get_terms` & `bisect_terms` shell function in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-29T17:15:17Z","receivedAt":"2016-08-29T17:15:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n>>> +static int bisect_terms(struct bisect_terms *terms, const char **argv, int argc)\n>>> +{\n>>> +     int i;\n>>> +\n>>> +     if (get_terms(terms)) {\n>>> +             fprintf(stderr, _(\"no terms defined\\n\"));\n>>> +             return -1;\n>>> +     }\n>>> +     if (argc == 0) {\n>>> +             printf(_(\"Your current terms are %s for the old state\\nand \"\n>>> +                    \"%s for the new state.\\n\"), terms->term_good.buf,\n>>> +                    terms->term_bad.buf);\n>>> +             return 0;\n>>> +     }\n>>> +\n>>> +     for (i = 0; i < argc; i++) {\n>>> +             if (!strcmp(argv[i], \"--term-good\"))\n>>> +                     printf(\"%s\\n\", terms->term_good.buf);\n>>> +             else if (!strcmp(argv[i], \"--term-bad\"))\n>>> +                     printf(\"%s\\n\", terms->term_bad.buf);\n>>> +             else\n>>> +                     printf(_(\"invalid argument %s for 'git bisect \"\n>>> +                               \"terms'.\\nSupported options are: \"\n>>> +                               \"--term-good|--term-old and \"\n>>> +                               \"--term-bad|--term-new.\"), argv[i]);\n>>> +     }\n>>\n>> The original took only one and gave one answer (and errored out when\n>> the user asked for more), but this one loops.  I can see either way\n>> is OK and do not think of a good reason to favor one over the other;\n>> unless there is a strong reason why you need this extended behaviour\n>> that allows users to ask multiple questions, I'd say we should keep\n>> the original behaviour.\n>\n> True! I can just use return error() instead of printf. Also I noticed\n> that this is printing to stdout while the original printed it to\n> stderr. Thanks!\n\nThe original you removed because the above can take it over is this\nin your patch.\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\nThe fprintf() that says \"no terms defined\" can be made error().  The\n\"invalid argument\" message used to be die in the original, and\nshould be sent to the standard error stream as you noticed.\n\nBut a bigger difference is that the original made sure that the\ncaller asked one question at a time.  \"terms --term-good --term-bad\"\nwas responded with a \"usage\".  That is no longer true in the\nrewrite.\n\n"},{"id":"300466","messageId":"xmqqfupncx5s.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"CAFZEwPP2j-+C=J-hiWEiW4wa=Yso27-M-QUABCTyd4WYieeezw@mail.gmail.com","subject":"Re: [PATCH v14 08/27] bisect--helper: `is_expected_rev` & `check_expected_revs` shell function in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-29T17:17:19Z","receivedAt":"2016-08-29T17:17:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n> Hey Junio,\n>\n> On Thu, Aug 25, 2016 at 3:43 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Pranit Bauva <pranit.bauva@gmail.com> writes:\n>>\n>>> +static int is_expected_rev(const char *expected_hex)\n>>> +{\n>>> +     struct strbuf actual_hex = STRBUF_INIT;\n>>> +     int res = 0;\n>>> +     if (strbuf_read_file(&actual_hex, git_path_bisect_expected_rev(), 0) >= 0) {\n>>> +             strbuf_trim(&actual_hex);\n>>> +             res = !strcmp(actual_hex.buf, expected_hex);\n>>\n>> If it is known to have 40-hex:\n>>\n>>  (1) accepting \">= 0\" seems way too lenient.  You only expect a\n>>      41-byte file (or 42 if somebody would write CRLF, but I do not\n>>      think anybody other than yourself is expected to write into\n>>      this file, and you do not write CRLF yourself);\n>>\n>>  (2) strbuf_trim() is overly loose.  You only want to trim the\n>>      terimnating LF and it is an error to have other trailing\n>>      whitespaces.\n>>\n>> I think the latter is not a new problem and it is OK to leave it\n>> as-is; limiting (1) to >= 40 may still be a good change, though,\n>> because it makes the intention of the code clearer.\n>\n> I can do the first change. Since this wasn't present in the shell\n> code, I will also mention it in the commit message.\n\nThere is no need for that, as that was present in the original.  The\noriginal compared the string with something that is known to be\n40-hex, so anything shorter than 40 wouldn't have matched.\n\nIt is merely a trivial and obvious optimization to do that in C\nrewrite.\n"},{"id":"300538","messageId":"CAFZEwPMz4n35x-g3cxM4KaADRJNmYmZBnwsDZD1wiiFPHJebew@mail.gmail.com","threadId":"43909","inReplyTo":"xmqqtwe5di02.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v14 09/27] bisect--helper: `bisect_write` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-30T06:42:46Z","receivedAt":"2016-08-30T06:42:54Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Hey Junio,\n\nOn Sun, Aug 28, 2016 at 2:52 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Pranit Bauva <pranit.bauva@gmail.com> writes:\n>\n> >>> +struct bisect_terms {\n> >>> +     struct strbuf term_good;\n> >>> +     struct strbuf term_bad;\n> >>> +};\n> >>\n> >> I think \"struct strbuf\" is overrated.  ...\n> >> I think you can just say \"const char *\" in this case.\n> >\n> > Using struct strbuf is not really overrated but in fact required. But\n>\n> Nothing is required.\n>\n> I can make your life easier by requiring you to never use struct\n> strbuf as a structure field type, though.  You will almost never\n> need it unless you are building something exotic anyway.\n>\n> Step back and think what \"strbuf\" is good for.  It holds a pointer\n> to a piece of memory the field owns, over-allocates and knows the\n> size of allocation and usage.  That is good if you need to\n>\n>  (1) frequently find out the length of the string; without a\n>      separate .len member you would have to run strlen().\n>\n>  (2) incrementally add to the string in-place; as it overallocates,\n>      appending to the string would not have to involve realloc()\n>      every time and the cost of it is amortized.\n>\n>  (3) make complex operations like splicing another string in,\n>      trimming substring out, etc.\n>\n> You need to do none of the above to these fields.  term.term_good is\n> either taken from an argv[] element, or you read from a line from a\n> file and set it.  You may do some trivial computation and set it to\n> the result, like \"the other field uses 'old', so this one need to be\n> set to 'new'\".  The user of the field either has the string and sets\n> it there, or reads the field's value as a whole string.  No string\n> manipulation in the field in-place is needed.\n>\n> > yes, for this patch it might seem as overrated. In the shell code\n> > initally TERM_GOOD is set to \"good\" while TERM_BAD is set to \"bad\".\n> > Now there are a lot of instances (one of which is bisect_start()\n> > function) where this can change. So if we keep it as \"const char *\",\n> > it would be right to change the value of it after wards. And we cannot\n> > keep it as \"char []\" because we don't know its size before hand.\n>\n> You are not making sense.  Nobody would suggest to use a fixed-size\n> char array in this structure.  That wouldn't even work in the case\n> where you are stuffing what comes in an argv[] element in there,\n> e.g.\n>\n>     terms.term_good = argv[3];\n>\n> And you can of course support changing the value of the field\n> without using strbuf.  Just update the pointer to point at the piece\n> of memory that holds the new value.\n>\n> In short, I do not see any good reason why the term_good field has\n> to be anything other than \"char *term_good\" or \"const char *term_good\".\n>\n> Now, what you need to consider choosing between the two depends on\n> where these strings can come from.  If they are known to be always\n> unchanging between the time you set it til the end of the program\n> (e.g. using an element in argv[]), you can just assign without\n> making any copy and you can use \"const char *term_good\".  All other\n> cases, the structure needs to take the ownership, and you would need\n> to make a copy if you don't have the ownership, e.g.\n>\n>         terms.term_good = xstrdup(argv[3]);\n>\n> You may be reading from a file, a line at a time and you may have a\n> line's content in a strbuf.  You do not (yet) own the buffer after\n> reading it, e.g.\n>\n>         strbuf_getline(&buf, fp);\n>         terms.term_good = strbuf_detach(&buf, NULL);\n>\n> Of course, if you need to take ownership of the memory, you would\n> need to free(3) it as needed, which means the pattern to set the\n> field would become\n>\n>         free(terms.term_good);\n>         terms.term_good = ... some new value ...;\n>\n> Using strbuf as a local variable is good.  It gives a higher level\n> of abstraction when you are actually performing string operations.\n> In most applications, however, a field in a struct is where the\n> result of a step of computation is kept, not a scratch-pad to\n> perform steps of computation in.  When you are ready to update the\n> value of a field, you _have_ a completed string, and you can just\n> use \"char *\" field to point at it.  There is no need for strbuf in\n> the field.\n>\n> Don't look at the data structure used in trailer.[ch] as a model; it\n> is an example of a terribly bad implementation taste, a pattern that\n> should not be followed.  Print it, not read it and burn it as a good\n> symbolic gesture.\n\nThanks for explaining when to use strbuf. I am convinced that the\nthing I am aiming for can be done with the help of \"const char *\".\nThough I will have to use strbuf in get_terms() and detach the string\nbuffer from there as you have mentioned previously.\n\nRegards,\nPranit Bauva\n"},{"id":"300593","messageId":"CAFZEwPP-c00aNvDKoQFiCf_-tqrP3tAwwU6KAnswfMkjyoP3QQ@mail.gmail.com","threadId":"43909","inReplyTo":"xmqq37lsmw15.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v14 14/27] bisect--helper: `bisect_next` and `bisect_auto_next` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-30T18:25:40Z","receivedAt":"2016-08-30T18:25:47Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Hey Junio,\n\nSorry for a late replay.\n\nOn Fri, Aug 26, 2016 at 2:00 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Pranit Bauva <pranit.bauva@gmail.com> writes:\n>\n>> A lot of parts of bisect.c uses exit() and these signals are then\n>> trapped in the `bisect_start` function. Since the shell script ceases\n>> its existence it would be necessary to convert those exit() calls to\n>> return statements so that errors can be reported efficiently in C code.\n>\n> Is efficiency really an issue?  I think the real reason is that it\n> would make it impossible for the callers to handle errors, if you do\n> not convert and let the error codepaths exit().\n\nI think I put the word \"efficiently\" wrongly over here. Will omit it.\n\n>> @@ -729,7 +735,7 @@ static struct commit **get_bad_and_good_commits(int *rev_nr)\n>>       return rev;\n>>  }\n>>\n>> -static void handle_bad_merge_base(void)\n>> +static int handle_bad_merge_base(void)\n>>  {\n>>       if (is_expected_rev(current_bad_oid)) {\n>>               char *bad_hex = oid_to_hex(current_bad_oid);\n>> @@ -750,17 +756,18 @@ static void handle_bad_merge_base(void)\n>>                               \"between %s and [%s].\\n\"),\n>>                               bad_hex, term_bad, term_good, bad_hex, good_hex);\n>>               }\n>> -             exit(3);\n>> +             return 3;\n>>       }\n>>\n>>       fprintf(stderr, _(\"Some %s revs are not ancestor of the %s rev.\\n\"\n>>               \"git bisect cannot work properly in this case.\\n\"\n>>               \"Maybe you mistook %s and %s revs?\\n\"),\n>>               term_good, term_bad, term_good, term_bad);\n>> -     exit(1);\n>> +     bisect_clean_state();\n>> +     return 1;\n>\n> What is the logic behind this function sometimes clean the state,\n> and some other times do not, when it makes an error-return?  We see\n> above that \"return 3\" codepath leaves the state behind.\n>\n> Either you forgot a necessary clean_state in \"return 3\" codepath,\n> or you forgot to document why the distinction exists in the in-code\n> comment for the function.  I cannot tell which, but I am leaning\n> towards guessing that it is the former.\n\nThis is a very tricky one. I have purposely not included this after a\nlot of testing. I have hand tested with the original git and with this\nbranch. The reason why anyone wouldn't be able to catch this is\nbecause its not covered in the test suite. I am including a patch with\nthis as an attachment (because I am behind a proxy right now but don't\nworry I will include this as a commit in the next series). The\noriginal behaviour of git does not clean the bisect state when this\nsituation occurs. On another note which you might have missed that\nbisect_clean_state() is purposely put before return 1 which is covered\nby the test suite. You can try removing it and see that there is a\nbroken tes. tI was thinking of including the tests after the whole\nconversion but now I think including this before will make the\nconversion more easier for review.\n\n>> -static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)\n>> +static int check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)\n>>  {\n>>       char *filename = git_pathdup(\"BISECT_ANCESTORS_OK\");\n>>       struct stat st;\n>> -     int fd;\n>> +     int fd, res = 0;\n>>\n>>       if (!current_bad_oid)\n>>               die(_(\"a %s revision is needed\"), term_bad);\n>\n> Can you let it die yere?\n\nNot really. I should change it to return error().\n\n>> @@ -873,8 +890,11 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout)\n>>                             filename);\n>>       else\n>>               close(fd);\n>> +\n>> +     return 0;\n>>   done:\n>>       free(filename);\n>> +     return 0;\n>>  }\n>\n> Who owns \"filename\"?  The first \"return 0\" leaves it unfreed, and\n> when \"goto done\" is done, it is freed.\n>\n> The above two may indicate that \"perhaps 'retval + goto finish'\n> pattern?\" is a really relevant suggestion for the earlier steps in\n> this series.\n\nYes.\n\n>>       if (!all) {\n>>               fprintf(stderr, _(\"No testable commit found.\\n\"\n>>                       \"Maybe you started with bad path parameters?\\n\"));\n>> -             exit(4);\n>> +             return 4;\n>>       }\n>>\n>>       bisect_rev = revs.commits->item->object.oid.hash;\n>>\n>>       if (!hashcmp(bisect_rev, current_bad_oid->hash)) {\n>> -             exit_if_skipped_commits(tried, current_bad_oid);\n>> +             res = exit_if_skipped_commits(tried, current_bad_oid);\n>> +             if (res)\n>> +                     return res;\n>> +\n>>               printf(\"%s is the first %s commit\\n\", sha1_to_hex(bisect_rev),\n>>                       term_bad);\n>>               show_diff_tree(prefix, revs.commits->item);\n>>               /* This means the bisection process succeeded. */\n>> -             exit(10);\n>> +             return 10;\n>>       }\n>>\n>>       nr = all - reaches - 1;\n>> @@ -1005,7 +1033,11 @@ int bisect_next_all(const char *prefix, int no_checkout)\n>>                 \"Bisecting: %d revisions left to test after this %s\\n\",\n>>                 nr), nr, steps_msg);\n>>\n>> -     return bisect_checkout(bisect_rev, no_checkout);\n>> +     res = bisect_checkout(bisect_rev, no_checkout);\n>> +     if (res)\n>> +             bisect_clean_state();\n>> +\n>> +     return res;\n>>  }\n>\n> There were tons of \"exit_if\" that was converted to \"if (res) return\n> res\" above, instead of jumping here to cause clean_state to be\n> called.  I cannot tell if this new call to clean_state() is wrong,\n> or all the earlier \"return res\" should come here.  I am guessing the\n> latter.\n\nNo I don't think its wrong. It is advised in the comment\n    In case of mistaken revs or checkout error, or signals received,\n    \"bisect_auto_next\" below may exit or misbehave.\n    We have to trap this to be able to clean up using\n    \"bisect_clean_state\".\n\nto clean the bisection state *iff checkout fails* otherwise not.\nLuckily this is already covered by the test suite. I think what you\nmeant is that bisect_clean_state() might be covered elsewhere too then\nwhy perform cleanup here, right? bisect_clean_state() have been\ncarefully put where ever required only.\n\n>> diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c\n>> index c64996a..ef7b3a1 100644\n>> --- a/builtin/bisect--helper.c\n>> +++ b/builtin/bisect--helper.c\n>> @@ -8,6 +8,7 @@\n>>  #include \"run-command.h\"\n>>  #include \"prompt.h\"\n>>  #include \"quote.h\"\n>> +#include \"revision.h\"\n>>\n>>  static GIT_PATH_FUNC(git_path_bisect_terms, \"BISECT_TERMS\")\n>>  static GIT_PATH_FUNC(git_path_bisect_expected_rev, \"BISECT_EXPECTED_REV\")\n>> @@ -29,6 +30,8 @@ static const char * const git_bisect_helper_usage[] = {\n>>       N_(\"git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]\"),\n>>       N_(\"git bisect--helper --bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]\"\n>>                                             \"[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]\"),\n>> +     N_(\"git bisect--helper --bisect-next\"),\n>> +     N_(\"git bisect--helper --bisect-auto-next\"),\n>>       NULL\n>>  };\n>>\n>> @@ -396,6 +399,129 @@ static int bisect_terms(struct bisect_terms *terms, const char **argv, int argc)\n>>       return 0;\n>>  }\n>>\n>> +static int register_good_ref(const char *refname,\n>> +                          const struct object_id *oid, int flags,\n>> +                          void *cb_data)\n>> +{\n>> +     struct string_list *good_refs = cb_data;\n>> +     string_list_append(good_refs, oid_to_hex(oid));\n>> +     return 0;\n>> +}\n>> +\n>> +static int bisect_next(struct bisect_terms *terms, const char *prefix)\n>> +{\n>> +     int res, no_checkout;\n>> +\n>> +     /* In case of mistaken revs or checkout error, or signals received,\n>\n> That's an unbalanced comment.  You end the block with \"*/\" on its\n> own line, so you should start the block with \"/*\" on its own line.\n> There seems to be at least one more such comment in this patch but I\n> won't repeat.\n\nI shall change this.\n\n>> +      * \"bisect_auto_next\" below may exit or misbehave.\n>> +      * We have to trap this to be able to clean up using\n>> +      * \"bisect_clean_state\".\n>> +      */\n>\n> \"exit\" meaning \"call exit() to terminate the process\", or something\n> else?  If the latter, don't say \"exit\", but say \"return error\".\n\nYes I think its necessary to change \"exit\" in comments to \"return\".\nThere are other places too in which I will have to change.\n\n>> +     if (bisect_next_check(terms, terms->term_good.buf))\n>> +             return -1;\n>\n> Mental note.  The \"autostart\" in the original is gone.  Perhaps it\n> is done by next_check in this code, but we haven't seen that yet.\n\nThis will be added back again in a coming patch[1].\n\n>> +     no_checkout = !is_empty_or_missing_file(git_path_bisect_head());\n>> +\n>> +     /* Perform all bisection computation, display and checkout */\n>> +     res = bisect_next_all(prefix , no_checkout);\n>> +\n>> +     if (res == 10) {\n>> +             FILE *fp;\n>> +             unsigned char sha1[20];\n>> +             struct commit *commit;\n>> +             struct pretty_print_context pp = {0};\n>> +             struct strbuf commit_name = STRBUF_INIT;\n>> +             char *bad_ref = xstrfmt(\"refs/bisect/%s\",\n>> +                                           terms->term_bad.buf);\n>> +             read_ref(bad_ref, sha1);\n>> +             commit = lookup_commit_reference(sha1);\n>> +             format_commit_message(commit, \"%s\", &commit_name, &pp);\n>> +             fp = fopen(git_path_bisect_log(), \"a\");\n>> +             if (!fp) {\n>> +                     free(bad_ref);\n>> +                     strbuf_release(&commit_name);\n>> +                     return -1;\n>> +             }\n>> +             if (fprintf(fp, \"# first %s commit: [%s] %s\\n\",\n>> +                         terms->term_bad.buf, sha1_to_hex(sha1),\n>> +                         commit_name.buf) < 1){\n>> +                     free(bad_ref);\n>> +                     strbuf_release(&commit_name);\n>> +                     fclose(fp);\n>> +                     return -1;\n>> +             }\n>> +             free(bad_ref);\n>> +             strbuf_release(&commit_name);\n>> +             fclose(fp);\n>> +             return 0;\n>\n> Doesn't it bother you that you have to write free(bad_ref)...fclose(fp)\n> repeatedly?\n\nMy mind was more involved in the actual conversion and that was the\nmain part bothering me. I did all the \"clean up\" stuff after I did the\nactual conversion. And since I was extremely happy after the porting\nhappened, the \"cleanup stuff\" didn't bother me much.\n\n>> +     }\n>> +     else if (res == 2) {\n>> +             FILE *fp;\n>> +             struct rev_info revs;\n>> +             struct argv_array rev_argv = ARGV_ARRAY_INIT;\n>> +             struct string_list good_revs = STRING_LIST_INIT_DUP;\n>> +             struct pretty_print_context pp = {0};\n>> +             struct commit *commit;\n>> +             char *term_good = xstrfmt(\"%s-*\", terms->term_good.buf);\n>> +             int i;\n>> +\n>> +             fp = fopen(git_path_bisect_log(), \"a\");\n>> +             if (!fp) {\n>> +                     free(term_good);\n>> +                     return -1;\n>> +             }\n>> +             if (fprintf(fp, \"# only skipped commits left to test\\n\") < 1) {\n>> +                     free(term_good);\n>> +                     fclose(fp);\n>> +                     return -1;\n>> +             }\n>> +             for_each_glob_ref_in(register_good_ref, term_good,\n>> +                                  \"refs/bisect/\", (void *) &good_revs);\n>> +\n>> +             free(term_good);\n>\n> Doesn't it bother you that you have to write free(term_good) repeatedly?\n>\n>> +             argv_array_pushl(&rev_argv, \"skipped_commits\", \"refs/bisect/bad\", \"--not\", NULL);\n>> +             for (i = 0; i < good_revs.nr; i++)\n>> +                     argv_array_push(&rev_argv, good_revs.items[i].string);\n>> +\n>> +             /* It is important to reset the flags used by revision walks\n>> +              * as the previous call to bisect_next_all() in turn\n>> +              * setups a revision walk.\n>> +              */\n>> +             reset_revision_walk();\n>> +             init_revisions(&revs, NULL);\n>> +             rev_argv.argc = setup_revisions(rev_argv.argc, rev_argv.argv, &revs, NULL);\n>> +             argv_array_clear(&rev_argv);\n>> +             string_list_clear(&good_revs, 0);\n>\n> Are you sure that the revision walking machinery is prepared to see\n> the argv[] and elements in it you have given to setup_revisions()\n> gets cleared before it starts doing the real work in\n> prepare_revision_walk()?  I am reasonably sure that the machinery\n> borrows strings like pathspec elements from the caller and expects\n> them to stay during revision traversal.\n\nI have extremely little understanding of revision walking. All what I\nknow about revision walking is what's covered in\nDocumentation/technical/api-revision-walking.txt . There it is\nmentioned that for multiple revision walking its necessary to reset.\nWhat's happening is that there are multiple calls for revision\nwalking. Now bisect_next() in itself calls for revision walking two\ntimes (the first one being with bisect_next_all and the next one\nconditionally with skip).  This is also the reason why I included a\nreset_revision_walk() in bisect.c too in this patch. Before what used\nto happen is that when git plumbing commands were called there was no\nprevious need for resetting the revision walk.  Now that only a C code\nexists after bisect_replay() conversion (I faced a problem in a\nfuturistic patch and thought it would be better to cover it up here),\nthere would be multiple calls to bisect_next(). Previously it wasn't a\nproblem because bisect_next_all() was a subcommand called from shell\nscript and for \"skip\" it was git-rev-list which did revision walking\nas a separate thing. I didn't do reset previously and because of this\nI used to get a NULL value in the revs.commits . It would be really\nhelpful if you could look more into it.\n\n> You seem to have acquired a habit of freeing and clearing things\n> early, which is bad.  Instead, make it a habit of free/clear at the\n> end, and make sure all error paths go through that central freeing\n> site.  That tends to future-proof your code better from leaking even\n> when later other people change it.\n\nSure!\n\n>> +             if (prepare_revision_walk(&revs)) {\n>> +                     die(_(\"revision walk setup failed\\n\"));\n>> +             }\n>\n> This one is still allowed to die, without clean_state?\n\nI couldn't really test this part of code because I don't know how to\nmake this call fail. And this isn't covered by the test suite either.\nBTW, here also it should be return error().\n\n>> +             while ((commit = get_revision(&revs)) != NULL) {\n>> +                     struct strbuf commit_name = STRBUF_INIT;\n>> +                     format_commit_message(commit, \"%s\",\n>> +                                           &commit_name, &pp);\n>> +                     fprintf(fp, \"# possible first %s commit: \"\n>> +                                 \"[%s] %s\\n\", terms->term_bad.buf,\n>> +                                 oid_to_hex(&commit->object.oid),\n>> +                                 commit_name.buf);\n>> +                     strbuf_release(&commit_name);\n>> +             }\n>> +\n>> +             fclose(fp);\n>> +             return res;\n>> +     }\n>> +\n>> +     return res;\n>> +}\n>\n>> @@ -415,47 +541,67 @@ static int bisect_start(struct bisect_terms *terms, int no_checkout,\n>>               no_checkout = 1;\n>>\n>>       for (i = 0; i < argc; i++) {\n>> -             if (!strcmp(argv[i], \"--\")) {\n>> +             const char *arg;\n>> +             if (starts_with(argv[i], \"'\"))\n>> +                     arg = sq_dequote(xstrdup(argv[i]));\n>> +             else\n>> +                     arg = argv[i];\n>> +             if (!strcmp(arg, \"--\")) {\n>>                       has_double_dash = 1;\n>>                       break;\n>>               }\n>>       }\n>\n> This is really bad; you are blindly assuming that anything that\n> begins with \" ' \" begins with \" ' \" because \"git-bisect.sh\" sq-quoted\n> and it never directly came from the command line that _wanted_ to\n> give you something that begins with a \" ' \".\n>\n> I suspect that you should be able to dequote on the calling script\n> side.  Then all these ugliness would disappear.\n\nI had an unsuccessful attempt at it. Though this ugliness is removed\nin the patch[2]. This is specifically because of the line in\nbisect_replay() shell function which calls bisect_start().\n\n>>       for (i = 0; i < argc; i++) {\n>> -             const char *commit_id = xstrfmt(\"%s^{commit}\", argv[i]);\n>> +             const char *arg, *commit_id;\n>> +             if (starts_with(argv[i], \"'\"))\n>> +                     arg = sq_dequote(xstrdup(argv[i]));\n>> +             else\n>> +                     arg = argv[i];\n>\n> Likewise.\n>\n>> +             commit_id = xstrfmt(\"%s^{commit}\", arg);\n>\n> In any case, I think a separate \"const char *arg\" that is an alias\n> to argv[i] in the loop is a very good idea to do from the very\n> beginning (i.e. should be done in a much much earlier patch in this\n> series).\n\nI will do it in the earlier patch.\n\n[1]: http://public-inbox.org/git/01020156b73fe6d7-8b80c663-7c77-469e-811f-40200ec6dbb1-000000@eu-west-1.amazonses.com/\n[2]: https://public-inbox.org/git/01020156b73fe6e4-d45cf1f7-03a3-4566-95d1-73788c5ab2f9-000000@eu-west-1.amazonses.com/\n\nRegards,\nPranit Bauva\n"},{"id":"300596","messageId":"CAFZEwPOt6aXA+URVzH8_=U+D=sMN=+Brp+15T=RWA=+D09fP9Q@mail.gmail.com","threadId":"43909","inReplyTo":"CAFZEwPP-c00aNvDKoQFiCf_-tqrP3tAwwU6KAnswfMkjyoP3QQ@mail.gmail.com","subject":"Re: [PATCH v14 14/27] bisect--helper: `bisect_next` and `bisect_auto_next` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-30T18:44:25Z","receivedAt":"2016-08-30T18:44:32Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Hey Junio,\n\nOn Tue, Aug 30, 2016 at 11:55 PM, Pranit Bauva <pranit.bauva@gmail.com> wrote:\n>\n>>> @@ -729,7 +735,7 @@ static struct commit **get_bad_and_good_commits(int *rev_nr)\n>>>       return rev;\n>>>  }\n>>>\n>>> -static void handle_bad_merge_base(void)\n>>> +static int handle_bad_merge_base(void)\n>>>  {\n>>>       if (is_expected_rev(current_bad_oid)) {\n>>>               char *bad_hex = oid_to_hex(current_bad_oid);\n>>> @@ -750,17 +756,18 @@ static void handle_bad_merge_base(void)\n>>>                               \"between %s and [%s].\\n\"),\n>>>                               bad_hex, term_bad, term_good, bad_hex, good_hex);\n>>>               }\n>>> -             exit(3);\n>>> +             return 3;\n>>>       }\n>>>\n>>>       fprintf(stderr, _(\"Some %s revs are not ancestor of the %s rev.\\n\"\n>>>               \"git bisect cannot work properly in this case.\\n\"\n>>>               \"Maybe you mistook %s and %s revs?\\n\"),\n>>>               term_good, term_bad, term_good, term_bad);\n>>> -     exit(1);\n>>> +     bisect_clean_state();\n>>> +     return 1;\n>>\n>> What is the logic behind this function sometimes clean the state,\n>> and some other times do not, when it makes an error-return?  We see\n>> above that \"return 3\" codepath leaves the state behind.\n>>\n>> Either you forgot a necessary clean_state in \"return 3\" codepath,\n>> or you forgot to document why the distinction exists in the in-code\n>> comment for the function.  I cannot tell which, but I am leaning\n>> towards guessing that it is the former.\n>\n> This is a very tricky one. I have purposely not included this after a\n> lot of testing. I have hand tested with the original git and with this\n> branch. The reason why anyone wouldn't be able to catch this is\n> because its not covered in the test suite. I am including a patch with\n> this as an attachment (because I am behind a proxy right now but don't\n> worry I will include this as a commit in the next series). The\n> original behaviour of git does not clean the bisect state when this\n> situation occurs. On another note which you might have missed that\n> bisect_clean_state() is purposely put before return 1 which is covered\n> by the test suite. You can try removing it and see that there is a\n> broken tes. tI was thinking of including the tests after the whole\n> conversion but now I think including this before will make the\n> conversion more easier for review.\n\nThe patch which I included as an attachment before will fail for\ndifferent reasons if you apply it on master branch. To test it on\nmaster branch use the current attachment. Again sorry I couldn't\ninclude this in the email itself.\n\nRegards,\nPranit Bauva\n"},{"id":"300600","messageId":"xmqqvayi2grg.fsf@gitster.mtv.corp.google.com","threadId":"43909","inReplyTo":"CAFZEwPP-c00aNvDKoQFiCf_-tqrP3tAwwU6KAnswfMkjyoP3QQ@mail.gmail.com","subject":"Re: [PATCH v14 14/27] bisect--helper: `bisect_next` and `bisect_auto_next` shell function in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-08-30T19:33:55Z","receivedAt":"2016-08-30T19:34:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pranit Bauva <pranit.bauva@gmail.com> writes:\n\n> This is a very tricky one. I have purposely not included this after a\n> lot of testing. I have hand tested with the original git and with this\n> branch. The reason why anyone wouldn't be able to catch this is\n> because its not covered in the test suite. I am including a patch with\n> this as an attachment (because I am behind a proxy right now but don't\n> worry I will include this as a commit in the next series). The\n> original behaviour of git does not clean the bisect state when this\n> situation occurs.\n\n\"We sometimes clean and we sometimes don't and this follows the\noriginal\" may be a valid justification but it is not a very useful\nexplanation.  The real issue is if not cleaning is intended (and if\nso why; otherwise, if it is clear that it is simply forgotten, we\ncan just fix it in the series as a follow-up step).\n\nIf not cleaning in some cases (but not others) is the right thing,\nat least there needs an in-code comment to warn others against\n\"fixing\" the lack of cleanups (e.g. \"don't clean state here, because\nthe caller still wants to see what state we were for this and that\nreason\").\n\n>>> +     if (bisect_next_check(terms, terms->term_good.buf))\n>>> +             return -1;\n>>\n>> Mental note.  The \"autostart\" in the original is gone.  Perhaps it\n>> is done by next_check in this code, but we haven't seen that yet.\n>\n> This will be added back again in a coming patch[1].\n\nIn other words, this series is broken at this step and the breakage\nstay with the codebase until a later step?\n\nI do not know if reordering the patches in the series is enough to\nfix that, or if it is even worth to avoid such a temporary breakage.\nIt depends on how serious the circularity is, but I would understand\nif it is too hard and not worth the effort (I think in a very early\nreview round some people advised against the bottom-up rewrite\nbecause they anticipated this exact reason).  At least the omission\n(and later resurrection) needs to be mentioned in the log so that\npeople understand what is going on when they later need to bisect.\n\nThanks.\n"},{"id":"300601","messageId":"CAFZEwPOb2HhULRyPqdnZd-_ADgnSeZsdikgG4odvD_svWMJgCQ@mail.gmail.com","threadId":"43909","inReplyTo":"xmqqvayi2grg.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v14 14/27] bisect--helper: `bisect_next` and `bisect_auto_next` shell function in C","fromName":"Pranit Bauva","fromEmail":"pranit.bauva@gmail.com","sentAt":"2016-08-30T20:17:25Z","receivedAt":"2016-08-30T20:17:46Z","isPatch":true,"sender":{"key":"pranit.bauva@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2959938?v=4"},"body":"Hey Junio,\n\nOn Wed, Aug 31, 2016 at 1:03 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Pranit Bauva <pranit.bauva@gmail.com> writes:\n>\n>> This is a very tricky one. I have purposely not included this after a\n>> lot of testing. I have hand tested with the original git and with this\n>> branch. The reason why anyone wouldn't be able to catch this is\n>> because its not covered in the test suite. I am including a patch with\n>> this as an attachment (because I am behind a proxy right now but don't\n>> worry I will include this as a commit in the next series). The\n>> original behaviour of git does not clean the bisect state when this\n>> situation occurs.\n>\n> \"We sometimes clean and we sometimes don't and this follows the\n> original\" may be a valid justification but it is not a very useful\n> explanation.  The real issue is if not cleaning is intended (and if\n> so why; otherwise, if it is clear that it is simply forgotten, we\n> can just fix it in the series as a follow-up step).\n\nI think we do want to recover from this \"bad merge base\" state and for\nthat not cleaning up is essential. The original behaviour of git seems\nnatural to me.\n\n> If not cleaning in some cases (but not others) is the right thing,\n> at least there needs an in-code comment to warn others against\n> \"fixing\" the lack of cleanups (e.g. \"don't clean state here, because\n> the caller still wants to see what state we were for this and that\n> reason\").\n\nI will mention it in the comments.\n\n>>>> +     if (bisect_next_check(terms, terms->term_good.buf))\n>>>> +             return -1;\n>>>\n>>> Mental note.  The \"autostart\" in the original is gone.  Perhaps it\n>>> is done by next_check in this code, but we haven't seen that yet.\n>>\n>> This will be added back again in a coming patch[1].\n>\n> In other words, this series is broken at this step and the breakage\n> stay with the codebase until a later step?\n\nBroken though it passes the test suite.\n\n> I do not know if reordering the patches in the series is enough to\n> fix that, or if it is even worth to avoid such a temporary breakage.\n> It depends on how serious the circularity is, but I would understand\n> if it is too hard and not worth the effort (I think in a very early\n> review round some people advised against the bottom-up rewrite\n> because they anticipated this exact reason).  At least the omission\n> (and later resurrection) needs to be mentioned in the log so that\n> people understand what is going on when they later need to bisect.\n\nbisect_autostart() call from bisect_next() was introduced in the\nearliest version of git-bisect in the commit 8cc6a0831 but it isn't\nreally a very big deal and I think it would be OK to skip it for a\nvery little while as any which ways the series in the end would fix\nit. It is important to mention this in the commit message and I will\ndo it.\n\nRegards,\nPranit Bauva\n"}]}