{"thread":{"id":"27755","subject":"Doesn't disambiguate between 'external command failed' and 'command not found'","startedAt":"2011-07-05T16:49:24Z","lastAt":"2011-07-08T16:52:49Z","messageCount":13,"participants":["Alex Vandiver","Michael Schubert","Jeff King","Sverre Rabbelier","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"170834","messageId":"1309884564.18513.12.camel@umgah","threadId":"27755","inReplyTo":null,"subject":"Doesn't disambiguate between 'external command failed' and 'command not found'","fromName":"Alex Vandiver","fromEmail":"alex@chmrr.net","sentAt":"2011-07-05T16:49:24Z","receivedAt":"2011-07-05T16:49:24Z","isPatch":false,"sender":{"key":"alex@chmrr.net","avatar":"https://avatars.githubusercontent.com/u/28347?v=4"},"body":"An external git-whatever command which fails to run gets reported as not\nhaving been found, and suggests ... exactly what you just ran.  If you\nmiss the first line of the output, this can be extremely confusing --\nand \"is not a git command\" is somewhat misleading:\n\n        umgah ~ $ cat bin/git-bogus\n        #!/usr/bin/env nonexistant\n        echo \"yay\"\n        \n        umgah ~ $ git bogus\n        /usr/bin/env: nonexistant: No such file or directory\n        git: 'bogus' is not a git command. See 'git --help'.\n        \n        Did you mean this?\n        \tbogus\n\nI've no patch right now, but I thought I'd report the frustration, in\ncase someone else wanted to get to it first.\n - Alex\n"},{"id":"170840","messageId":"4E137701.1020007@elegosoft.com","threadId":"27755","inReplyTo":"1309884564.18513.12.camel@umgah","subject":"Re: Doesn't disambiguate between 'external command failed' and 'command not found'","fromName":"Michael Schubert","fromEmail":"mschub@elegosoft.com","sentAt":"2011-07-05T20:41:37Z","receivedAt":"2011-07-05T20:41:37Z","isPatch":false,"sender":{"key":"mschub@elegosoft.com","avatar":null},"body":"Hi,\n\nhere is a tiny patch; maybe there is a cleaner way doing this.?\n\n-- >8 --\n\nSubject: [PATCH] help_unknown_cmd: do not propose an \"unknown\" cmd\n\nWhen executing an external shell script like `git foo` with the following\nshebang \"#!/usr/bin/not/existing\", execvp returns 127 (ENOENT). Since\nhelp_unknown_cmd proposes the use of all external commands similar to\nthe name of the \"unknown\" command, it suggests the just failed command\nagain. Stop it.\n\nSigned-off-by: Michael Schubert <mschub@elegosoft.com>\n---\n help.c |   16 ++++++++++++++--\n 1 files changed, 14 insertions(+), 2 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex 7654f1b..10b98ba 100644\n--- a/help.c\n+++ b/help.c\n@@ -383,12 +383,24 @@ const char *help_unknown_cmd(const char *cmd)\n \n \tfprintf(stderr, \"git: '%s' is not a git command. See 'git --help'.\\n\", cmd);\n \n-\tif (SIMILAR_ENOUGH(best_similarity)) {\n+\tif (n==1 && !strcmp(cmd, main_cmds.names[0]->name))\n+\t\t;\n+\t\t/*\n+\t\t * This avoids proposing the use of a command\n+\t\t * which apparently just didn't work, e.g.\n+\t\t * when executing a shell script git-foo with\n+\t\t * the following shebang:\n+\t\t *\n+\t\t * \t#!/usr/bin/not/here\n+\t\t *\n+\t\t */\n+\telse if (SIMILAR_ENOUGH(best_similarity)) {\n \t\tfprintf(stderr, \"\\nDid you mean %s?\\n\",\n \t\t\tn < 2 ? \"this\": \"one of these\");\n \n \t\tfor (i = 0; i < n; i++)\n-\t\t\tfprintf(stderr, \"\\t%s\\n\", main_cmds.names[i]->name);\n+\t\t\tif (strcmp(cmd, main_cmds.names[i]->name))\n+\t\t\t\tfprintf(stderr, \"\\t%s\\n\", main_cmds.names[i]->name);\n \t}\n \n \texit(1);\n-- \n1.7.6.132.gdca5\n"},{"id":"170847","messageId":"20110705231604.GC12085@sigill.intra.peff.net","threadId":"27755","inReplyTo":"4E137701.1020007@elegosoft.com","subject":"Re: Doesn't disambiguate between 'external command failed' and 'command not found'","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-07-05T23:16:05Z","receivedAt":"2011-07-05T23:16:05Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Jul 05, 2011 at 10:41:37PM +0200, Michael Schubert wrote:\n\n> Subject: [PATCH] help_unknown_cmd: do not propose an \"unknown\" cmd\n> \n> When executing an external shell script like `git foo` with the following\n> shebang \"#!/usr/bin/not/existing\", execvp returns 127 (ENOENT). Since\n> help_unknown_cmd proposes the use of all external commands similar to\n> the name of the \"unknown\" command, it suggests the just failed command\n> again. Stop it.\n\nYeah, I don't think we can distinguish \"not there\" versus \"bad\ninterpreter\" just from the exec return. We would have to then search the\nPATH to see if the file actually exists.\n\n> -\tif (SIMILAR_ENOUGH(best_similarity)) {\n> +\tif (n==1 && !strcmp(cmd, main_cmds.names[0]->name))\n> +\t\t;\n> +\t\t/*\n> +\t\t * This avoids proposing the use of a command\n> +\t\t * which apparently just didn't work, e.g.\n> +\t\t * when executing a shell script git-foo with\n> +\t\t * the following shebang:\n> +\t\t *\n> +\t\t * \t#!/usr/bin/not/here\n> +\t\t *\n> +\t\t */\n> +\telse if (SIMILAR_ENOUGH(best_similarity)) {\n\nThis misses the \"autocorrect\" case just above, which should not\nautocorrect a command to itself (and I didn't try, but I assume it makes\nmore a really slow infinite loop).\n\nSo if you are going to follow this strategy, you are probably better to\njust skip the entry (or give it a high levenshtein distance) in the main\nloop where we calculate candidates.\n\nBut I wonder if we can do even better than just omitting it from the\ncandidates list. I mentioned searching the PATH above; but that is\nexactly what load_command_list does to create this candidate list. So I\nthink the only way we can have an exact match is one of:\n\n  1. There is a race condition. We tried to exec the command, and it was\n     missing; meanwhile, another process created the command.\n\n  2. Exec'ing the command returned ENOENT because of a bad interpreter.\n\nOption (1) seems fairly unlikely; so maybe we should give the user some\nadvice about (2)?\n\nSomething like:\n\ndiff --git a/help.c b/help.c\nindex e925ca1..522b2ba 100644\n--- a/help.c\n+++ b/help.c\n@@ -305,6 +305,10 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)\n #define SIMILARITY_FLOOR 7\n #define SIMILAR_ENOUGH(x) ((x) < SIMILARITY_FLOOR)\n \n+static const char bad_interpreter_advice[] =\n+\"'%s' appears to be a git command, but we were not able to\\n\"\n+\"execute it. Check the #!-line of the git-%s script.\";\n+\n const char *help_unknown_cmd(const char *cmd)\n {\n \tint i, n, best_similarity = 0;\n@@ -329,6 +333,14 @@ const char *help_unknown_cmd(const char *cmd)\n \t\tint cmp = 0; /* avoid compiler stupidity */\n \t\tconst char *candidate = main_cmds.names[i]->name;\n \n+\t\t/*\n+\t\t * An exact match means we have the command, but\n+\t\t * for some reason exec'ing it gave us ENOENT; probably\n+\t\t * it's a bad interpreter in the #! line.\n+\t\t */\n+\t\tif (!strcmp(candidate, cmd))\n+\t\t\tdie(bad_interpreter_advice, cmd, cmd);\n+\n \t\t/* Does the candidate appear in common_cmds list? */\n \t\twhile (n < ARRAY_SIZE(common_cmds) &&\n \t\t       (cmp = strcmp(common_cmds[n].name, candidate)) < 0)\n\nI'm not all that happy with the advice, though. It's pretty technical\nand specific. I'm not sure whether it would be helpful to most users or\nnot.\n\n-Peff\n"},{"id":"170848","messageId":"20110705232200.GD12085@sigill.intra.peff.net","threadId":"27755","inReplyTo":"20110705231604.GC12085@sigill.intra.peff.net","subject":"Re: Doesn't disambiguate between 'external command failed' and 'command not found'","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-07-05T23:22:00Z","receivedAt":"2011-07-05T23:22:00Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Jul 05, 2011 at 07:16:05PM -0400, Jeff King wrote:\n\n> So if you are going to follow this strategy, you are probably better to\n> just skip the entry (or give it a high levenshtein distance) in the main\n> loop where we calculate candidates.\n\nAnd here's what that would look like.\n\ndiff --git a/help.c b/help.c\nindex e925ca1..15e6f0b 100644\n--- a/help.c\n+++ b/help.c\n@@ -329,6 +329,11 @@ const char *help_unknown_cmd(const char *cmd)\n \t\tint cmp = 0; /* avoid compiler stupidity */\n \t\tconst char *candidate = main_cmds.names[i]->name;\n \n+\t\tif (!strcmp(candidate, cmd)) {\n+\t\t\tmain_cmds.names[i]->len = SIMILARITY_FLOOR + 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n \t\t/* Does the candidate appear in common_cmds list? */\n \t\twhile (n < ARRAY_SIZE(common_cmds) &&\n \t\t       (cmp = strcmp(common_cmds[n].name, candidate)) < 0)\n\nI suspect it can create its own brand of confusion, though:\n\n  $ cat `which git-broken`\n  #!/bin/bogus\n  $ git broken\n  git: 'broken' is not a git command. See 'git --help'.\n\nAt which point I search through my PATH and confirm that indeed,\n\"git-broken\" _is_ a git command. And I'm left on my own to figure out\nthat it's a broken #!-line.\n\nSo I think I prefer giving some more specific advice. Even if we don't\nmention \"#!\" lines explicitly, saying \"This exists, but exec didn't\nwork\" is probably more helpful than pretending it's not there. It gives\nclueful people an idea of where to start looking for the problem.\n\n-Peff\n"},{"id":"170907","messageId":"CAGdFq_gUUEWOKkVKK2vbR73JAZOj-BZomx939CRpSs=eF0BXog@mail.gmail.com","threadId":"27755","inReplyTo":"20110705232200.GD12085@sigill.intra.peff.net","subject":"Re: Doesn't disambiguate between 'external command failed' and 'command not found'","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2011-07-06T11:24:15Z","receivedAt":"2011-07-06T11:24:15Z","isPatch":false,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Wed, Jul 6, 2011 at 01:22, Jeff King <peff@peff.net> wrote:\n> So I think I prefer giving some more specific advice. Even if we don't\n> mention \"#!\" lines explicitly, saying \"This exists, but exec didn't\n> work\" is probably more helpful than pretending it's not there. It gives\n> clueful people an idea of where to start looking for the problem.\n\nSeconded. We should at least give the user enough information to\nfigure out next steps. I like the advice from bad_interpreter_advice,\nalthough it might be phrased more as a suggestion \"Try looking at\n...\"?\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"170912","messageId":"4E144B55.8020907@elegosoft.com","threadId":"27755","inReplyTo":"20110705231604.GC12085@sigill.intra.peff.net","subject":"Re: Doesn't disambiguate between 'external command failed' and 'command not found'","fromName":"Michael Schubert","fromEmail":"mschub@elegosoft.com","sentAt":"2011-07-06T11:47:33Z","receivedAt":"2011-07-06T11:47:33Z","isPatch":false,"sender":{"key":"mschub@elegosoft.com","avatar":null},"body":"\n> So if you are going to follow this strategy, you are probably better to\n> just skip the entry (or give it a high levenshtein distance) in the main\n> loop where we calculate candidates.\n\nYes.\n\n> But I wonder if we can do even better than just omitting it from the\n> candidates list. I mentioned searching the PATH above; but that is\n> exactly what load_command_list does to create this candidate list. So I\n> think the only way we can have an exact match is one of:\n> \n>   1. There is a race condition. We tried to exec the command, and it was\n>      missing; meanwhile, another process created the command.\n> \n>   2. Exec'ing the command returned ENOENT because of a bad interpreter.\n> \n> Option (1) seems fairly unlikely; so maybe we should give the user some\n> advice about (2)?\n\nLike this? I've replaced \"Check the #!-line of the git-%s script.\" with\n\"Maybe git-%s is broken?\" to be less technical and specific..\n\n-- >8 --\n\nSubject: [PATCH] help_unknown_cmd: do not propose an \"unknown\" cmd\n\nWhen executing an external shell script like `git foo` with the following\nshebang \"#!/usr/bin/not/existing\", execvp returns 127 (ENOENT). Since\nhelp_unknown_cmd proposes the use of all external commands similar to\nthe name of the \"unknown\" command, it suggests the just failed command\nagain. Stop it and give some advice to the user.\n\nHelped-by: Jeff King <peff@peff.net>\nSigned-off-by: Michael Schubert <mschub@elegosoft.com>\n---\n help.c |   12 ++++++++++++\n 1 files changed, 12 insertions(+), 0 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex 7654f1b..a5a0613 100644\n--- a/help.c\n+++ b/help.c\n@@ -302,6 +302,10 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)\n #define SIMILARITY_FLOOR 7\n #define SIMILAR_ENOUGH(x) ((x) < SIMILARITY_FLOOR)\n \n+static const char bad_interpreter_advice[] =\n+\t\"'%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 const char *help_unknown_cmd(const char *cmd)\n {\n \tint i, n, best_similarity = 0;\n@@ -326,6 +330,14 @@ const char *help_unknown_cmd(const char *cmd)\n \t\tint cmp = 0; /* avoid compiler stupidity */\n \t\tconst char *candidate = main_cmds.names[i]->name;\n \n+\t\t/*\n+\t\t * An exact match means we have the command, but\n+\t\t * for some reason exec'ing it gave us ENOENT; probably\n+\t\t * it's a bad interpreter in the #! line.\n+\t\t */\n+\t\tif (!strcmp(candidate, cmd))\n+\t\t\tdie(bad_interpreter_advice, cmd, cmd);\n+\n \t\t/* Does the candidate appear in common_cmds list? */\n \t\twhile (n < ARRAY_SIZE(common_cmds) &&\n \t\t       (cmp = strcmp(common_cmds[n].name, candidate)) < 0)\n-- \n1.7.6.132.g91c244\n"},{"id":"170931","messageId":"7vpqlnmidy.fsf@alter.siamese.dyndns.org","threadId":"27755","inReplyTo":"20110705231604.GC12085@sigill.intra.peff.net","subject":"Re: Doesn't disambiguate between 'external command failed' and 'command not found'","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-07-06T17:24:57Z","receivedAt":"2011-07-06T17:24:57Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> I'm not all that happy with the advice, though. It's pretty technical\n> and specific. I'm not sure whether it would be helpful to most users or\n> not.\n\nYeah, Michael's rewording makes it fuzzier by saying \"exists, unable to\nexecute, maybe git-%s is broken?\".\n\nI notice that we do not give the path to the file that implements the\ncommand. Perhaps we should walk the $PATH after we see this failure to\npinpoint which one is to be inspected (I vaguely recall a weatherbaloon\npatch to a similar effect)?\n"},{"id":"170932","messageId":"20110706175615.GA17978@sigill.intra.peff.net","threadId":"27755","inReplyTo":"7vpqlnmidy.fsf@alter.siamese.dyndns.org","subject":"Re: Doesn't disambiguate between 'external command failed' and 'command not found'","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-07-06T17:56:15Z","receivedAt":"2011-07-06T17:56:15Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jul 06, 2011 at 10:24:57AM -0700, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > I'm not all that happy with the advice, though. It's pretty technical\n> > and specific. I'm not sure whether it would be helpful to most users or\n> > not.\n> \n> Yeah, Michael's rewording makes it fuzzier by saying \"exists, unable to\n> execute, maybe git-%s is broken?\".\n\nYeah, I like his better.\n\n> I notice that we do not give the path to the file that implements the\n> command. Perhaps we should walk the $PATH after we see this failure to\n> pinpoint which one is to be inspected (I vaguely recall a weatherbaloon\n> patch to a similar effect)?\n\nThat would be better still. But I don't know how much effort this is\nreally worth. It is about catching one specific uncommon\nmisconfiguration. If it were part of a more general exec wrapper that\ngave better output (which I think is the weatherballoon you mean, that\nyou did a month or three ago), I think it might be more worthwhile.\n\nBut even then, I seem to remember the discussion fizzling out to \"is\nthis really that common a problem?\"\n\nSo I'm happy with just taking Michael's patch.\n\n-Peff\n"},{"id":"170934","messageId":"20110706175803.GB17978@sigill.intra.peff.net","threadId":"27755","inReplyTo":"4E144B55.8020907@elegosoft.com","subject":"Re: Doesn't disambiguate between 'external command failed' and 'command not found'","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-07-06T17:58:03Z","receivedAt":"2011-07-06T17:58:03Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jul 06, 2011 at 01:47:33PM +0200, Michael Schubert wrote:\n\n> Like this? I've replaced \"Check the #!-line of the git-%s script.\" with\n> \"Maybe git-%s is broken?\" to be less technical and specific..\n\nYeah, looks good to me (unless somebody wants to do something more\nelaborate to catch other exec problems, but I personally don't think\nit's worth the effort).\n\n-Peff\n"},{"id":"170935","messageId":"20110706180026.GC17978@sigill.intra.peff.net","threadId":"27755","inReplyTo":"20110706175803.GB17978@sigill.intra.peff.net","subject":"Re: Doesn't disambiguate between 'external command failed' and 'command not found'","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-07-06T18:00:26Z","receivedAt":"2011-07-06T18:00:26Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jul 06, 2011 at 01:58:03PM -0400, Jeff King wrote:\n\n> > Like this? I've replaced \"Check the #!-line of the git-%s script.\" with\n> > \"Maybe git-%s is broken?\" to be less technical and specific..\n> \n> Yeah, looks good to me (unless somebody wants to do something more\n> elaborate to catch other exec problems, but I personally don't think\n> it's worth the effort).\n\nOne minor nit, though. I haven't been paying attention to the progress\nof the gettext topics, but should this message:\n\n> +static const char bad_interpreter_advice[] =\n> +\t\"'%s' appears to be a git command, but we were not\\n\"\n> +\t\"able to execute it. Maybe git-%s is broken?\";\n\nActually be inside _() for gettext?\n\n-Peff\n"},{"id":"170952","messageId":"7vei23htzz.fsf@alter.siamese.dyndns.org","threadId":"27755","inReplyTo":"20110706180026.GC17978@sigill.intra.peff.net","subject":"Re: Doesn't disambiguate between 'external command failed' and 'command not found'","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-07-06T23:25:20Z","receivedAt":"2011-07-06T23:25:20Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Wed, Jul 06, 2011 at 01:58:03PM -0400, Jeff King wrote:\n>\n>> > Like this? I've replaced \"Check the #!-line of the git-%s script.\" with\n>> > \"Maybe git-%s is broken?\" to be less technical and specific..\n>> \n>> Yeah, looks good to me (unless somebody wants to do something more\n>> elaborate to catch other exec problems, but I personally don't think\n>> it's worth the effort).\n>\n> One minor nit, though. I haven't been paying attention to the progress\n> of the gettext topics, but should this message:\n>\n>> +static const char bad_interpreter_advice[] =\n>> +\t\"'%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> Actually be inside _() for gettext?\n\nI would mark it with N_() and then the calling site inside die() with _()\nif I were doing this.\n"},{"id":"171012","messageId":"4E16D731.5020904@elegosoft.com","threadId":"27755","inReplyTo":"7vei23htzz.fsf@alter.siamese.dyndns.org","subject":"Re: Doesn't disambiguate between 'external command failed' and 'command not found'","fromName":"Michael Schubert","fromEmail":"mschub@elegosoft.com","sentAt":"2011-07-08T10:08:49Z","receivedAt":"2011-07-08T10:08:49Z","isPatch":false,"sender":{"key":"mschub@elegosoft.com","avatar":null},"body":"On 07/07/2011 01:25 AM, Junio C Hamano wrote:\n> Jeff King <peff@peff.net> writes:\n>> One minor nit, though. I haven't been paying attention to the progress\n>> of the gettext topics, but should this message:\n>>\n>>> +static const char bad_interpreter_advice[] =\n>>> +\t\"'%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>> Actually be inside _() for gettext?\n> \n> I would mark it with N_() and then the calling site inside die() with _()\n> if I were doing this.\n\nSorry for the delay.\n\n-- >8 --\n\nSubject: [PATCH] help_unknown_cmd: do not propose an \"unknown\" cmd\n\nWhen executing an external shell script like `git foo` with the following\nshebang \"#!/usr/bin/not/existing\", execvp returns 127 (ENOENT). Since\nhelp_unknown_cmd proposes the use of all external commands similar to\nthe name of the \"unknown\" command, it suggests the just failed command\nagain. Stop it and give some advice to the user.\n\nHelped-by: Jeff King <peff@peff.net>\nSigned-off-by: Michael Schubert <mschub@elegosoft.com>\n---\n help.c |   12 ++++++++++++\n 1 files changed, 12 insertions(+), 0 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex 7654f1b..4219355 100644\n--- a/help.c\n+++ b/help.c\n@@ -302,6 +302,10 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)\n #define SIMILARITY_FLOOR 7\n #define SIMILAR_ENOUGH(x) ((x) < SIMILARITY_FLOOR)\n \n+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 const char *help_unknown_cmd(const char *cmd)\n {\n \tint i, n, best_similarity = 0;\n@@ -326,6 +330,14 @@ const char *help_unknown_cmd(const char *cmd)\n \t\tint cmp = 0; /* avoid compiler stupidity */\n \t\tconst char *candidate = main_cmds.names[i]->name;\n \n+\t\t/*\n+\t\t * An exact match means we have the command, but\n+\t\t * for some reason exec'ing it gave us ENOENT; probably\n+\t\t * it's a bad interpreter in the #! line.\n+\t\t */\n+\t\tif (!strcmp(candidate, cmd))\n+\t\t\tdie(_(bad_interpreter_advice), cmd, cmd);\n+\n \t\t/* Does the candidate appear in common_cmds list? */\n \t\twhile (n < ARRAY_SIZE(common_cmds) &&\n \t\t       (cmp = strcmp(common_cmds[n].name, candidate)) < 0)\n-- \n1.7.6.132.g91c244.dirty\n"},{"id":"171099","messageId":"7vwrfod1hy.fsf@alter.siamese.dyndns.org","threadId":"27755","inReplyTo":"4E16D731.5020904@elegosoft.com","subject":"Re: Doesn't disambiguate between 'external command failed' and 'command not found'","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-07-08T16:52:49Z","receivedAt":"2011-07-08T16:52:49Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael Schubert <mschub@elegosoft.com> writes:\n\n> Sorry for the delay.\n\nThanks.\n"}]}