{"thread":{"id":"65833","subject":"[PATCH] help: prompt user to run corrected command on typo","startedAt":"2026-06-18T14:26:15Z","lastAt":"2026-06-23T16:09:41Z","messageCount":8,"participants":["calicomills","Justin Tobler","Jishnu C K","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"545851","messageId":"6a340006.60da1a74.20db39.8f57@mx.google.com","threadId":"65833","inReplyTo":null,"subject":"[PATCH] help: prompt user to run corrected command on typo","fromName":"calicomills","fromEmail":"jishnuck26@gmail.com","sentAt":"2026-06-18T14:26:14Z","receivedAt":"2026-06-18T14:26:15Z","isPatch":true,"body":"From 0dc9e5c4593611b75e7003e8fdbea9370524c05b Mon Sep 17 00:00:00 2001\nFrom: calicomills <jishnuck26@gmail.com>\nDate: Thu, 18 Jun 2026 19:47:12 +0530\nSubject: [PATCH] help: prompt user to run corrected command on typo\n\nWhen a user mistypes a git command and there is exactly one similar\ncommand, git currently prints a suggestion but exits, requiring the\nuser to retype the corrected command manually.\n\nInstead, when stdin and stderr are both connected to a terminal and\nthere is a single best match, prompt the user with:\n\n  Did you mean 'git checkout neo'? [y/N]\n\nThe full corrected invocation (command + original arguments) is shown\nin the prompt so the user knows exactly what will run. Answering 'y'\nre-executes git with the corrected command and all original arguments.\nAnswering anything else exits as before.\n\nWhen there are multiple similarly-named commands, or when running\nnon-interactively (scripts, pipes), the original behaviour of printing\nthe suggestion list and exiting is preserved.\n\nThe help_unknown_cmd() signature is updated to accept the full args\nvector so the prompt can include the original arguments alongside the\ncorrected command name.\n\nAdd tests to t9003 covering:\n- non-interactive single match: falls back to suggestion list\n- non-interactive multiple matches: falls back to suggestion list\n- interactive single match, 'y': corrected command runs (TTY prereq)\n- interactive single match, 'n': exits cleanly (TTY prereq)\n\nSigned-off-by: calicomills <jishnuck26@gmail.com>\n---\n builtin/help.c              |  2 +-\n git.c                       |  2 +-\n help.c                      | 40 ++++++++++++++++++++++------\n help.h                      |  3 ++-\n t/t9003-help-autocorrect.sh | 53 +++++++++++++++++++++++++++++++++++++\n 5 files changed, 89 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/help.c b/builtin/help.c\nindex a140339999..b17e61ccc8 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -618,7 +618,7 @@ static char *check_git_cmd(const char *cmd)\n \t}\n \n \tif (exclude_guides)\n-\t\treturn help_unknown_cmd(cmd);\n+\t\treturn help_unknown_cmd(cmd, NULL);\n \n \treturn xstrdup(cmd);\n }\ndiff --git a/git.c b/git.c\nindex 36f08891ef..d379cc85bb 100644\n--- a/git.c\n+++ b/git.c\n@@ -994,7 +994,7 @@ int cmd_main(int argc, const char **argv)\n \t\t\texit(1);\n \t\t}\n \t\tif (!done_help) {\n-\t\t\tchar *assumed = help_unknown_cmd(cmd);\n+\t\t\tchar *assumed = help_unknown_cmd(cmd, &args);\n \t\t\tstrvec_replace(&args, 0, assumed);\n \t\t\tfree(assumed);\n \t\t\tcmd = args.v[0];\ndiff --git a/help.c b/help.c\nindex 46241492ce..30f32a7206 100644\n--- a/help.c\n+++ b/help.c\n@@ -641,7 +641,7 @@ static const char bad_interpreter_advice[] =\n \tN_(\"'%s' appears to be a git command, but we were not\\n\"\n \t\"able to execute it. Maybe git-%s is broken?\");\n \n-char *help_unknown_cmd(const char *cmd)\n+char *help_unknown_cmd(const char *cmd, const struct strvec *args)\n {\n \tstruct help_unknown_cmd_config cfg = { 0 };\n \tint i, n, best_similarity = 0;\n@@ -762,13 +762,37 @@ char *help_unknown_cmd(const char *cmd)\n \tfprintf_ln(stderr, _(\"git: '%s' is not a git command. See 'git --help'.\"), cmd);\n \n \tif (SIMILAR_ENOUGH(best_similarity)) {\n-\t\tfprintf_ln(stderr,\n-\t\t\t   Q_(\"\\nThe most similar command is\",\n-\t\t\t      \"\\nThe most similar commands are\",\n-\t\t\t   n));\n-\n-\t\tfor (i = 0; i < n; i++)\n-\t\t\tfprintf(stderr, \"\\t%s\\n\", main_cmds.names[i]->name);\n+\t\tif (n == 1 && isatty(0) && isatty(2)) {\n+\t\t\tchar *answer;\n+\t\t\tstruct strbuf msg = STRBUF_INIT;\n+\t\t\tstruct strbuf full_cmd = STRBUF_INIT;\n+\t\t\tstrbuf_addstr(&full_cmd, main_cmds.names[0]->name);\n+\t\t\tif (args) {\n+\t\t\t\tfor (size_t j = 1; j < args->nr; j++) {\n+\t\t\t\t\tstrbuf_addch(&full_cmd, ' ');\n+\t\t\t\t\tstrbuf_addstr(&full_cmd, args->v[j]);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tstrbuf_addf(&msg, _(\"\\nDid you mean 'git %s'? [y/N] \"),\n+\t\t\t\t    full_cmd.buf);\n+\t\t\tstrbuf_release(&full_cmd);\n+\t\t\tanswer = git_prompt(msg.buf, PROMPT_ECHO);\n+\t\t\tstrbuf_release(&msg);\n+\t\t\tif (starts_with(answer, \"y\") || starts_with(answer, \"Y\")) {\n+\t\t\t\tchar *assumed = xstrdup(main_cmds.names[0]->name);\n+\t\t\t\tcmdnames_release(&cfg.aliases);\n+\t\t\t\tcmdnames_release(&main_cmds);\n+\t\t\t\tcmdnames_release(&other_cmds);\n+\t\t\t\treturn assumed;\n+\t\t\t}\n+\t\t} else {\n+\t\t\tfprintf_ln(stderr,\n+\t\t\t\t   Q_(\"\\nThe most similar command is\",\n+\t\t\t\t      \"\\nThe most similar commands are\",\n+\t\t\t\t   n));\n+\t\t\tfor (i = 0; i < n; i++)\n+\t\t\t\tfprintf(stderr, \"\\t%s\\n\", main_cmds.names[i]->name);\n+\t\t}\n \t}\n \n \texit(1);\ndiff --git a/help.h b/help.h\nindex c54bf0977d..a8c465b3df 100644\n--- a/help.h\n+++ b/help.h\n@@ -32,7 +32,8 @@ void list_all_other_cmds(struct string_list *list);\n void list_cmds_by_category(struct string_list *list,\n \t\t\t   const char *category);\n void list_cmds_by_config(struct string_list *list);\n-char *help_unknown_cmd(const char *cmd);\n+#include \"strvec.h\"\n+char *help_unknown_cmd(const char *cmd, const struct strvec *args);\n void load_command_list(const char *prefix,\n \t\t       struct cmdnames *main_cmds,\n \t\t       struct cmdnames *other_cmds);\ndiff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh\nindex 8da318d2b5..6fe2da1595 100755\n--- a/t/t9003-help-autocorrect.sh\n+++ b/t/t9003-help-autocorrect.sh\n@@ -70,4 +70,57 @@ test_expect_success 'autocorrect works in work tree created from bare repo' '\n \tgit -C worktree -c help.autocorrect=immediate status\n '\n \n+# Default behaviour (no help.autocorrect set): when there is exactly one\n+# similar command but the session is non-interactive, fall back to printing\n+# the suggestion list and exiting rather than showing a prompt.\n+test_expect_success 'default: single match non-interactive shows suggestion and fails' '\n+\ttest_might_fail git config --unset help.autocorrect &&\n+\n+\ttest_must_fail git lfg 2>actual &&\n+\tgrep \"most similar command\" actual &&\n+\tgrep \"lgf\" actual\n+'\n+\n+test_expect_success 'default: multiple matches non-interactive shows list and fails' '\n+\ttest_might_fail git config --unset help.autocorrect &&\n+\n+\ttest_must_fail git com 2>actual &&\n+\tgrep \"most similar commands\" actual &&\n+\tgrep \"commit\" actual\n+'\n+\n+# Interactive prompt tests require a real TTY.  On macOS the TTY prereq is\n+# skipped due to IO::Pty reliability issues; these tests run on Linux CI.\n+test_expect_success TTY 'default: single match interactive, answer y runs command' '\n+\tgit config --unset help.autocorrect &&\n+\n+\twrite_script git-typotest <<-\\EOF &&\n+\t\techo typotest-ran\n+\tEOF\n+\tPATH=\"$PATH:.\" export PATH &&\n+\n+\t# Feed \"y\" to /dev/tty via a wrapper that answers the prompt\n+\twrite_script answer-prompt <<-\\EOF &&\n+\t\t# Write the answer to the controlling terminal\n+\t\tprintf \"y\\n\" >/dev/tty\n+\t\texec \"$@\"\n+\tEOF\n+\n+\ttest_terminal ./answer-prompt git typotest 2>err >out &&\n+\tgrep \"typotest-ran\" out &&\n+\tgrep \"Did you mean\" err\n+'\n+\n+test_expect_success TTY 'default: single match interactive, answer n exits cleanly' '\n+\tgit config --unset help.autocorrect &&\n+\n+\twrite_script answer-prompt-no <<-\\EOF &&\n+\t\tprintf \"n\\n\" >/dev/tty\n+\t\texec \"$@\"\n+\tEOF\n+\n+\ttest_must_fail test_terminal ./answer-prompt-no git typotest 2>err &&\n+\tgrep \"Did you mean\" err\n+'\n+\n test_done\n-- \n2.50.1\n\n\n"},{"id":"545874","messageId":"ajQuqTB580gqNP8D@denethor","threadId":"65833","inReplyTo":"6a340006.60da1a74.20db39.8f57@mx.google.com","subject":"Re: [PATCH] help: prompt user to run corrected command on typo","fromName":"Justin Tobler","fromEmail":"jltobler@gmail.com","sentAt":"2026-06-18T17:48:55Z","receivedAt":"2026-06-18T17:48:58Z","isPatch":true,"body":"On 26/06/18 07:26AM, calicomills wrote:\n> From 0dc9e5c4593611b75e7003e8fdbea9370524c05b Mon Sep 17 00:00:00 2001\n> From: calicomills <jishnuck26@gmail.com>\n> Date: Thu, 18 Jun 2026 19:47:12 +0530\n> Subject: [PATCH] help: prompt user to run corrected command on typo\n> \n> When a user mistypes a git command and there is exactly one similar\n> command, git currently prints a suggestion but exits, requiring the\n> user to retype the corrected command manually.\n> \n> Instead, when stdin and stderr are both connected to a terminal and\n> there is a single best match, prompt the user with:\n> \n>   Did you mean 'git checkout neo'? [y/N]\n> \n> The full corrected invocation (command + original arguments) is shown\n> in the prompt so the user knows exactly what will run. Answering 'y'\n> re-executes git with the corrected command and all original arguments.\n> Answering anything else exits as before.\n\nIsn't this already possible via setting `help.autoCorrect=prompt` in the\nconfig? For example:\n\n  git -c help.autoCorrect=prompt comit --allow-empty -m init\n\nseems to already do exactly what is proposed here.\n\n-Justin\n"},{"id":"545918","messageId":"6a34dc40.2c570c9e.381c97.203f@mx.google.com","threadId":"65833","inReplyTo":"ajQuqTB580gqNP8D@denethor","subject":"Re: [PATCH] help: prompt user to run corrected command on typo","fromName":"Jishnu C K","fromEmail":"jishnuck26@gmail.com","sentAt":"2026-06-19T06:05:52Z","receivedAt":"2026-06-19T06:05:53Z","isPatch":true,"body":"On Thu, Jun 18, 2026, Justin Tobler wrote:\n> Isn't this already possible via setting `help.autoCorrect=prompt` in the\n> config?\n\nThank you for the review.\n\nYou're right that `help.autocorrect=prompt` exists and is similar.\nOur change differs in two ways:\n\n1. No configuration needed. The existing prompt mode requires the user\n   to explicitly set `help.autocorrect=prompt`. Most users are unaware\n   of this option, so they see a suggestion and must retype the full\n   command manually. Our change makes the interactive prompt the\n   default behaviour when stdin and stderr are a terminal.\n\n2. The prompt includes the original arguments. `help.autocorrect=prompt`\n   shows only:\n\n     Run 'checkout' instead [y/N]?\n\n   Our prompt shows the full corrected invocation:\n\n     Did you mean 'git checkout neo'? [y/N]\n\n   This lets the user confirm exactly what will run, including their\n   original arguments, before pressing 'y'.\n\nIf the consensus is that the default should remain non-interactive,\nwe are happy to rework this as an improvement to the existing\n`autocorrect=prompt` mode (showing args in the prompt) with\ndocumentation updates to make the option more discoverable.\n\n-- \nJishnu C K\n"},{"id":"545993","messageId":"ajVatJzQ0L5WAOUh@denethor","threadId":"65833","inReplyTo":"6a34dc40.2c570c9e.381c97.203f@mx.google.com","subject":"Re: [PATCH] help: prompt user to run corrected command on typo","fromName":"Justin Tobler","fromEmail":"jltobler@gmail.com","sentAt":"2026-06-19T16:24:59Z","receivedAt":"2026-06-19T16:25:03Z","isPatch":true,"body":"On 26/06/18 11:05PM, Jishnu C K wrote:\n> If the consensus is that the default should remain non-interactive,\n> we are happy to rework this as an improvement to the existing\n> `autocorrect=prompt` mode (showing args in the prompt) with\n> documentation updates to make the option more discoverable.\n\nI'm not sure what the current consensus is here, but as it would be a\nchange to the existing behavior it would need its merits discussed\naccordingly. Personally, I think requiring users to opt-in to\nautocorrect isn't a significant barrier itself. It does require that\nusers know that the option is available in the first place though. So if\ndiscoverablility of this feature is lacking and can be improved in\ndocumentation, that certainly seems like a reasonable change. \n\nRegarding changing the prompt to display command arguments, I'm\nrelatively indifferent towards it. I'm not sure it adds a ton of value,\nbut maybe other folks will have a different opinion.\n\n-Justin\n"},{"id":"545997","messageId":"xmqq5x3elc49.fsf@gitster.g","threadId":"65833","inReplyTo":"6a34dc40.2c570c9e.381c97.203f@mx.google.com","subject":"Re: [PATCH] help: prompt user to run corrected command on typo","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-06-19T16:37:58Z","receivedAt":"2026-06-19T16:38:01Z","isPatch":true,"body":"Jishnu C K <jishnuck26@gmail.com> writes:\n\n> You're right that `help.autocorrect=prompt` exists and is similar.\n> Our change differs in two ways:\n>\n> 1. No configuration needed. The existing prompt mode requires the user\n\nI do not particularly see it as an advantage.\n\n> 2. The prompt includes the original arguments. `help.autocorrect=prompt`\n>    shows only:\n>\n>      Run 'checkout' instead [y/N]?\n>\n>    Our prompt shows the full corrected invocation:\n>\n>      Did you mean 'git checkout neo'? [y/N]\n>\n>    This lets the user confirm exactly what will run, including their\n>    original arguments, before pressing 'y'.\n\nThis may be an improvement, but is there a reason why such a change\nmust be done as a parallel and unrelated (re)implementation and not\nas an incrementa improvement to the code that implements the\nexisting feature?\n\n\n\n"},{"id":"546002","messageId":"6a357689.0f9b68c4.317a5d.1919@mx.google.com","threadId":"65833","inReplyTo":"ajQuqTB580gqNP8D@denethor","subject":"[PATCH v2] help: include arguments in autocorrect=prompt message","fromName":"Jishnu C K","fromEmail":"jishnuck26@gmail.com","sentAt":"2026-06-19T17:04:09Z","receivedAt":"2026-06-19T17:04:10Z","isPatch":true,"body":"v2: Reworked as an incremental improvement to the existing\nautocorrect=prompt code path rather than a parallel reimplementation,\nper feedback from Junio and Justin.\n\n---\nFrom a4e8fb6fd6dd6a501e565c7500cbf927d7cb0b42 Mon Sep 17 00:00:00 2001\nFrom: calicomills <jishnuck26@gmail.com>\nDate: Fri, 19 Jun 2026 13:01:40 +0530\nSubject: [PATCH v2 v2] help: include arguments in autocorrect=prompt message\n\nWhen 'help.autocorrect=prompt' is configured and the user mistypes\na git command, the prompt currently shows only the corrected command\nname:\n\n  Run 'checkout' instead [y/N]?\n\nThis leaves the user unsure whether their original arguments will be\npreserved. Update the prompt to include the full corrected invocation:\n\n  Run 'git checkout neo' instead [y/N]?\n\nThe help_unknown_cmd() signature is updated to accept the args vector\nso the prompt can show the original arguments alongside the corrected\ncommand name. Callers that do not have access to the args (e.g.\nbuiltin/help.c) pass NULL, which is handled gracefully.\n\nSigned-off-by: calicomills <jishnuck26@gmail.com>\n---\n help.c                      | 49 +++++++++++++----------------------\n t/t9003-help-autocorrect.sh | 51 +++++--------------------------------\n 2 files changed, 23 insertions(+), 77 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex 30f32a7206..9ea4c076e1 100644\n--- a/help.c\n+++ b/help.c\n@@ -739,7 +739,16 @@ char *help_unknown_cmd(const char *cmd, const struct strvec *args)\n \t\telse if (cfg.autocorrect == AUTOCORRECT_PROMPT) {\n \t\t\tchar *answer;\n \t\t\tstruct strbuf msg = STRBUF_INIT;\n-\t\t\tstrbuf_addf(&msg, _(\"Run '%s' instead [y/N]? \"), assumed);\n+\t\t\tstruct strbuf full_cmd = STRBUF_INIT;\n+\t\t\tstrbuf_addstr(&full_cmd, assumed);\n+\t\t\tif (args) {\n+\t\t\t\tfor (size_t j = 1; j < args->nr; j++) {\n+\t\t\t\t\tstrbuf_addch(&full_cmd, ' ');\n+\t\t\t\t\tstrbuf_addstr(&full_cmd, args->v[j]);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tstrbuf_addf(&msg, _(\"Run 'git %s' instead [y/N]? \"), full_cmd.buf);\n+\t\t\tstrbuf_release(&full_cmd);\n \t\t\tanswer = git_prompt(msg.buf, PROMPT_ECHO);\n \t\t\tstrbuf_release(&msg);\n \t\t\tif (!(starts_with(answer, \"y\") ||\n@@ -762,37 +771,13 @@ char *help_unknown_cmd(const char *cmd, const struct strvec *args)\n \tfprintf_ln(stderr, _(\"git: '%s' is not a git command. See 'git --help'.\"), cmd);\n \n \tif (SIMILAR_ENOUGH(best_similarity)) {\n-\t\tif (n == 1 && isatty(0) && isatty(2)) {\n-\t\t\tchar *answer;\n-\t\t\tstruct strbuf msg = STRBUF_INIT;\n-\t\t\tstruct strbuf full_cmd = STRBUF_INIT;\n-\t\t\tstrbuf_addstr(&full_cmd, main_cmds.names[0]->name);\n-\t\t\tif (args) {\n-\t\t\t\tfor (size_t j = 1; j < args->nr; j++) {\n-\t\t\t\t\tstrbuf_addch(&full_cmd, ' ');\n-\t\t\t\t\tstrbuf_addstr(&full_cmd, args->v[j]);\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tstrbuf_addf(&msg, _(\"\\nDid you mean 'git %s'? [y/N] \"),\n-\t\t\t\t    full_cmd.buf);\n-\t\t\tstrbuf_release(&full_cmd);\n-\t\t\tanswer = git_prompt(msg.buf, PROMPT_ECHO);\n-\t\t\tstrbuf_release(&msg);\n-\t\t\tif (starts_with(answer, \"y\") || starts_with(answer, \"Y\")) {\n-\t\t\t\tchar *assumed = xstrdup(main_cmds.names[0]->name);\n-\t\t\t\tcmdnames_release(&cfg.aliases);\n-\t\t\t\tcmdnames_release(&main_cmds);\n-\t\t\t\tcmdnames_release(&other_cmds);\n-\t\t\t\treturn assumed;\n-\t\t\t}\n-\t\t} else {\n-\t\t\tfprintf_ln(stderr,\n-\t\t\t\t   Q_(\"\\nThe most similar command is\",\n-\t\t\t\t      \"\\nThe most similar commands are\",\n-\t\t\t\t   n));\n-\t\t\tfor (i = 0; i < n; i++)\n-\t\t\t\tfprintf(stderr, \"\\t%s\\n\", main_cmds.names[i]->name);\n-\t\t}\n+\t\tfprintf_ln(stderr,\n+\t\t\t   Q_(\"\\nThe most similar command is\",\n+\t\t\t      \"\\nThe most similar commands are\",\n+\t\t\t   n));\n+\n+\t\tfor (i = 0; i < n; i++)\n+\t\t\tfprintf(stderr, \"\\t%s\\n\", main_cmds.names[i]->name);\n \t}\n \n \texit(1);\ndiff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh\nindex 6fe2da1595..75821d63e1 100755\n--- a/t/t9003-help-autocorrect.sh\n+++ b/t/t9003-help-autocorrect.sh\n@@ -70,57 +70,18 @@ test_expect_success 'autocorrect works in work tree created from bare repo' '\n \tgit -C worktree -c help.autocorrect=immediate status\n '\n \n-# Default behaviour (no help.autocorrect set): when there is exactly one\n-# similar command but the session is non-interactive, fall back to printing\n-# the suggestion list and exiting rather than showing a prompt.\n-test_expect_success 'default: single match non-interactive shows suggestion and fails' '\n-\ttest_might_fail git config --unset help.autocorrect &&\n-\n-\ttest_must_fail git lfg 2>actual &&\n-\tgrep \"most similar command\" actual &&\n-\tgrep \"lgf\" actual\n-'\n-\n-test_expect_success 'default: multiple matches non-interactive shows list and fails' '\n-\ttest_might_fail git config --unset help.autocorrect &&\n-\n-\ttest_must_fail git com 2>actual &&\n-\tgrep \"most similar commands\" actual &&\n-\tgrep \"commit\" actual\n-'\n-\n-# Interactive prompt tests require a real TTY.  On macOS the TTY prereq is\n-# skipped due to IO::Pty reliability issues; these tests run on Linux CI.\n-test_expect_success TTY 'default: single match interactive, answer y runs command' '\n-\tgit config --unset help.autocorrect &&\n-\n-\twrite_script git-typotest <<-\\EOF &&\n-\t\techo typotest-ran\n-\tEOF\n-\tPATH=\"$PATH:.\" export PATH &&\n-\n-\t# Feed \"y\" to /dev/tty via a wrapper that answers the prompt\n-\twrite_script answer-prompt <<-\\EOF &&\n-\t\t# Write the answer to the controlling terminal\n-\t\tprintf \"y\\n\" >/dev/tty\n-\t\texec \"$@\"\n-\tEOF\n-\n-\ttest_terminal ./answer-prompt git typotest 2>err >out &&\n-\tgrep \"typotest-ran\" out &&\n-\tgrep \"Did you mean\" err\n-'\n-\n-test_expect_success TTY 'default: single match interactive, answer n exits cleanly' '\n-\tgit config --unset help.autocorrect &&\n+# autocorrect=prompt should include the original arguments in the prompt.\n+# Requires a TTY; skipped on macOS due to IO::Pty reliability issues.\n+test_expect_success TTY 'autocorrect=prompt includes arguments in prompt' '\n+\tgit config help.autocorrect prompt &&\n \n \twrite_script answer-prompt-no <<-\\EOF &&\n \t\tprintf \"n\\n\" >/dev/tty\n \t\texec \"$@\"\n \tEOF\n \n-\ttest_must_fail test_terminal ./answer-prompt-no git typotest 2>err &&\n-\tgrep \"Did you mean\" err\n+\ttest_must_fail test_terminal ./answer-prompt-no git lfg --oneline 2>actual &&\n+\tgrep \"lgf --oneline\" actual\n '\n \n test_done\n-- \n2.50.1\n\n\n"},{"id":"546239","messageId":"9D9B615B-3B80-4F97-9DDC-4B043519F26D@gmail.com","threadId":"65833","inReplyTo":"6a357689.0f9b68c4.317a5d.1919@mx.google.com","subject":"Re: [PATCH v2] help: include arguments in autocorrect=prompt message","fromName":"Jishnu C K","fromEmail":"jishnuck26@gmail.com","sentAt":"2026-06-23T15:21:34Z","receivedAt":"2026-06-23T15:22:48Z","isPatch":true,"body":"Any review comments?\nSent from my iPhone\n\n> On 19 Jun 2026, at 10:34 PM, Jishnu C K <jishnuck26@gmail.com> wrote:\n> \n> ﻿v2: Reworked as an incremental improvement to the existing\n> autocorrect=prompt code path rather than a parallel reimplementation,\n> per feedback from Junio and Justin.\n> \n> ---\n> From a4e8fb6fd6dd6a501e565c7500cbf927d7cb0b42 Mon Sep 17 00:00:00 2001\n> From: calicomills <jishnuck26@gmail.com>\n> Date: Fri, 19 Jun 2026 13:01:40 +0530\n> Subject: [PATCH v2 v2] help: include arguments in autocorrect=prompt message\n> \n> When 'help.autocorrect=prompt' is configured and the user mistypes\n> a git command, the prompt currently shows only the corrected command\n> name:\n> \n>  Run 'checkout' instead [y/N]?\n> \n> This leaves the user unsure whether their original arguments will be\n> preserved. Update the prompt to include the full corrected invocation:\n> \n>  Run 'git checkout neo' instead [y/N]?\n> \n> The help_unknown_cmd() signature is updated to accept the args vector\n> so the prompt can show the original arguments alongside the corrected\n> command name. Callers that do not have access to the args (e.g.\n> builtin/help.c) pass NULL, which is handled gracefully.\n> \n> Signed-off-by: calicomills <jishnuck26@gmail.com>\n> ---\n> help.c                      | 49 +++++++++++++----------------------\n> t/t9003-help-autocorrect.sh | 51 +++++--------------------------------\n> 2 files changed, 23 insertions(+), 77 deletions(-)\n> \n> diff --git a/help.c b/help.c\n> index 30f32a7206..9ea4c076e1 100644\n> --- a/help.c\n> +++ b/help.c\n> @@ -739,7 +739,16 @@ char *help_unknown_cmd(const char *cmd, const struct strvec *args)\n>        else if (cfg.autocorrect == AUTOCORRECT_PROMPT) {\n>            char *answer;\n>            struct strbuf msg = STRBUF_INIT;\n> -            strbuf_addf(&msg, _(\"Run '%s' instead [y/N]? \"), assumed);\n> +            struct strbuf full_cmd = STRBUF_INIT;\n> +            strbuf_addstr(&full_cmd, assumed);\n> +            if (args) {\n> +                for (size_t j = 1; j < args->nr; j++) {\n> +                    strbuf_addch(&full_cmd, ' ');\n> +                    strbuf_addstr(&full_cmd, args->v[j]);\n> +                }\n> +            }\n> +            strbuf_addf(&msg, _(\"Run 'git %s' instead [y/N]? \"), full_cmd.buf);\n> +            strbuf_release(&full_cmd);\n>            answer = git_prompt(msg.buf, PROMPT_ECHO);\n>            strbuf_release(&msg);\n>            if (!(starts_with(answer, \"y\") ||\n> @@ -762,37 +771,13 @@ char *help_unknown_cmd(const char *cmd, const struct strvec *args)\n>    fprintf_ln(stderr, _(\"git: '%s' is not a git command. See 'git --help'.\"), cmd);\n> \n>    if (SIMILAR_ENOUGH(best_similarity)) {\n> -        if (n == 1 && isatty(0) && isatty(2)) {\n> -            char *answer;\n> -            struct strbuf msg = STRBUF_INIT;\n> -            struct strbuf full_cmd = STRBUF_INIT;\n> -            strbuf_addstr(&full_cmd, main_cmds.names[0]->name);\n> -            if (args) {\n> -                for (size_t j = 1; j < args->nr; j++) {\n> -                    strbuf_addch(&full_cmd, ' ');\n> -                    strbuf_addstr(&full_cmd, args->v[j]);\n> -                }\n> -            }\n> -            strbuf_addf(&msg, _(\"\\nDid you mean 'git %s'? [y/N] \"),\n> -                    full_cmd.buf);\n> -            strbuf_release(&full_cmd);\n> -            answer = git_prompt(msg.buf, PROMPT_ECHO);\n> -            strbuf_release(&msg);\n> -            if (starts_with(answer, \"y\") || starts_with(answer, \"Y\")) {\n> -                char *assumed = xstrdup(main_cmds.names[0]->name);\n> -                cmdnames_release(&cfg.aliases);\n> -                cmdnames_release(&main_cmds);\n> -                cmdnames_release(&other_cmds);\n> -                return assumed;\n> -            }\n> -        } else {\n> -            fprintf_ln(stderr,\n> -                   Q_(\"\\nThe most similar command is\",\n> -                      \"\\nThe most similar commands are\",\n> -                   n));\n> -            for (i = 0; i < n; i++)\n> -                fprintf(stderr, \"\\t%s\\n\", main_cmds.names[i]->name);\n> -        }\n> +        fprintf_ln(stderr,\n> +               Q_(\"\\nThe most similar command is\",\n> +                  \"\\nThe most similar commands are\",\n> +               n));\n> +\n> +        for (i = 0; i < n; i++)\n> +            fprintf(stderr, \"\\t%s\\n\", main_cmds.names[i]->name);\n>    }\n> \n>    exit(1);\n> diff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh\n> index 6fe2da1595..75821d63e1 100755\n> --- a/t/t9003-help-autocorrect.sh\n> +++ b/t/t9003-help-autocorrect.sh\n> @@ -70,57 +70,18 @@ test_expect_success 'autocorrect works in work tree created from bare repo' '\n>    git -C worktree -c help.autocorrect=immediate status\n> '\n> \n> -# Default behaviour (no help.autocorrect set): when there is exactly one\n> -# similar command but the session is non-interactive, fall back to printing\n> -# the suggestion list and exiting rather than showing a prompt.\n> -test_expect_success 'default: single match non-interactive shows suggestion and fails' '\n> -    test_might_fail git config --unset help.autocorrect &&\n> -\n> -    test_must_fail git lfg 2>actual &&\n> -    grep \"most similar command\" actual &&\n> -    grep \"lgf\" actual\n> -'\n> -\n> -test_expect_success 'default: multiple matches non-interactive shows list and fails' '\n> -    test_might_fail git config --unset help.autocorrect &&\n> -\n> -    test_must_fail git com 2>actual &&\n> -    grep \"most similar commands\" actual &&\n> -    grep \"commit\" actual\n> -'\n> -\n> -# Interactive prompt tests require a real TTY.  On macOS the TTY prereq is\n> -# skipped due to IO::Pty reliability issues; these tests run on Linux CI.\n> -test_expect_success TTY 'default: single match interactive, answer y runs command' '\n> -    git config --unset help.autocorrect &&\n> -\n> -    write_script git-typotest <<-\\EOF &&\n> -        echo typotest-ran\n> -    EOF\n> -    PATH=\"$PATH:.\" export PATH &&\n> -\n> -    # Feed \"y\" to /dev/tty via a wrapper that answers the prompt\n> -    write_script answer-prompt <<-\\EOF &&\n> -        # Write the answer to the controlling terminal\n> -        printf \"y\\n\" >/dev/tty\n> -        exec \"$@\"\n> -    EOF\n> -\n> -    test_terminal ./answer-prompt git typotest 2>err >out &&\n> -    grep \"typotest-ran\" out &&\n> -    grep \"Did you mean\" err\n> -'\n> -\n> -test_expect_success TTY 'default: single match interactive, answer n exits cleanly' '\n> -    git config --unset help.autocorrect &&\n> +# autocorrect=prompt should include the original arguments in the prompt.\n> +# Requires a TTY; skipped on macOS due to IO::Pty reliability issues.\n> +test_expect_success TTY 'autocorrect=prompt includes arguments in prompt' '\n> +    git config help.autocorrect prompt &&\n> \n>    write_script answer-prompt-no <<-\\EOF &&\n>        printf \"n\\n\" >/dev/tty\n>        exec \"$@\"\n>    EOF\n> \n> -    test_must_fail test_terminal ./answer-prompt-no git typotest 2>err &&\n> -    grep \"Did you mean\" err\n> +    test_must_fail test_terminal ./answer-prompt-no git lfg --oneline 2>actual &&\n> +    grep \"lgf --oneline\" actual\n> '\n> \n> test_done\n> --\n> 2.50.1\n> \n> \n"},{"id":"546246","messageId":"xmqqcxxhnsqk.fsf@gitster.g","threadId":"65833","inReplyTo":"6a357689.0f9b68c4.317a5d.1919@mx.google.com","subject":"Re: [PATCH v2] help: include arguments in autocorrect=prompt message","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-06-23T16:09:39Z","receivedAt":"2026-06-23T16:09:41Z","isPatch":true,"body":"Jishnu C K <jishnuck26@gmail.com> writes:\n\n> v2: Reworked as an incremental improvement to the existing\n> autocorrect=prompt code path rather than a parallel reimplementation,\n> per feedback from Junio and Justin.\n>\n> ---\n> From a4e8fb6fd6dd6a501e565c7500cbf927d7cb0b42 Mon Sep 17 00:00:00 2001\n> From: calicomills <jishnuck26@gmail.com>\n> Date: Fri, 19 Jun 2026 13:01:40 +0530\n> Subject: [PATCH v2 v2] help: include arguments in autocorrect=prompt message\n\nTo learn what a typical v2 of a single-patch topic should look like,\nsee\n\n  https://lore.kernel.org/git/aipTOsH8LKTSwglj@collabora.com/\n\nfor an example.\n\n - Having auxiliary comments explaining why there is this v2,\n   including description of the difference since v1, is good, but\n   have it below the three-dash line after your sign off, not at the\n   beginning.\n\n - Please do not include \"From a4e8fb6f...\" line, which is meant as\n   a separator in multi-patch output from the git format-patch\n   command; knowing the exact commit object name you took the patch\n   from in your repository would not help anybody.\n\n - Do not include \"From:\" in the body of the message either, unless\n   you are relaying somebody else's patch, i.e., when the From\n   e-mail header (you) does not name the person who wrote the patch\n   (somebody else).\n\n - Do not include \"Date:\" in the body of the message either, as that\n   is the timestamp you wrote the change, but we care more about the\n   time when the general public first saw the patch, which is in the\n   e-mail header already.\n\n - Do not include \"Subject:\" in the body of the message either, as\n   that should be on the Subject e-mail header.\n\n> When 'help.autocorrect=prompt' is configured and the user mistypes\n> a git command, the prompt currently shows only the corrected command\n> name:\n>\n>   Run 'checkout' instead [y/N]?\n>\n> This leaves the user unsure whether their original arguments will be\n> preserved. Update the prompt to include the full corrected invocation:\n>\n>   Run 'git checkout neo' instead [y/N]?\n>\n> The help_unknown_cmd() signature is updated to accept the args vector\n> so the prompt can show the original arguments alongside the corrected\n> command name. Callers that do not have access to the args (e.g.\n> builtin/help.c) pass NULL, which is handled gracefully.\n>\n> Signed-off-by: calicomills <jishnuck26@gmail.com>\n\nDocumentation/SubmittingPatches[[real-name]] prefers to see us\ninteracting with humans with real-sounding names, not handles.\n\n> ---\n>  help.c                      | 49 +++++++++++++----------------------\n>  t/t9003-help-autocorrect.sh | 51 +++++--------------------------------\n>  2 files changed, 23 insertions(+), 77 deletions(-)\n>\n> diff --git a/help.c b/help.c\n> index 30f32a7206..9ea4c076e1 100644\n> --- a/help.c\n> +++ b/help.c\n> @@ -739,7 +739,16 @@ char *help_unknown_cmd(const char *cmd, const struct strvec *args)\n>  \t\telse if (cfg.autocorrect == AUTOCORRECT_PROMPT) {\n>  \t\t\tchar *answer;\n>  \t\t\tstruct strbuf msg = STRBUF_INIT;\n> -\t\t\tstrbuf_addf(&msg, _(\"Run '%s' instead [y/N]? \"), assumed);\n> +\t\t\tstruct strbuf full_cmd = STRBUF_INIT;\n> +\t\t\tstrbuf_addstr(&full_cmd, assumed);\n> +\t\t\tif (args) {\n> +\t\t\t\tfor (size_t j = 1; j < args->nr; j++) {\n> +\t\t\t\t\tstrbuf_addch(&full_cmd, ' ');\n> +\t\t\t\t\tstrbuf_addstr(&full_cmd, args->v[j]);\n> +\t\t\t\t}\n> +\t\t\t}\n> +\t\t\tstrbuf_addf(&msg, _(\"Run 'git %s' instead [y/N]? \"), full_cmd.buf);\n> +\t\t\tstrbuf_release(&full_cmd);\n\nThis change seems to match what is explained in the proposed log\nmessage.  Instead of giving the \"assumed\" command without its\narguments, the full command line is gprepared to be given in 'msg'.\n\nBut if we really wanted to let these be cut-and-paste, don't you\nneed to shell-quote the command line?  If the user typed\n\n\t$ git comit -m \"Hello world\"\n\nthe above makes\n\n\tRun 'git commit -m hello world' instead [y/N]?\n\nwhich would record the change made only to the file \"world\" with log\nmessage \"hello\", which is not what the user wanted to do.\n\n> @@ -762,37 +771,13 @@ char *help_unknown_cmd(const char *cmd, const struct strvec *args)\n>  \tfprintf_ln(stderr, _(\"git: '%s' is not a git command. See 'git --help'.\"), cmd);\n>  \n>  \tif (SIMILAR_ENOUGH(best_similarity)) {\n> -\t\tif (n == 1 && isatty(0) && isatty(2)) {\n> -\t\t\tchar *answer;\n> -\t\t\tstruct strbuf msg = STRBUF_INIT;\n> -\t\t\tstruct strbuf full_cmd = STRBUF_INIT;\n> -\t\t\tstrbuf_addstr(&full_cmd, main_cmds.names[0]->name);\n> -\t\t\tif (args) {\n> -\t\t\t\tfor (size_t j = 1; j < args->nr; j++) {\n> -\t\t\t\t\tstrbuf_addch(&full_cmd, ' ');\n> -\t\t\t\t\tstrbuf_addstr(&full_cmd, args->v[j]);\n> -\t\t\t\t}\n> -\t\t\t}\n> -\t\t\tstrbuf_addf(&msg, _(\"\\nDid you mean 'git %s'? [y/N] \"),\n> -\t\t\t\t    full_cmd.buf);\n> -\t\t\tstrbuf_release(&full_cmd);\n> -\t\t\tanswer = git_prompt(msg.buf, PROMPT_ECHO);\n> -\t\t\tstrbuf_release(&msg);\n> -\t\t\tif (starts_with(answer, \"y\") || starts_with(answer, \"Y\")) {\n> -\t\t\t\tchar *assumed = xstrdup(main_cmds.names[0]->name);\n> -\t\t\t\tcmdnames_release(&cfg.aliases);\n> -\t\t\t\tcmdnames_release(&main_cmds);\n> -\t\t\t\tcmdnames_release(&other_cmds);\n> -\t\t\t\treturn assumed;\n> -\t\t\t}\n\nWhat is this removal about?  The original used to give interactive\nprompt to let the user say \"Yes\", but with this part removed, it no\nlonger offers the \"well we have only one candidate, do you want to\nrun that one?\", and you instead ...\n\n> -\t\t} else {\n> -\t\t\tfprintf_ln(stderr,\n> -\t\t\t\t   Q_(\"\\nThe most similar command is\",\n> -\t\t\t\t      \"\\nThe most similar commands are\",\n> -\t\t\t\t   n));\n> -\t\t\tfor (i = 0; i < n; i++)\n> -\t\t\t\tfprintf(stderr, \"\\t%s\\n\", main_cmds.names[i]->name);\n> -\t\t}\n\n... only give \"these are the possible candidates?\"\n\n> +\t\tfprintf_ln(stderr,\n> +\t\t\t   Q_(\"\\nThe most similar command is\",\n> +\t\t\t      \"\\nThe most similar commands are\",\n> +\t\t\t   n));\n> +\n> +\t\tfor (i = 0; i < n; i++)\n> +\t\t\tfprintf(stderr, \"\\t%s\\n\", main_cmds.names[i]->name);\n>  \t}\n\nPuzzled.\n\nWorse, this [v2] does not even apply cleanly to any of the trees we\nhave.\n\nAha!  Is the removal I see above a mere \"oops, this was wrong, so\nremove it\" done on top of a previous iteration of the patch?\n\nPlease do not do that.  It would mean we will keep unwanted code\nthat went into a wrong direction (which is v1) in our history.\n\nThe development may wander around in different directions like a\ndrunken man, changing course every time patches are updated, until\nit finally gets right, but the name of the game around here, before\nyour change is merged to 'next', is to \"pretend to be a more perfect\ndeveloper than you actually are\" ;-).  You can pretend that you\nnever made a design mistake you made in [v1], and instead directly\narrived at a good state from the state of our public tree.  That\nmeans [v2] (and any subsequent rerolls, until your seires gets\nmerged to 'next') must apply directly without any of the older\niterations to 'master' (or if it is a bugfix, 'maint') branch.\n\nThanks.\n"}]}