{"thread":{"id":"14766","subject":"git help broken","startedAt":"2008-07-30T20:52:26Z","lastAt":"2008-08-22T04:40:09Z","messageCount":13,"participants":["Kevin Ballard","Miklos Vajna","Johannes Schindelin","Christian Couder"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"85685","messageId":"C0DB03B0-8AF5-4B6A-A9DB-16608128EB31@sb.org","threadId":"14766","inReplyTo":null,"subject":"git help broken","fromName":"Kevin Ballard","fromEmail":"kevin@sb.org","sentAt":"2008-07-30T20:52:26Z","receivedAt":"2008-07-30T20:52:26Z","isPatch":false,"sender":{"key":"kevin@sb.org","avatar":"https://avatars.githubusercontent.com/u/714?v=4"},"body":"`git help diff` no longer finds the git-diff manpage (as of tip of  \nnext branch). I haven't tested, but I suspect  \n940208a771066229bc6a486f6a058e332b71cfe4 is responsible.\n\n-Kevin Ballard\n\n-- \nKevin Ballard\nhttp://kevin.sb.org\nkevin@sb.org\nhttp://www.tildesoft.com\n"},{"id":"85699","messageId":"1217457487-6509-1-git-send-email-vmiklos@frugalware.org","threadId":"14766","inReplyTo":"C0DB03B0-8AF5-4B6A-A9DB-16608128EB31@sb.org","subject":"[PATCH] builtin-help: always load_command_list() in cmd_help()","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-30T22:38:07Z","receivedAt":"2008-07-30T22:38:07Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"When cmd_help() is called, we always need the list of main and other\ncommands, not just when the list of all commands is shown. Before this\npatch 'git help diff' invoked 'man gitdiff' because cmd_to_page()\nthought 'diff' is not a git command.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n\nOn Wed, Jul 30, 2008 at 01:52:26PM -0700, Kevin Ballard <kevin@sb.org> wrote:\n> `git help diff` no longer finds the git-diff manpage (as of tip of\n> next branch). I haven't tested, but I suspect\n> 940208a771066229bc6a486f6a058e332b71cfe4 is responsible.\n\nThis fixed the issue for me.\n\nThanks!\n\n help.c |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex 88c0d5b..968f368 100644\n--- a/help.c\n+++ b/help.c\n@@ -690,6 +690,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n {\n \tint nongit;\n \tconst char *alias;\n+\tunsigned int longest = load_command_list(\"git-\", &main_cmds, &other_cmds);\n \n \tsetup_git_directory_gently(&nongit);\n \tgit_config(git_help_config, NULL);\n@@ -698,7 +699,6 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \t\t\tbuiltin_help_usage, 0);\n \n \tif (show_all) {\n-\t\tunsigned int longest = load_command_list(\"git-\", &main_cmds, &other_cmds);\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n \t\tlist_commands(\"git commands\", longest, &main_cmds, &other_cmds);\n \t\tprintf(\"%s\\n\", git_more_info_string);\n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85701","messageId":"871A4541-3980-4C82-8A4A-CF9BE066946D@sb.org","threadId":"14766","inReplyTo":"1217457487-6509-1-git-send-email-vmiklos@frugalware.org","subject":"Re: [PATCH] builtin-help: always load_command_list() in cmd_help()","fromName":"Kevin Ballard","fromEmail":"kevin@sb.org","sentAt":"2008-07-30T22:50:46Z","receivedAt":"2008-07-30T22:50:46Z","isPatch":true,"sender":{"key":"kevin@sb.org","avatar":"https://avatars.githubusercontent.com/u/714?v=4"},"body":"This patch works great for me.\n\nHeck, after these help changes, git-help behaves even better in its  \nerror message.\n\n > git help merge-recursive\nNo manual entry for git-merge-recursive\n > git help sdfkjl\nNo manual entry for gitsdfkjl\n\nIt used to complain No manual entry for gitmerge-recursive.\n\nAcked-by: Kevin Ballard <kevin@sb.org>\n\n-Kevin Ballard\n\nOn Jul 30, 2008, at 3:38 PM, Miklos Vajna wrote:\n\n> When cmd_help() is called, we always need the list of main and other\n> commands, not just when the list of all commands is shown. Before this\n> patch 'git help diff' invoked 'man gitdiff' because cmd_to_page()\n> thought 'diff' is not a git command.\n>\n> Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>\n> ---\n>\n> On Wed, Jul 30, 2008 at 01:52:26PM -0700, Kevin Ballard  \n> <kevin@sb.org> wrote:\n>> `git help diff` no longer finds the git-diff manpage (as of tip of\n>> next branch). I haven't tested, but I suspect\n>> 940208a771066229bc6a486f6a058e332b71cfe4 is responsible.\n>\n> This fixed the issue for me.\n>\n> Thanks!\n>\n> help.c |    2 +-\n> 1 files changed, 1 insertions(+), 1 deletions(-)\n>\n> diff --git a/help.c b/help.c\n> index 88c0d5b..968f368 100644\n> --- a/help.c\n> +++ b/help.c\n> @@ -690,6 +690,7 @@ int cmd_help(int argc, const char **argv, const  \n> char *prefix)\n> {\n> \tint nongit;\n> \tconst char *alias;\n> +\tunsigned int longest = load_command_list(\"git-\", &main_cmds,  \n> &other_cmds);\n>\n> \tsetup_git_directory_gently(&nongit);\n> \tgit_config(git_help_config, NULL);\n> @@ -698,7 +699,6 @@ int cmd_help(int argc, const char **argv, const  \n> char *prefix)\n> \t\t\tbuiltin_help_usage, 0);\n>\n> \tif (show_all) {\n> -\t\tunsigned int longest = load_command_list(\"git-\", &main_cmds,  \n> &other_cmds);\n> \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n> \t\tlist_commands(\"git commands\", longest, &main_cmds, &other_cmds);\n> \t\tprintf(\"%s\\n\", git_more_info_string);\n> -- \n> 1.6.0.rc0.14.g95f8.dirty\n>\n\n-- \nKevin Ballard\nhttp://kevin.sb.org\nkevin@sb.org\nhttp://www.tildesoft.com\n"},{"id":"85707","messageId":"alpine.LSU.1.00.0807310141060.3486@wbgn129.biozentrum.uni-wuerzburg.de","threadId":"14766","inReplyTo":"C0DB03B0-8AF5-4B6A-A9DB-16608128EB31@sb.org","subject":"Re: git help broken","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-30T23:42:15Z","receivedAt":"2008-07-30T23:42:15Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 30 Jul 2008, Kevin Ballard wrote:\n\n> `git help diff` no longer finds the git-diff manpage (as of tip of next \n> branch). I haven't tested, but I suspect \n> 940208a771066229bc6a486f6a058e332b71cfe4 is responsible.\n\nJust to save everybody else and her dog the trouble: that commit's oneline \nis \"builtin-help: make some internal functions available to other \nbuiltins\".\n\nAnd from the patch, it is pretty obvious that it does not come close to \nthe \"man\" code path.\n\nCiao,\nDscho\n"},{"id":"85709","messageId":"alpine.LSU.1.00.0807310144040.3486@wbgn129.biozentrum.uni-wuerzburg.de","threadId":"14766","inReplyTo":"alpine.LSU.1.00.0807310141060.3486@wbgn129.biozentrum.uni-wuerzburg.de","subject":"Re: git help broken","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-30T23:44:36Z","receivedAt":"2008-07-30T23:44:36Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 31 Jul 2008, Johannes Schindelin wrote:\n\n> On Wed, 30 Jul 2008, Kevin Ballard wrote:\n> \n> > `git help diff` no longer finds the git-diff manpage (as of tip of next \n> > branch). I haven't tested, but I suspect \n> > 940208a771066229bc6a486f6a058e332b71cfe4 is responsible.\n> \n> Just to save everybody else and her dog the trouble: that commit's oneline \n> is \"builtin-help: make some internal functions available to other \n> builtins\".\n> \n> And from the patch, it is pretty obvious that it does not come close to \n> the \"man\" code path.\n\nOh, so it was involved?\n\nOh, well,\nDscho\n"},{"id":"85710","messageId":"88026755-3022-43A5-921C-D11244E1F723@sb.org","threadId":"14766","inReplyTo":"alpine.LSU.1.00.0807310141060.3486@wbgn129.biozentrum.uni-wuerzburg.de","subject":"Re: git help broken","fromName":"Kevin Ballard","fromEmail":"kevin@sb.org","sentAt":"2008-07-30T23:45:27Z","receivedAt":"2008-07-30T23:45:27Z","isPatch":false,"sender":{"key":"kevin@sb.org","avatar":"https://avatars.githubusercontent.com/u/714?v=4"},"body":"On Jul 30, 2008, at 4:42 PM, Johannes Schindelin wrote:\n\n> On Wed, 30 Jul 2008, Kevin Ballard wrote:\n>\n>> `git help diff` no longer finds the git-diff manpage (as of tip of  \n>> next\n>> branch). I haven't tested, but I suspect\n>> 940208a771066229bc6a486f6a058e332b71cfe4 is responsible.\n>\n> Just to save everybody else and her dog the trouble: that commit's  \n> oneline\n> is \"builtin-help: make some internal functions available to other\n> builtins\".\n>\n> And from the patch, it is pretty obvious that it does not come close  \n> to\n> the \"man\" code path.\n\nI suspected it because it was the only non-merge commit since my last  \npull that mentioned \"help\" in the message. Regardless, Miklos has  \nposted a patch that works.\n\n-Kevin Ballard\n\n-- \nKevin Ballard\nhttp://kevin.sb.org\nkevin@sb.org\nhttp://www.tildesoft.com\n"},{"id":"85714","messageId":"20080731000454.GJ32057@genesis.frugalware.org","threadId":"14766","inReplyTo":"alpine.LSU.1.00.0807310144040.3486@wbgn129.biozentrum.uni-wuerzburg.de","subject":"Re: git help broken","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-31T00:04:54Z","receivedAt":"2008-07-31T00:04:54Z","isPatch":false,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Thu, Jul 31, 2008 at 01:44:36AM +0200, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> > And from the patch, it is pretty obvious that it does not come close to \n> > the \"man\" code path.\n> \n> Oh, so it was involved?\n\nYes. The command list is no longer loaded automatically and the default\nfor non-git commands on git help foo was 'gitfoo', I guess for\ngittutorial and such manpages.\n"},{"id":"85860","messageId":"200808010628.52875.chriscool@tuxfamily.org","threadId":"14766","inReplyTo":"20080731000454.GJ32057@genesis.frugalware.org","subject":"Re: git help broken","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2008-08-01T04:28:52Z","receivedAt":"2008-08-01T04:28:52Z","isPatch":false,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Le jeudi 31 juillet 2008, Miklos Vajna a écrit :\n> On Thu, Jul 31, 2008 at 01:44:36AM +0200, Johannes Schindelin \n<Johannes.Schindelin@gmx.de> wrote:\n> > > And from the patch, it is pretty obvious that it does not come close\n> > > to the \"man\" code path.\n> >\n> > Oh, so it was involved?\n>\n> Yes. The command list is no longer loaded automatically and the default\n> for non-git commands on git help foo was 'gitfoo', I guess for\n> gittutorial and such manpages.\n\nYeah, and it seems that \"git help help\" doesn't work any more since my patch \nthat does that:\n\n2dce956e397be8a769624e8693565b8a30056060 help: check early if we have a \ncommand, if not try a documentation topic\n\nI didn't realize that the function \"is_git_command\" would not work \nfor \"help\".\n\nPerhaps there should be another function like is_git_command that could work \nusing the \"struct cmd_struct commands\" defined in \"handle_internal_command\" \nin \"git.c\". That may be faster and more accurate.\n\nUnfortunately I won't have time to work on this as I will leave for vacation \nin a few hours. Sorry to leave this behind.\n\nBest regards,\nChristian.\n"},{"id":"85904","messageId":"20080801144121.GU32057@genesis.frugalware.org","threadId":"14766","inReplyTo":"200808010628.52875.chriscool@tuxfamily.org","subject":"Re: git help broken","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-08-01T14:41:21Z","receivedAt":"2008-08-01T14:41:21Z","isPatch":false,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Fri, Aug 01, 2008 at 06:28:52AM +0200, Christian Couder <chriscool@tuxfamily.org> wrote:\n> I didn't realize that the function \"is_git_command\" would not work \n> for \"help\".\n\nIs there any reason why help is not a builtin? I think that would solve\nthe problem.\n\nI'm willing to do such a patch, I just asked in case that would be\nno-go for some - for me - unknown reason.\n\nThanks.\n"},{"id":"85970","messageId":"1217664518-17047-1-git-send-email-vmiklos@frugalware.org","threadId":"14766","inReplyTo":"20080801144121.GU32057@genesis.frugalware.org","subject":"[PATCH] Builtin git-help.","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-08-02T08:08:38Z","receivedAt":"2008-08-02T08:08:38Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"This patch splits out git-help's functions to builtin-help.c and leaves\nonly functions used by other builtins in help.c.\n\nFirst this removes git-help's functions from libgit which are not\ninteresting for other builtins, second this makes 'git help help' work\nagain.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n\nThis is for 'next'.\n\n Makefile       |    3 +-\n builtin-help.c |  462 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n help.c         |  464 --------------------------------------------------------\n help.h         |    6 +\n 4 files changed, 470 insertions(+), 465 deletions(-)\n create mode 100644 builtin-help.c\n\ndiff --git a/Makefile b/Makefile\nindex 8431ffd..562e453 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -519,6 +519,7 @@ BUILTIN_OBJS += builtin-for-each-ref.o\n BUILTIN_OBJS += builtin-fsck.o\n BUILTIN_OBJS += builtin-gc.o\n BUILTIN_OBJS += builtin-grep.o\n+BUILTIN_OBJS += builtin-help.o\n BUILTIN_OBJS += builtin-init-db.o\n BUILTIN_OBJS += builtin-log.o\n BUILTIN_OBJS += builtin-ls-files.o\n@@ -1090,7 +1091,7 @@ git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \\\n \t\t$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)\n \n-help.o: help.c common-cmds.h GIT-CFLAGS\n+builtin-help.o: builtin-help.c common-cmds.h GIT-CFLAGS\n \t$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \\\n \t\t'-DGIT_HTML_PATH=\"$(htmldir_SQ)\"' \\\n \t\t'-DGIT_MAN_PATH=\"$(mandir_SQ)\"' \\\ndiff --git a/builtin-help.c b/builtin-help.c\nnew file mode 100644\nindex 0000000..391f749\n--- /dev/null\n+++ b/builtin-help.c\n@@ -0,0 +1,462 @@\n+/*\n+ * builtin-help.c\n+ *\n+ * Builtin help command\n+ */\n+#include \"cache.h\"\n+#include \"builtin.h\"\n+#include \"exec_cmd.h\"\n+#include \"common-cmds.h\"\n+#include \"parse-options.h\"\n+#include \"run-command.h\"\n+#include \"help.h\"\n+\n+static struct man_viewer_list {\n+\tstruct man_viewer_list *next;\n+\tchar name[FLEX_ARRAY];\n+} *man_viewer_list;\n+\n+static struct man_viewer_info_list {\n+\tstruct man_viewer_info_list *next;\n+\tconst char *info;\n+\tchar name[FLEX_ARRAY];\n+} *man_viewer_info_list;\n+\n+enum help_format {\n+\tHELP_FORMAT_MAN,\n+\tHELP_FORMAT_INFO,\n+\tHELP_FORMAT_WEB,\n+};\n+\n+static int show_all = 0;\n+static enum help_format help_format = HELP_FORMAT_MAN;\n+static struct option builtin_help_options[] = {\n+\tOPT_BOOLEAN('a', \"all\", &show_all, \"print all available commands\"),\n+\tOPT_SET_INT('m', \"man\", &help_format, \"show man page\", HELP_FORMAT_MAN),\n+\tOPT_SET_INT('w', \"web\", &help_format, \"show manual in web browser\",\n+\t\t\tHELP_FORMAT_WEB),\n+\tOPT_SET_INT('i', \"info\", &help_format, \"show info page\",\n+\t\t\tHELP_FORMAT_INFO),\n+\tOPT_END(),\n+};\n+\n+static const char * const builtin_help_usage[] = {\n+\t\"git help [--all] [--man|--web|--info] [command]\",\n+\tNULL\n+};\n+\n+static enum help_format parse_help_format(const char *format)\n+{\n+\tif (!strcmp(format, \"man\"))\n+\t\treturn HELP_FORMAT_MAN;\n+\tif (!strcmp(format, \"info\"))\n+\t\treturn HELP_FORMAT_INFO;\n+\tif (!strcmp(format, \"web\") || !strcmp(format, \"html\"))\n+\t\treturn HELP_FORMAT_WEB;\n+\tdie(\"unrecognized help format '%s'\", format);\n+}\n+\n+static const char *get_man_viewer_info(const char *name)\n+{\n+\tstruct man_viewer_info_list *viewer;\n+\n+\tfor (viewer = man_viewer_info_list; viewer; viewer = viewer->next)\n+\t{\n+\t\tif (!strcasecmp(name, viewer->name))\n+\t\t\treturn viewer->info;\n+\t}\n+\treturn NULL;\n+}\n+\n+static int check_emacsclient_version(void)\n+{\n+\tstruct strbuf buffer = STRBUF_INIT;\n+\tstruct child_process ec_process;\n+\tconst char *argv_ec[] = { \"emacsclient\", \"--version\", NULL };\n+\tint version;\n+\n+\t/* emacsclient prints its version number on stderr */\n+\tmemset(&ec_process, 0, sizeof(ec_process));\n+\tec_process.argv = argv_ec;\n+\tec_process.err = -1;\n+\tec_process.stdout_to_stderr = 1;\n+\tif (start_command(&ec_process)) {\n+\t\tfprintf(stderr, \"Failed to start emacsclient.\\n\");\n+\t\treturn -1;\n+\t}\n+\tstrbuf_read(&buffer, ec_process.err, 20);\n+\tclose(ec_process.err);\n+\n+\t/*\n+\t * Don't bother checking return value, because \"emacsclient --version\"\n+\t * seems to always exits with code 1.\n+\t */\n+\tfinish_command(&ec_process);\n+\n+\tif (prefixcmp(buffer.buf, \"emacsclient\")) {\n+\t\tfprintf(stderr, \"Failed to parse emacsclient version.\\n\");\n+\t\tstrbuf_release(&buffer);\n+\t\treturn -1;\n+\t}\n+\n+\tstrbuf_remove(&buffer, 0, strlen(\"emacsclient\"));\n+\tversion = atoi(buffer.buf);\n+\n+\tif (version < 22) {\n+\t\tfprintf(stderr,\n+\t\t\t\"emacsclient version '%d' too old (< 22).\\n\",\n+\t\t\tversion);\n+\t\tstrbuf_release(&buffer);\n+\t\treturn -1;\n+\t}\n+\n+\tstrbuf_release(&buffer);\n+\treturn 0;\n+}\n+\n+static void exec_woman_emacs(const char* path, const char *page)\n+{\n+\tif (!check_emacsclient_version()) {\n+\t\t/* This works only with emacsclient version >= 22. */\n+\t\tstruct strbuf man_page = STRBUF_INIT;\n+\n+\t\tif (!path)\n+\t\t\tpath = \"emacsclient\";\n+\t\tstrbuf_addf(&man_page, \"(woman \\\"%s\\\")\", page);\n+\t\texeclp(path, \"emacsclient\", \"-e\", man_page.buf, NULL);\n+\t\twarning(\"failed to exec '%s': %s\", path, strerror(errno));\n+\t}\n+}\n+\n+static void exec_man_konqueror(const char* path, const char *page)\n+{\n+\tconst char *display = getenv(\"DISPLAY\");\n+\tif (display && *display) {\n+\t\tstruct strbuf man_page = STRBUF_INIT;\n+\t\tconst char *filename = \"kfmclient\";\n+\n+\t\t/* It's simpler to launch konqueror using kfmclient. */\n+\t\tif (path) {\n+\t\t\tconst char *file = strrchr(path, '/');\n+\t\t\tif (file && !strcmp(file + 1, \"konqueror\")) {\n+\t\t\t\tchar *new = xstrdup(path);\n+\t\t\t\tchar *dest = strrchr(new, '/');\n+\n+\t\t\t\t/* strlen(\"konqueror\") == strlen(\"kfmclient\") */\n+\t\t\t\tstrcpy(dest + 1, \"kfmclient\");\n+\t\t\t\tpath = new;\n+\t\t\t}\n+\t\t\tif (file)\n+\t\t\t\tfilename = file;\n+\t\t} else\n+\t\t\tpath = \"kfmclient\";\n+\t\tstrbuf_addf(&man_page, \"man:%s(1)\", page);\n+\t\texeclp(path, filename, \"newTab\", man_page.buf, NULL);\n+\t\twarning(\"failed to exec '%s': %s\", path, strerror(errno));\n+\t}\n+}\n+\n+static void exec_man_man(const char* path, const char *page)\n+{\n+\tif (!path)\n+\t\tpath = \"man\";\n+\texeclp(path, \"man\", page, NULL);\n+\twarning(\"failed to exec '%s': %s\", path, strerror(errno));\n+}\n+\n+static void exec_man_cmd(const char *cmd, const char *page)\n+{\n+\tstruct strbuf shell_cmd = STRBUF_INIT;\n+\tstrbuf_addf(&shell_cmd, \"%s %s\", cmd, page);\n+\texecl(\"/bin/sh\", \"sh\", \"-c\", shell_cmd.buf, NULL);\n+\twarning(\"failed to exec '%s': %s\", cmd, strerror(errno));\n+}\n+\n+static void add_man_viewer(const char *name)\n+{\n+\tstruct man_viewer_list **p = &man_viewer_list;\n+\tsize_t len = strlen(name);\n+\n+\twhile (*p)\n+\t\tp = &((*p)->next);\n+\t*p = xcalloc(1, (sizeof(**p) + len + 1));\n+\tstrncpy((*p)->name, name, len);\n+}\n+\n+static int supported_man_viewer(const char *name, size_t len)\n+{\n+\treturn (!strncasecmp(\"man\", name, len) ||\n+\t\t!strncasecmp(\"woman\", name, len) ||\n+\t\t!strncasecmp(\"konqueror\", name, len));\n+}\n+\n+static void do_add_man_viewer_info(const char *name,\n+\t\t\t\t   size_t len,\n+\t\t\t\t   const char *value)\n+{\n+\tstruct man_viewer_info_list *new = xcalloc(1, sizeof(*new) + len + 1);\n+\n+\tstrncpy(new->name, name, len);\n+\tnew->info = xstrdup(value);\n+\tnew->next = man_viewer_info_list;\n+\tman_viewer_info_list = new;\n+}\n+\n+static int add_man_viewer_path(const char *name,\n+\t\t\t       size_t len,\n+\t\t\t       const char *value)\n+{\n+\tif (supported_man_viewer(name, len))\n+\t\tdo_add_man_viewer_info(name, len, value);\n+\telse\n+\t\twarning(\"'%s': path for unsupported man viewer.\\n\"\n+\t\t\t\"Please consider using 'man.<tool>.cmd' instead.\",\n+\t\t\tname);\n+\n+\treturn 0;\n+}\n+\n+static int add_man_viewer_cmd(const char *name,\n+\t\t\t      size_t len,\n+\t\t\t      const char *value)\n+{\n+\tif (supported_man_viewer(name, len))\n+\t\twarning(\"'%s': cmd for supported man viewer.\\n\"\n+\t\t\t\"Please consider using 'man.<tool>.path' instead.\",\n+\t\t\tname);\n+\telse\n+\t\tdo_add_man_viewer_info(name, len, value);\n+\n+\treturn 0;\n+}\n+\n+static int add_man_viewer_info(const char *var, const char *value)\n+{\n+\tconst char *name = var + 4;\n+\tconst char *subkey = strrchr(name, '.');\n+\n+\tif (!subkey)\n+\t\treturn error(\"Config with no key for man viewer: %s\", name);\n+\n+\tif (!strcmp(subkey, \".path\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\treturn add_man_viewer_path(name, subkey - name, value);\n+\t}\n+\tif (!strcmp(subkey, \".cmd\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\treturn add_man_viewer_cmd(name, subkey - name, value);\n+\t}\n+\n+\twarning(\"'%s': unsupported man viewer sub key.\", subkey);\n+\treturn 0;\n+}\n+\n+static int git_help_config(const char *var, const char *value, void *cb)\n+{\n+\tif (!strcmp(var, \"help.format\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\thelp_format = parse_help_format(value);\n+\t\treturn 0;\n+\t}\n+\tif (!strcmp(var, \"man.viewer\")) {\n+\t\tif (!value)\n+\t\t\treturn config_error_nonbool(var);\n+\t\tadd_man_viewer(value);\n+\t\treturn 0;\n+\t}\n+\tif (!prefixcmp(var, \"man.\"))\n+\t\treturn add_man_viewer_info(var, value);\n+\n+\treturn git_default_config(var, value, cb);\n+}\n+\n+struct cmdnames main_cmds, other_cmds;\n+\n+void list_common_cmds_help(void)\n+{\n+\tint i, longest = 0;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(common_cmds); i++) {\n+\t\tif (longest < strlen(common_cmds[i].name))\n+\t\t\tlongest = strlen(common_cmds[i].name);\n+\t}\n+\n+\tputs(\"The most commonly used git commands are:\");\n+\tfor (i = 0; i < ARRAY_SIZE(common_cmds); i++) {\n+\t\tprintf(\"   %s   \", common_cmds[i].name);\n+\t\tmput_char(' ', longest - strlen(common_cmds[i].name));\n+\t\tputs(common_cmds[i].help);\n+\t}\n+}\n+\n+static int is_git_command(const char *s)\n+{\n+\treturn is_in_cmdlist(&main_cmds, s) ||\n+\t\tis_in_cmdlist(&other_cmds, s);\n+}\n+\n+static const char *prepend(const char *prefix, const char *cmd)\n+{\n+\tsize_t pre_len = strlen(prefix);\n+\tsize_t cmd_len = strlen(cmd);\n+\tchar *p = xmalloc(pre_len + cmd_len + 1);\n+\tmemcpy(p, prefix, pre_len);\n+\tstrcpy(p + pre_len, cmd);\n+\treturn p;\n+}\n+\n+static const char *cmd_to_page(const char *git_cmd)\n+{\n+\tif (!git_cmd)\n+\t\treturn \"git\";\n+\telse if (!prefixcmp(git_cmd, \"git\"))\n+\t\treturn git_cmd;\n+\telse if (is_git_command(git_cmd))\n+\t\treturn prepend(\"git-\", git_cmd);\n+\telse\n+\t\treturn prepend(\"git\", git_cmd);\n+}\n+\n+static void setup_man_path(void)\n+{\n+\tstruct strbuf new_path;\n+\tconst char *old_path = getenv(\"MANPATH\");\n+\n+\tstrbuf_init(&new_path, 0);\n+\n+\t/* We should always put ':' after our path. If there is no\n+\t * old_path, the ':' at the end will let 'man' to try\n+\t * system-wide paths after ours to find the manual page. If\n+\t * there is old_path, we need ':' as delimiter. */\n+\tstrbuf_addstr(&new_path, GIT_MAN_PATH);\n+\tstrbuf_addch(&new_path, ':');\n+\tif (old_path)\n+\t\tstrbuf_addstr(&new_path, old_path);\n+\n+\tsetenv(\"MANPATH\", new_path.buf, 1);\n+\n+\tstrbuf_release(&new_path);\n+}\n+\n+static void exec_viewer(const char *name, const char *page)\n+{\n+\tconst char *info = get_man_viewer_info(name);\n+\n+\tif (!strcasecmp(name, \"man\"))\n+\t\texec_man_man(info, page);\n+\telse if (!strcasecmp(name, \"woman\"))\n+\t\texec_woman_emacs(info, page);\n+\telse if (!strcasecmp(name, \"konqueror\"))\n+\t\texec_man_konqueror(info, page);\n+\telse if (info)\n+\t\texec_man_cmd(info, page);\n+\telse\n+\t\twarning(\"'%s': unknown man viewer.\", name);\n+}\n+\n+static void show_man_page(const char *git_cmd)\n+{\n+\tstruct man_viewer_list *viewer;\n+\tconst char *page = cmd_to_page(git_cmd);\n+\n+\tsetup_man_path();\n+\tfor (viewer = man_viewer_list; viewer; viewer = viewer->next)\n+\t{\n+\t\texec_viewer(viewer->name, page); /* will return when unable */\n+\t}\n+\texec_viewer(\"man\", page);\n+\tdie(\"no man viewer handled the request\");\n+}\n+\n+static void show_info_page(const char *git_cmd)\n+{\n+\tconst char *page = cmd_to_page(git_cmd);\n+\tsetenv(\"INFOPATH\", GIT_INFO_PATH, 1);\n+\texeclp(\"info\", \"info\", \"gitman\", page, NULL);\n+}\n+\n+static void get_html_page_path(struct strbuf *page_path, const char *page)\n+{\n+\tstruct stat st;\n+\tconst char *html_path = system_path(GIT_HTML_PATH);\n+\n+\t/* Check that we have a git documentation directory. */\n+\tif (stat(mkpath(\"%s/git.html\", html_path), &st)\n+\t    || !S_ISREG(st.st_mode))\n+\t\tdie(\"'%s': not a documentation directory.\", html_path);\n+\n+\tstrbuf_init(page_path, 0);\n+\tstrbuf_addf(page_path, \"%s/%s.html\", html_path, page);\n+}\n+\n+/*\n+ * If open_html is not defined in a platform-specific way (see for\n+ * example compat/mingw.h), we use the script web--browse to display\n+ * HTML.\n+ */\n+#ifndef open_html\n+void open_html(const char *path)\n+{\n+\texecl_git_cmd(\"web--browse\", \"-c\", \"help.browser\", path, NULL);\n+}\n+#endif\n+\n+static void show_html_page(const char *git_cmd)\n+{\n+\tconst char *page = cmd_to_page(git_cmd);\n+\tstruct strbuf page_path; /* it leaks but we exec bellow */\n+\n+\tget_html_page_path(&page_path, page);\n+\n+\topen_html(page_path.buf);\n+}\n+\n+int cmd_help(int argc, const char **argv, const char *prefix)\n+{\n+\tint nongit;\n+\tconst char *alias;\n+\tunsigned int longest = load_command_list(\"git-\", &main_cmds, &other_cmds);\n+\n+\tsetup_git_directory_gently(&nongit);\n+\tgit_config(git_help_config, NULL);\n+\n+\targc = parse_options(argc, argv, builtin_help_options,\n+\t\t\tbuiltin_help_usage, 0);\n+\n+\tif (show_all) {\n+\t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n+\t\tlist_commands(\"git commands\", longest, &main_cmds, &other_cmds);\n+\t\tprintf(\"%s\\n\", git_more_info_string);\n+\t\treturn 0;\n+\t}\n+\n+\tif (!argv[0]) {\n+\t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n+\t\tlist_common_cmds_help();\n+\t\tprintf(\"\\n%s\\n\", git_more_info_string);\n+\t\treturn 0;\n+\t}\n+\n+\talias = alias_lookup(argv[0]);\n+\tif (alias && !is_git_command(argv[0])) {\n+\t\tprintf(\"`git %s' is aliased to `%s'\\n\", argv[0], alias);\n+\t\treturn 0;\n+\t}\n+\n+\tswitch (help_format) {\n+\tcase HELP_FORMAT_MAN:\n+\t\tshow_man_page(argv[0]);\n+\t\tbreak;\n+\tcase HELP_FORMAT_INFO:\n+\t\tshow_info_page(argv[0]);\n+\t\tbreak;\n+\tcase HELP_FORMAT_WEB:\n+\t\tshow_html_page(argv[0]);\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\ndiff --git a/help.c b/help.c\nindex 968f368..1afbac0 100644\n--- a/help.c\n+++ b/help.c\n@@ -1,278 +1,8 @@\n-/*\n- * builtin-help.c\n- *\n- * Builtin help-related commands (help, usage, version)\n- */\n #include \"cache.h\"\n #include \"builtin.h\"\n #include \"exec_cmd.h\"\n-#include \"common-cmds.h\"\n-#include \"parse-options.h\"\n-#include \"run-command.h\"\n #include \"help.h\"\n \n-static struct man_viewer_list {\n-\tstruct man_viewer_list *next;\n-\tchar name[FLEX_ARRAY];\n-} *man_viewer_list;\n-\n-static struct man_viewer_info_list {\n-\tstruct man_viewer_info_list *next;\n-\tconst char *info;\n-\tchar name[FLEX_ARRAY];\n-} *man_viewer_info_list;\n-\n-enum help_format {\n-\tHELP_FORMAT_MAN,\n-\tHELP_FORMAT_INFO,\n-\tHELP_FORMAT_WEB,\n-};\n-\n-static int show_all = 0;\n-static enum help_format help_format = HELP_FORMAT_MAN;\n-static struct option builtin_help_options[] = {\n-\tOPT_BOOLEAN('a', \"all\", &show_all, \"print all available commands\"),\n-\tOPT_SET_INT('m', \"man\", &help_format, \"show man page\", HELP_FORMAT_MAN),\n-\tOPT_SET_INT('w', \"web\", &help_format, \"show manual in web browser\",\n-\t\t\tHELP_FORMAT_WEB),\n-\tOPT_SET_INT('i', \"info\", &help_format, \"show info page\",\n-\t\t\tHELP_FORMAT_INFO),\n-\tOPT_END(),\n-};\n-\n-static const char * const builtin_help_usage[] = {\n-\t\"git help [--all] [--man|--web|--info] [command]\",\n-\tNULL\n-};\n-\n-static enum help_format parse_help_format(const char *format)\n-{\n-\tif (!strcmp(format, \"man\"))\n-\t\treturn HELP_FORMAT_MAN;\n-\tif (!strcmp(format, \"info\"))\n-\t\treturn HELP_FORMAT_INFO;\n-\tif (!strcmp(format, \"web\") || !strcmp(format, \"html\"))\n-\t\treturn HELP_FORMAT_WEB;\n-\tdie(\"unrecognized help format '%s'\", format);\n-}\n-\n-static const char *get_man_viewer_info(const char *name)\n-{\n-\tstruct man_viewer_info_list *viewer;\n-\n-\tfor (viewer = man_viewer_info_list; viewer; viewer = viewer->next)\n-\t{\n-\t\tif (!strcasecmp(name, viewer->name))\n-\t\t\treturn viewer->info;\n-\t}\n-\treturn NULL;\n-}\n-\n-static int check_emacsclient_version(void)\n-{\n-\tstruct strbuf buffer = STRBUF_INIT;\n-\tstruct child_process ec_process;\n-\tconst char *argv_ec[] = { \"emacsclient\", \"--version\", NULL };\n-\tint version;\n-\n-\t/* emacsclient prints its version number on stderr */\n-\tmemset(&ec_process, 0, sizeof(ec_process));\n-\tec_process.argv = argv_ec;\n-\tec_process.err = -1;\n-\tec_process.stdout_to_stderr = 1;\n-\tif (start_command(&ec_process)) {\n-\t\tfprintf(stderr, \"Failed to start emacsclient.\\n\");\n-\t\treturn -1;\n-\t}\n-\tstrbuf_read(&buffer, ec_process.err, 20);\n-\tclose(ec_process.err);\n-\n-\t/*\n-\t * Don't bother checking return value, because \"emacsclient --version\"\n-\t * seems to always exits with code 1.\n-\t */\n-\tfinish_command(&ec_process);\n-\n-\tif (prefixcmp(buffer.buf, \"emacsclient\")) {\n-\t\tfprintf(stderr, \"Failed to parse emacsclient version.\\n\");\n-\t\tstrbuf_release(&buffer);\n-\t\treturn -1;\n-\t}\n-\n-\tstrbuf_remove(&buffer, 0, strlen(\"emacsclient\"));\n-\tversion = atoi(buffer.buf);\n-\n-\tif (version < 22) {\n-\t\tfprintf(stderr,\n-\t\t\t\"emacsclient version '%d' too old (< 22).\\n\",\n-\t\t\tversion);\n-\t\tstrbuf_release(&buffer);\n-\t\treturn -1;\n-\t}\n-\n-\tstrbuf_release(&buffer);\n-\treturn 0;\n-}\n-\n-static void exec_woman_emacs(const char* path, const char *page)\n-{\n-\tif (!check_emacsclient_version()) {\n-\t\t/* This works only with emacsclient version >= 22. */\n-\t\tstruct strbuf man_page = STRBUF_INIT;\n-\n-\t\tif (!path)\n-\t\t\tpath = \"emacsclient\";\n-\t\tstrbuf_addf(&man_page, \"(woman \\\"%s\\\")\", page);\n-\t\texeclp(path, \"emacsclient\", \"-e\", man_page.buf, NULL);\n-\t\twarning(\"failed to exec '%s': %s\", path, strerror(errno));\n-\t}\n-}\n-\n-static void exec_man_konqueror(const char* path, const char *page)\n-{\n-\tconst char *display = getenv(\"DISPLAY\");\n-\tif (display && *display) {\n-\t\tstruct strbuf man_page = STRBUF_INIT;\n-\t\tconst char *filename = \"kfmclient\";\n-\n-\t\t/* It's simpler to launch konqueror using kfmclient. */\n-\t\tif (path) {\n-\t\t\tconst char *file = strrchr(path, '/');\n-\t\t\tif (file && !strcmp(file + 1, \"konqueror\")) {\n-\t\t\t\tchar *new = xstrdup(path);\n-\t\t\t\tchar *dest = strrchr(new, '/');\n-\n-\t\t\t\t/* strlen(\"konqueror\") == strlen(\"kfmclient\") */\n-\t\t\t\tstrcpy(dest + 1, \"kfmclient\");\n-\t\t\t\tpath = new;\n-\t\t\t}\n-\t\t\tif (file)\n-\t\t\t\tfilename = file;\n-\t\t} else\n-\t\t\tpath = \"kfmclient\";\n-\t\tstrbuf_addf(&man_page, \"man:%s(1)\", page);\n-\t\texeclp(path, filename, \"newTab\", man_page.buf, NULL);\n-\t\twarning(\"failed to exec '%s': %s\", path, strerror(errno));\n-\t}\n-}\n-\n-static void exec_man_man(const char* path, const char *page)\n-{\n-\tif (!path)\n-\t\tpath = \"man\";\n-\texeclp(path, \"man\", page, NULL);\n-\twarning(\"failed to exec '%s': %s\", path, strerror(errno));\n-}\n-\n-static void exec_man_cmd(const char *cmd, const char *page)\n-{\n-\tstruct strbuf shell_cmd = STRBUF_INIT;\n-\tstrbuf_addf(&shell_cmd, \"%s %s\", cmd, page);\n-\texecl(\"/bin/sh\", \"sh\", \"-c\", shell_cmd.buf, NULL);\n-\twarning(\"failed to exec '%s': %s\", cmd, strerror(errno));\n-}\n-\n-static void add_man_viewer(const char *name)\n-{\n-\tstruct man_viewer_list **p = &man_viewer_list;\n-\tsize_t len = strlen(name);\n-\n-\twhile (*p)\n-\t\tp = &((*p)->next);\n-\t*p = xcalloc(1, (sizeof(**p) + len + 1));\n-\tstrncpy((*p)->name, name, len);\n-}\n-\n-static int supported_man_viewer(const char *name, size_t len)\n-{\n-\treturn (!strncasecmp(\"man\", name, len) ||\n-\t\t!strncasecmp(\"woman\", name, len) ||\n-\t\t!strncasecmp(\"konqueror\", name, len));\n-}\n-\n-static void do_add_man_viewer_info(const char *name,\n-\t\t\t\t   size_t len,\n-\t\t\t\t   const char *value)\n-{\n-\tstruct man_viewer_info_list *new = xcalloc(1, sizeof(*new) + len + 1);\n-\n-\tstrncpy(new->name, name, len);\n-\tnew->info = xstrdup(value);\n-\tnew->next = man_viewer_info_list;\n-\tman_viewer_info_list = new;\n-}\n-\n-static int add_man_viewer_path(const char *name,\n-\t\t\t       size_t len,\n-\t\t\t       const char *value)\n-{\n-\tif (supported_man_viewer(name, len))\n-\t\tdo_add_man_viewer_info(name, len, value);\n-\telse\n-\t\twarning(\"'%s': path for unsupported man viewer.\\n\"\n-\t\t\t\"Please consider using 'man.<tool>.cmd' instead.\",\n-\t\t\tname);\n-\n-\treturn 0;\n-}\n-\n-static int add_man_viewer_cmd(const char *name,\n-\t\t\t      size_t len,\n-\t\t\t      const char *value)\n-{\n-\tif (supported_man_viewer(name, len))\n-\t\twarning(\"'%s': cmd for supported man viewer.\\n\"\n-\t\t\t\"Please consider using 'man.<tool>.path' instead.\",\n-\t\t\tname);\n-\telse\n-\t\tdo_add_man_viewer_info(name, len, value);\n-\n-\treturn 0;\n-}\n-\n-static int add_man_viewer_info(const char *var, const char *value)\n-{\n-\tconst char *name = var + 4;\n-\tconst char *subkey = strrchr(name, '.');\n-\n-\tif (!subkey)\n-\t\treturn error(\"Config with no key for man viewer: %s\", name);\n-\n-\tif (!strcmp(subkey, \".path\")) {\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\treturn add_man_viewer_path(name, subkey - name, value);\n-\t}\n-\tif (!strcmp(subkey, \".cmd\")) {\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\treturn add_man_viewer_cmd(name, subkey - name, value);\n-\t}\n-\n-\twarning(\"'%s': unsupported man viewer sub key.\", subkey);\n-\treturn 0;\n-}\n-\n-static int git_help_config(const char *var, const char *value, void *cb)\n-{\n-\tif (!strcmp(var, \"help.format\")) {\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\thelp_format = parse_help_format(value);\n-\t\treturn 0;\n-\t}\n-\tif (!strcmp(var, \"man.viewer\")) {\n-\t\tif (!value)\n-\t\t\treturn config_error_nonbool(var);\n-\t\tadd_man_viewer(value);\n-\t\treturn 0;\n-\t}\n-\tif (!prefixcmp(var, \"man.\"))\n-\t\treturn add_man_viewer_info(var, value);\n-\n-\treturn git_default_config(var, value, cb);\n-}\n-\n /* most GUI terminals set COLUMNS (although some don't export it) */\n static int term_columns(void)\n {\n@@ -295,14 +25,6 @@ static int term_columns(void)\n \treturn 80;\n }\n \n-static inline void mput_char(char c, unsigned int num)\n-{\n-\twhile(num--)\n-\t\tputchar(c);\n-}\n-\n-struct cmdnames main_cmds, other_cmds;\n-\n void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n {\n \tstruct cmdname *ent = xmalloc(sizeof(*ent) + len + 1);\n@@ -526,23 +248,6 @@ void list_commands(const char *title, unsigned int longest,\n \t}\n }\n \n-void list_common_cmds_help(void)\n-{\n-\tint i, longest = 0;\n-\n-\tfor (i = 0; i < ARRAY_SIZE(common_cmds); i++) {\n-\t\tif (longest < strlen(common_cmds[i].name))\n-\t\t\tlongest = strlen(common_cmds[i].name);\n-\t}\n-\n-\tputs(\"The most commonly used git commands are:\");\n-\tfor (i = 0; i < ARRAY_SIZE(common_cmds); i++) {\n-\t\tprintf(\"   %s   \", common_cmds[i].name);\n-\t\tmput_char(' ', longest - strlen(common_cmds[i].name));\n-\t\tputs(common_cmds[i].help);\n-\t}\n-}\n-\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\n@@ -552,128 +257,6 @@ int is_in_cmdlist(struct cmdnames *c, const char *s)\n \treturn 0;\n }\n \n-static int is_git_command(const char *s)\n-{\n-\treturn is_in_cmdlist(&main_cmds, s) ||\n-\t\tis_in_cmdlist(&other_cmds, s);\n-}\n-\n-static const char *prepend(const char *prefix, const char *cmd)\n-{\n-\tsize_t pre_len = strlen(prefix);\n-\tsize_t cmd_len = strlen(cmd);\n-\tchar *p = xmalloc(pre_len + cmd_len + 1);\n-\tmemcpy(p, prefix, pre_len);\n-\tstrcpy(p + pre_len, cmd);\n-\treturn p;\n-}\n-\n-static const char *cmd_to_page(const char *git_cmd)\n-{\n-\tif (!git_cmd)\n-\t\treturn \"git\";\n-\telse if (!prefixcmp(git_cmd, \"git\"))\n-\t\treturn git_cmd;\n-\telse if (is_git_command(git_cmd))\n-\t\treturn prepend(\"git-\", git_cmd);\n-\telse\n-\t\treturn prepend(\"git\", git_cmd);\n-}\n-\n-static void setup_man_path(void)\n-{\n-\tstruct strbuf new_path;\n-\tconst char *old_path = getenv(\"MANPATH\");\n-\n-\tstrbuf_init(&new_path, 0);\n-\n-\t/* We should always put ':' after our path. If there is no\n-\t * old_path, the ':' at the end will let 'man' to try\n-\t * system-wide paths after ours to find the manual page. If\n-\t * there is old_path, we need ':' as delimiter. */\n-\tstrbuf_addstr(&new_path, GIT_MAN_PATH);\n-\tstrbuf_addch(&new_path, ':');\n-\tif (old_path)\n-\t\tstrbuf_addstr(&new_path, old_path);\n-\n-\tsetenv(\"MANPATH\", new_path.buf, 1);\n-\n-\tstrbuf_release(&new_path);\n-}\n-\n-static void exec_viewer(const char *name, const char *page)\n-{\n-\tconst char *info = get_man_viewer_info(name);\n-\n-\tif (!strcasecmp(name, \"man\"))\n-\t\texec_man_man(info, page);\n-\telse if (!strcasecmp(name, \"woman\"))\n-\t\texec_woman_emacs(info, page);\n-\telse if (!strcasecmp(name, \"konqueror\"))\n-\t\texec_man_konqueror(info, page);\n-\telse if (info)\n-\t\texec_man_cmd(info, page);\n-\telse\n-\t\twarning(\"'%s': unknown man viewer.\", name);\n-}\n-\n-static void show_man_page(const char *git_cmd)\n-{\n-\tstruct man_viewer_list *viewer;\n-\tconst char *page = cmd_to_page(git_cmd);\n-\n-\tsetup_man_path();\n-\tfor (viewer = man_viewer_list; viewer; viewer = viewer->next)\n-\t{\n-\t\texec_viewer(viewer->name, page); /* will return when unable */\n-\t}\n-\texec_viewer(\"man\", page);\n-\tdie(\"no man viewer handled the request\");\n-}\n-\n-static void show_info_page(const char *git_cmd)\n-{\n-\tconst char *page = cmd_to_page(git_cmd);\n-\tsetenv(\"INFOPATH\", GIT_INFO_PATH, 1);\n-\texeclp(\"info\", \"info\", \"gitman\", page, NULL);\n-}\n-\n-static void get_html_page_path(struct strbuf *page_path, const char *page)\n-{\n-\tstruct stat st;\n-\tconst char *html_path = system_path(GIT_HTML_PATH);\n-\n-\t/* Check that we have a git documentation directory. */\n-\tif (stat(mkpath(\"%s/git.html\", html_path), &st)\n-\t    || !S_ISREG(st.st_mode))\n-\t\tdie(\"'%s': not a documentation directory.\", html_path);\n-\n-\tstrbuf_init(page_path, 0);\n-\tstrbuf_addf(page_path, \"%s/%s.html\", html_path, page);\n-}\n-\n-/*\n- * If open_html is not defined in a platform-specific way (see for\n- * example compat/mingw.h), we use the script web--browse to display\n- * HTML.\n- */\n-#ifndef open_html\n-void open_html(const char *path)\n-{\n-\texecl_git_cmd(\"web--browse\", \"-c\", \"help.browser\", path, NULL);\n-}\n-#endif\n-\n-static void show_html_page(const char *git_cmd)\n-{\n-\tconst char *page = cmd_to_page(git_cmd);\n-\tstruct strbuf page_path; /* it leaks but we exec bellow */\n-\n-\tget_html_page_path(&page_path, page);\n-\n-\topen_html(page_path.buf);\n-}\n-\n void help_unknown_cmd(const char *cmd)\n {\n \tfprintf(stderr, \"git: '%s' is not a git-command. See 'git --help'.\\n\", cmd);\n@@ -685,50 +268,3 @@ int cmd_version(int argc, const char **argv, const char *prefix)\n \tprintf(\"git version %s\\n\", git_version_string);\n \treturn 0;\n }\n-\n-int cmd_help(int argc, const char **argv, const char *prefix)\n-{\n-\tint nongit;\n-\tconst char *alias;\n-\tunsigned int longest = load_command_list(\"git-\", &main_cmds, &other_cmds);\n-\n-\tsetup_git_directory_gently(&nongit);\n-\tgit_config(git_help_config, NULL);\n-\n-\targc = parse_options(argc, argv, builtin_help_options,\n-\t\t\tbuiltin_help_usage, 0);\n-\n-\tif (show_all) {\n-\t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n-\t\tlist_commands(\"git commands\", longest, &main_cmds, &other_cmds);\n-\t\tprintf(\"%s\\n\", git_more_info_string);\n-\t\treturn 0;\n-\t}\n-\n-\tif (!argv[0]) {\n-\t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n-\t\tlist_common_cmds_help();\n-\t\tprintf(\"\\n%s\\n\", git_more_info_string);\n-\t\treturn 0;\n-\t}\n-\n-\talias = alias_lookup(argv[0]);\n-\tif (alias && !is_git_command(argv[0])) {\n-\t\tprintf(\"`git %s' is aliased to `%s'\\n\", argv[0], alias);\n-\t\treturn 0;\n-\t}\n-\n-\tswitch (help_format) {\n-\tcase HELP_FORMAT_MAN:\n-\t\tshow_man_page(argv[0]);\n-\t\tbreak;\n-\tcase HELP_FORMAT_INFO:\n-\t\tshow_info_page(argv[0]);\n-\t\tbreak;\n-\tcase HELP_FORMAT_WEB:\n-\t\tshow_html_page(argv[0]);\n-\t\tbreak;\n-\t}\n-\n-\treturn 0;\n-}\ndiff --git a/help.h b/help.h\nindex d614e54..3f1ae89 100644\n--- a/help.h\n+++ b/help.h\n@@ -10,6 +10,12 @@ struct cmdnames {\n \t} **names;\n };\n \n+static inline void mput_char(char c, unsigned int num)\n+{\n+\twhile(num--)\n+\t\tputchar(c);\n+}\n+\n unsigned int load_command_list(const char *prefix,\n \t\tstruct cmdnames *main_cmds,\n \t\tstruct cmdnames *other_cmds);\n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"87923","messageId":"200808210451.12795.chriscool@tuxfamily.org","threadId":"14766","inReplyTo":"20080801144121.GU32057@genesis.frugalware.org","subject":"Re: git help broken","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2008-08-21T02:51:11Z","receivedAt":"2008-08-21T02:51:11Z","isPatch":false,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Le vendredi 1 août 2008, Miklos Vajna a écrit :\n> On Fri, Aug 01, 2008 at 06:28:52AM +0200, Christian Couder \n<chriscool@tuxfamily.org> wrote:\n> > I didn't realize that the function \"is_git_command\" would not work\n> > for \"help\".\n>\n> Is there any reason why help is not a builtin? I think that would solve\n> the problem.\n>\n> I'm willing to do such a patch, I just asked in case that would be\n> no-go for some - for me - unknown reason.\n\nSorry I didn't answer before. I was really busy during my vacation ;-P\n\nI think you are right, and in \"next\" where your patch has been merged, \"git \nhelp help\" works fine.\n\nBut unfortunately it seems that your patch hasn't been merged into master, \nso \"git help help\" is still broken there and in git 1.6.0.\n\nThanks,\nChristian.\n"},{"id":"87986","messageId":"1219328508-11561-1-git-send-email-vmiklos@frugalware.org","threadId":"14766","inReplyTo":"200808210451.12795.chriscool@tuxfamily.org","subject":"[PATCH] Fix 'git help help'","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-08-21T14:21:48Z","receivedAt":"2008-08-21T14:21:48Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"git help foo invokes man git-foo if foo is a git command, otherwise it\ninvokes man gitfoo. 'help' is not a git command, but the manual page is\ncalled git-help, so add this special exception.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n\nOn Thu, Aug 21, 2008 at 04:51:11AM +0200, Christian Couder <chriscool@tuxfamily.org> wrote:\n> But unfortunately it seems that your patch hasn't been merged into\n> master,\n> so \"git help help\" is still broken there and in git 1.6.0.\n\nHere is a patch for 'maint'.\n\n help.c |    3 ++-\n 1 files changed, 2 insertions(+), 1 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex 3cb1962..dc0786d 100644\n--- a/help.c\n+++ b/help.c\n@@ -555,7 +555,8 @@ static int is_git_command(const char *s)\n {\n \tload_command_list();\n \treturn is_in_cmdlist(&main_cmds, s) ||\n-\t\tis_in_cmdlist(&other_cmds, s);\n+\t\tis_in_cmdlist(&other_cmds, s) ||\n+\t\t!strcmp(s, \"help\");\n }\n \n static const char *prepend(const char *prefix, const char *cmd)\n-- \n1.6.0.rc3.17.gc14c8.dirty\n"},{"id":"88084","messageId":"200808220640.10993.chriscool@tuxfamily.org","threadId":"14766","inReplyTo":"1219328508-11561-1-git-send-email-vmiklos@frugalware.org","subject":"Re: [PATCH] Fix 'git help help'","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2008-08-22T04:40:09Z","receivedAt":"2008-08-22T04:40:09Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Le jeudi 21 août 2008, Miklos Vajna a écrit :\n> git help foo invokes man git-foo if foo is a git command, otherwise it\n> invokes man gitfoo. 'help' is not a git command, but the manual page is\n> called git-help, so add this special exception.\n>\n> Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>\n\nAcked-by: Christian Couder <chriscool@tuxfamily.org>\n\n> ---\n>\n> On Thu, Aug 21, 2008 at 04:51:11AM +0200, Christian Couder \n<chriscool@tuxfamily.org> wrote:\n> > But unfortunately it seems that your patch hasn't been merged into\n> > master,\n> > so \"git help help\" is still broken there and in git 1.6.0.\n>\n> Here is a patch for 'maint'.\n\nIt works fine.\n\nThanks,\nChristian.\n"}]}