{"thread":{"id":"48155","subject":"[PATCH/RFC 0/5] Keep all info in command-list.txt in git binary","startedAt":"2018-03-26T16:56:11Z","lastAt":"2018-05-13T06:50:42Z","messageCount":137,"participants":["Nguyễn Thái Ngọc Duy","Eric Sunshine","Junio C Hamano","Duy Nguyen","Philip Oakley","SZEDER Gábor","Ramsay Jones","Simon Ruderich","Øystein Walle"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"343018","messageId":"20180326165520.802-1-pclouds@gmail.com","threadId":"48155","inReplyTo":null,"subject":"[PATCH/RFC 0/5] Keep all info in command-list.txt in git binary","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-03-26T16:55:15Z","receivedAt":"2018-03-26T16:56:11Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is pretty rough but I'd like to see how people feel about this\nfirst.\n\nI notice we have two places for command classification. One in\ncommand-list.txt, one in __git_list_porcelain_commands() in\ngit-completion.bash. People who are following nd/parseopt-completion\nprobably know that I'm try to reduce duplication in this script as\nmuch as possible, this is another step towards that.\n\nBy keeping all information of command-list.txt in git binary, we could\nprovide the porcelain list to git-completion.bash via \"git\n--list-cmds=porcelain\", so we don't neeed a separate command\nclassification in git-completion.bash anymore.\n\nBecause we have all command synopsis as a side effect, we could\nnow support \"git help -a --verbose\" which prints something like \"git\nhelp\", a command name and a description, but we could do it for _all_\nrecognized commands. This could help people look for a command even if\nwe don't provide \"git appropos\".\n\nPS. Elsewhere I introduced --list-builtin-cmds, which should become\n--list-cmds=builtin if this series seems like a good idea to move\nforward.\n\nNguyễn Thái Ngọc Duy (5):\n  git.c: convert --list-builtins to --list-cmds=builtins\n  git.c: implement --list-cmds=all and use it in git-completion.bash\n  generate-cmdlist.sh: keep all information in common-cmds.h\n  git.c: implement --list-cmds=porcelain\n  help: add \"-a --verbose\" to list all commands with synopsis\n\n Documentation/git-help.txt             |   4 +-\n builtin/help.c                         |   6 ++\n contrib/completion/git-completion.bash |  94 +-----------------\n generate-cmdlist.sh                    |  46 ++++++---\n git.c                                  |  11 ++-\n help.c                                 | 131 +++++++++++++++++++++++--\n help.h                                 |   3 +\n t/t0012-help.sh                        |   2 +-\n t/t9902-completion.sh                  |   4 +-\n 9 files changed, 187 insertions(+), 114 deletions(-)\n\n-- \n2.17.0.rc0.348.gd5a49e0b6f\n\n"},{"id":"343019","messageId":"20180326165520.802-3-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180326165520.802-1-pclouds@gmail.com","subject":"[PATCH/RFC 2/5] git.c: implement --list-cmds=all and use it in git-completion.bash","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-03-26T16:55:17Z","receivedAt":"2018-03-26T16:56:14Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash |  2 +-\n git.c                                  |  2 ++\n help.c                                 | 15 +++++++++++++++\n help.h                                 |  1 +\n 4 files changed, 19 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex c7957f0a90..e0f545819d 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -833,7 +833,7 @@ __git_commands () {\n \tthen\n \t\tprintf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n \telse\n-\t\tgit help -a|egrep '^  [a-zA-Z0-9]'\n+\t\tgit --list-cmds=all\n \tfi\n }\n \ndiff --git a/git.c b/git.c\nindex f350002260..2e0c5e17e2 100644\n--- a/git.c\n+++ b/git.c\n@@ -208,6 +208,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t} else if (skip_prefix(cmd, \"--list-cmds=\", &cmd)) {\n \t\t\tif (!strcmp(cmd, \"builtins\"))\n \t\t\t\tlist_builtins();\n+\t\t\telse if (!strcmp(cmd, \"all\"))\n+\t\t\t\tlist_all_cmds();\n \t\t\telse\n \t\t\t\tdie(\"unsupported command listing type '%s'\", cmd);\n \t\t\texit(0);\ndiff --git a/help.c b/help.c\nindex 60071a9bea..f3f35dfbb1 100644\n--- a/help.c\n+++ b/help.c\n@@ -228,6 +228,21 @@ void list_common_cmds_help(void)\n \t}\n }\n \n+void list_all_cmds(void)\n+{\n+\tstruct cmdnames main_cmds, other_cmds;\n+\tint i;\n+\n+\tmemset(&main_cmds, 0, sizeof(main_cmds));\n+\tmemset(&other_cmds, 0, sizeof(other_cmds));\n+\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n+\n+\tfor (i = 0; i < main_cmds.cnt; i++)\n+\t\tputs(main_cmds.names[i]->name);\n+\tfor (i = 0; i < other_cmds.cnt; i++)\n+\t\tputs(other_cmds.names[i]->name);\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex b21d7c94e8..0bf29f8dc5 100644\n--- a/help.h\n+++ b/help.h\n@@ -17,6 +17,7 @@ static inline void mput_char(char c, unsigned int num)\n }\n \n extern void list_common_cmds_help(void);\n+extern void list_all_cmds(void);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\n-- \n2.17.0.rc0.348.gd5a49e0b6f\n\n"},{"id":"343020","messageId":"20180326165520.802-2-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180326165520.802-1-pclouds@gmail.com","subject":"[PATCH/RFC 1/5] git.c: convert --list-builtins to --list-cmds=builtins","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-03-26T16:55:16Z","receivedAt":"2018-03-26T16:56:15Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Even if this is a hidden option, let's make it a bit more generic\nsince we're introducing more listing types.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n git.c           | 7 +++++--\n t/t0012-help.sh | 2 +-\n 2 files changed, 6 insertions(+), 3 deletions(-)\n\ndiff --git a/git.c b/git.c\nindex ceaa58ef40..f350002260 100644\n--- a/git.c\n+++ b/git.c\n@@ -205,8 +205,11 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t}\n \t\t\t(*argv)++;\n \t\t\t(*argc)--;\n-\t\t} else if (!strcmp(cmd, \"--list-builtins\")) {\n-\t\t\tlist_builtins();\n+\t\t} else if (skip_prefix(cmd, \"--list-cmds=\", &cmd)) {\n+\t\t\tif (!strcmp(cmd, \"builtins\"))\n+\t\t\t\tlist_builtins();\n+\t\t\telse\n+\t\t\t\tdie(\"unsupported command listing type '%s'\", cmd);\n \t\t\texit(0);\n \t\t} else {\n \t\t\tfprintf(stderr, _(\"unknown option: %s\\n\"), cmd);\ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex 487b92a5de..fd2a7f27dc 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -50,7 +50,7 @@ test_expect_success \"--help does not work for guides\" \"\n \"\n \n test_expect_success 'generate builtin list' '\n-\tgit --list-builtins >builtins\n+\tgit --list-cmds=builtins >builtins\n '\n \n while read builtin\n-- \n2.17.0.rc0.348.gd5a49e0b6f\n\n"},{"id":"343021","messageId":"20180326165520.802-4-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180326165520.802-1-pclouds@gmail.com","subject":"[PATCH/RFC 3/5] generate-cmdlist.sh: keep all information in common-cmds.h","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-03-26T16:55:18Z","receivedAt":"2018-03-26T16:56:18Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"common-cmds.h is used to extract the list of common commands (by\ngroup) and a one-line summary of each command. Some information is\ndropped, for example command category or summary of other commands.\nUpdate generate-cmdlist.sh to keep all the information. The extra info\nwill be used shortly.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n generate-cmdlist.sh | 46 ++++++++++++++++++++++++++++++++++-----------\n help.c              | 43 ++++++++++++++++++++++++++++++++++++------\n 2 files changed, 72 insertions(+), 17 deletions(-)\n\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex eeea4b67ea..72235e7296 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -2,9 +2,10 @@\n \n echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n-\tchar name[16];\n+\tchar name[32];\n \tchar help[80];\n-\tunsigned char group;\n+\tunsigned int category;\n+\tunsigned int group;\n };\n \n static const char *common_cmd_groups[] = {\"\n@@ -23,27 +24,50 @@ sed -n '\n \t' \"$1\"\n printf '};\\n\\n'\n \n+echo \"#define GROUP_NONE 0xff /* no common group */\"\n+echo \"#define GROUP_ 0xff /* no common group */\"\n n=0\n-substnum=\n while read grp\n do\n-\techo \"^git-..*[ \t]$grp\"\n-\tsubstnum=\"$substnum${substnum:+;}s/[ \t]$grp/$n/\"\n+\techo \"#define GROUP_$grp $n\"\n \tn=$(($n+1))\n-done <\"$grps\" >\"$match\"\n+done <\"$grps\"\n+echo\n \n-printf 'static struct cmdname_help common_cmds[] = {\\n'\n-grep -f \"$match\" \"$1\" |\n+echo '/*'\n+printf 'static const char *cmd_categories[] = {\\n'\n+grep '^git-' \"$1\" |\n+awk '{print $2;}' |\n+sort |\n+uniq |\n+while read category; do\n+\tprintf '\\t\\\"'$category'\\\",\\n'\n+done\n+printf '\\tNULL\\n};\\n\\n'\n+echo '*/'\n+\n+n=0\n+grep '^git-' \"$1\" |\n+awk '{print $2;}' |\n+sort |\n+uniq |\n+while read category; do\n+\techo \"#define CAT_$category $n\"\n+\tn=$(($n+1))\n+done\n+echo\n+\n+printf 'static struct cmdname_help command_list[] = {\\n'\n+grep \"^git-\" \"$1\" |\n sed 's/^git-//' |\n sort |\n-while read cmd tags\n+while read cmd category tags\n do\n-\ttag=$(echo \"$tags\" | sed \"$substnum; s/[^0-9]//g\")\n \tsed -n '\n \t\t/^NAME/,/git-'\"$cmd\"'/H\n \t\t${\n \t\t\tx\n-\t\t\ts/.*git-'\"$cmd\"' - \\(.*\\)/\t{\"'\"$cmd\"'\", N_(\"\\1\"), '$tag'},/\n+\t\t\ts/.*git-'\"$cmd\"' - \\(.*\\)/\t{\"'\"$cmd\"'\", N_(\"\\1\"), CAT_'$category', GROUP_'$tags' },/\n \t\t\tp\n \t\t}' \"Documentation/git-$cmd.txt\"\n done\ndiff --git a/help.c b/help.c\nindex f3f35dfbb1..4d07ea3913 100644\n--- a/help.c\n+++ b/help.c\n@@ -190,6 +190,28 @@ void list_commands(unsigned int colopts,\n \t}\n }\n \n+static void extract_common_cmds(struct cmdname_help **p_common_cmds,\n+\t\t\t\tint *p_nr)\n+{\n+\tint i, nr = 0;\n+\tstruct cmdname_help *common_cmds;\n+\n+\tALLOC_ARRAY(common_cmds, ARRAY_SIZE(command_list));\n+\n+\tfor (i = 0; i < ARRAY_SIZE(command_list); i++) {\n+\t\tconst struct cmdname_help *cmd = command_list + i;\n+\n+\t\tif (cmd->category != CAT_mainporcelain ||\n+\t\t    cmd->group == GROUP_NONE)\n+\t\t\tcontinue;\n+\n+\t\tcommon_cmds[nr++] = *cmd;\n+\t}\n+\n+\t*p_common_cmds = common_cmds;\n+\t*p_nr = nr;\n+}\n+\n static int cmd_group_cmp(const void *elem1, const void *elem2)\n {\n \tconst struct cmdname_help *e1 = elem1;\n@@ -206,17 +228,21 @@ void list_common_cmds_help(void)\n {\n \tint i, longest = 0;\n \tint current_grp = -1;\n+\tint nr = 0;\n+\tstruct cmdname_help *common_cmds;\n+\n+\textract_common_cmds(&common_cmds, &nr);\n \n-\tfor (i = 0; i < ARRAY_SIZE(common_cmds); i++) {\n+\tfor (i = 0; i < nr; i++) {\n \t\tif (longest < strlen(common_cmds[i].name))\n \t\t\tlongest = strlen(common_cmds[i].name);\n \t}\n \n-\tQSORT(common_cmds, ARRAY_SIZE(common_cmds), cmd_group_cmp);\n+\tQSORT(common_cmds, nr, cmd_group_cmp);\n \n \tputs(_(\"These are common Git commands used in various situations:\"));\n \n-\tfor (i = 0; i < ARRAY_SIZE(common_cmds); i++) {\n+\tfor (i = 0; i < nr; i++) {\n \t\tif (common_cmds[i].group != current_grp) {\n \t\t\tprintf(\"\\n%s\\n\", _(common_cmd_groups[common_cmds[i].group]));\n \t\t\tcurrent_grp = common_cmds[i].group;\n@@ -226,6 +252,7 @@ void list_common_cmds_help(void)\n \t\tmput_char(' ', longest - strlen(common_cmds[i].name));\n \t\tputs(_(common_cmds[i].help));\n \t}\n+\tfree(common_cmds);\n }\n \n void list_all_cmds(void)\n@@ -298,8 +325,9 @@ static const char bad_interpreter_advice[] =\n \n const char *help_unknown_cmd(const char *cmd)\n {\n-\tint i, n, best_similarity = 0;\n+\tint i, n, best_similarity = 0, nr_common;\n \tstruct cmdnames main_cmds, other_cmds;\n+\tstruct cmdname_help *common_cmds;\n \n \tmemset(&main_cmds, 0, sizeof(main_cmds));\n \tmemset(&other_cmds, 0, sizeof(other_cmds));\n@@ -314,6 +342,8 @@ const char *help_unknown_cmd(const char *cmd)\n \tQSORT(main_cmds.names, main_cmds.cnt, cmdname_compare);\n \tuniq(&main_cmds);\n \n+\textract_common_cmds(&common_cmds, &nr_common);\n+\n \t/* This abuses cmdname->len for levenshtein distance */\n \tfor (i = 0, n = 0; i < main_cmds.cnt; i++) {\n \t\tint cmp = 0; /* avoid compiler stupidity */\n@@ -328,10 +358,10 @@ const char *help_unknown_cmd(const char *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\twhile (n < nr_common &&\n \t\t       (cmp = strcmp(common_cmds[n].name, candidate)) < 0)\n \t\t\tn++;\n-\t\tif ((n < ARRAY_SIZE(common_cmds)) && !cmp) {\n+\t\tif ((n < nr_common) && !cmp) {\n \t\t\t/* Yes, this is one of the common commands */\n \t\t\tn++; /* use the entry from common_cmds[] */\n \t\t\tif (starts_with(candidate, cmd)) {\n@@ -344,6 +374,7 @@ const char *help_unknown_cmd(const char *cmd)\n \t\tmain_cmds.names[i]->len =\n \t\t\tlevenshtein(cmd, candidate, 0, 2, 1, 3) + 1;\n \t}\n+\tFREE_AND_NULL(common_cmds);\n \n \tQSORT(main_cmds.names, main_cmds.cnt, levenshtein_compare);\n \n-- \n2.17.0.rc0.348.gd5a49e0b6f\n\n"},{"id":"343022","messageId":"20180326165520.802-6-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180326165520.802-1-pclouds@gmail.com","subject":"[PATCH/RFC 5/5] help: add \"-a --verbose\" to list all commands with synopsis","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-03-26T16:55:20Z","receivedAt":"2018-03-26T16:56:22Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-help.txt |  4 ++-\n builtin/help.c             |  6 ++++\n help.c                     | 61 ++++++++++++++++++++++++++++++++++++++\n help.h                     |  1 +\n 4 files changed, 71 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-help.txt b/Documentation/git-help.txt\nindex 40d328a4b3..a40fc38d8b 100644\n--- a/Documentation/git-help.txt\n+++ b/Documentation/git-help.txt\n@@ -8,7 +8,7 @@ git-help - Display help information about Git\n SYNOPSIS\n --------\n [verse]\n-'git help' [-a|--all] [-g|--guide]\n+'git help' [-a|--all [--verbose]] [-g|--guide]\n \t   [-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE]\n \n DESCRIPTION\n@@ -42,6 +42,8 @@ OPTIONS\n --all::\n \tPrints all the available commands on the standard output. This\n \toption overrides any given command or guide name.\n+\tWhen used with `--verbose` print description for all recognized\n+\tcommands.\n \n -g::\n --guides::\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 598867cfea..a371199674 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -36,6 +36,7 @@ static const char *html_path;\n \n static int show_all = 0;\n static int show_guides = 0;\n+static int verbose;\n static unsigned int colopts;\n static enum help_format help_format = HELP_FORMAT_NONE;\n static int exclude_guides;\n@@ -48,6 +49,7 @@ static struct option builtin_help_options[] = {\n \t\t\tHELP_FORMAT_WEB),\n \tOPT_SET_INT('i', \"info\", &help_format, N_(\"show info page\"),\n \t\t\tHELP_FORMAT_INFO),\n+\tOPT__VERBOSE(&verbose, N_(\"print command description\")),\n \tOPT_END(),\n };\n \n@@ -463,6 +465,10 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \tif (show_all) {\n \t\tgit_config(git_help_config, NULL);\n+\t\tif (verbose) {\n+\t\t\tlist_all_cmds_help();\n+\t\t\treturn 0;\n+\t\t}\n \t\tprintf(_(\"usage: %s%s\"), _(git_usage_string), \"\\n\\n\");\n \t\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n \t\tlist_commands(colopts, &main_cmds, &other_cmds);\ndiff --git a/help.c b/help.c\nindex cacd8249bb..afbf98c241 100644\n--- a/help.c\n+++ b/help.c\n@@ -282,6 +282,67 @@ void list_porcelain_cmds(void)\n \t}\n }\n \n+static int cmd_category_cmp(const void *elem1, const void *elem2)\n+{\n+\tconst struct cmdname_help *e1 = elem1;\n+\tconst struct cmdname_help *e2 = elem2;\n+\n+\tif (e1->category < e2->category)\n+\t\treturn -1;\n+\tif (e1->category > e2->category)\n+\t\treturn 1;\n+\treturn strcmp(e1->name, e2->name);\n+}\n+\n+static const char *get_category_name(unsigned int category)\n+{\n+\tswitch (category) {\n+\tcase CAT_ancillaryinterrogators: return _(\"Ancillary interrogators\");\n+\tcase CAT_ancillarymanipulators: return _(\"Ancillary manipulators\");\n+\tcase CAT_foreignscminterface: return _(\"Foreign SCM interface\");\n+\tcase CAT_mainporcelain: return _(\"Main porcelain\");\n+\tcase CAT_plumbinginterrogators: return _(\"Plumbing interrogators\");\n+\tcase CAT_plumbingmanipulators: return _(\"Plumbing interrogators\");\n+\tcase CAT_purehelpers: return _(\"Pure helpers\");\n+\tcase CAT_synchelpers: return _(\"Sync helpers\");\n+\tcase CAT_synchingrepositories: return _(\"Synching repositories\");\n+\tdefault:\n+\t\tdie(\"BUG: unknown command category %u\", category);\n+\t}\n+}\n+\n+void list_all_cmds_help(void)\n+{\n+\tint i, longest = 0;\n+\tint current_category = -1;\n+\tint nr = ARRAY_SIZE(command_list);\n+\tstruct cmdname_help *cmds = command_list;\n+\n+\tfor (i = 0; i < nr; i++) {\n+\t\tstruct cmdname_help *cmd = cmds + i;\n+\n+\t\tif (longest < strlen(cmd->name))\n+\t\t\tlongest = strlen(cmd->name);\n+\t}\n+\n+\tQSORT(cmds, nr, cmd_category_cmp);\n+\n+\tputs(_(\"These are all Git commands:\"));\n+\n+\tfor (i = 0; i < nr; i++) {\n+\t\tstruct cmdname_help *cmd = cmds + i;\n+\n+\t\tif (cmd->category != current_category) {\n+\t\t\tcurrent_category = cmd->category;\n+\t\t\tprintf(\"\\n%s:\\n\", get_category_name(current_category));\n+\t\t}\n+\n+\t\tprintf(\"   %s   \", cmd->name);\n+\t\tmput_char(' ', longest - strlen(cmd->name));\n+\t\tputs(_(cmd->help));\n+\t}\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex 33e2210ebd..62449f1b7e 100644\n--- a/help.h\n+++ b/help.h\n@@ -17,6 +17,7 @@ static inline void mput_char(char c, unsigned int num)\n }\n \n extern void list_common_cmds_help(void);\n+extern void list_all_cmds_help(void);\n extern void list_all_cmds(void);\n extern void list_porcelain_cmds(void);\n extern const char *help_unknown_cmd(const char *cmd);\n-- \n2.17.0.rc0.348.gd5a49e0b6f\n\n"},{"id":"343023","messageId":"20180326165520.802-5-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180326165520.802-1-pclouds@gmail.com","subject":"[PATCH/RFC 4/5] git.c: implement --list-cmds=porcelain","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-03-26T16:55:19Z","receivedAt":"2018-03-26T16:56:31Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is useful for git-completion.bash because it needs this set of\ncommands. Right now we have to maintain a separate command category in\nthere.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash | 94 ++------------------------\n git.c                                  |  2 +\n help.c                                 | 12 ++++\n help.h                                 |  1 +\n t/t9902-completion.sh                  |  4 +-\n 5 files changed, 20 insertions(+), 93 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex e0f545819d..d711a9b53a 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -833,14 +833,15 @@ __git_commands () {\n \tthen\n \t\tprintf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n \telse\n-\t\tgit --list-cmds=all\n+\t\tgit --list-cmds=$1\n \tfi\n }\n \n __git_list_all_commands ()\n {\n \tlocal i IFS=\" \"$'\\n'\n-\tfor i in $(__git_commands)\n+\tlocal category=${1-all}\n+\tfor i in $(__git_commands $category)\n \tdo\n \t\tcase $i in\n \t\t*--*)             : helper pattern;;\n@@ -856,98 +857,11 @@ __git_compute_all_commands ()\n \t__git_all_commands=$(__git_list_all_commands)\n }\n \n-__git_list_porcelain_commands ()\n-{\n-\tlocal i IFS=\" \"$'\\n'\n-\t__git_compute_all_commands\n-\tfor i in $__git_all_commands\n-\tdo\n-\t\tcase $i in\n-\t\t*--*)             : helper pattern;;\n-\t\tapplymbox)        : ask gittus;;\n-\t\tapplypatch)       : ask gittus;;\n-\t\tarchimport)       : import;;\n-\t\tcat-file)         : plumbing;;\n-\t\tcheck-attr)       : plumbing;;\n-\t\tcheck-ignore)     : plumbing;;\n-\t\tcheck-mailmap)    : plumbing;;\n-\t\tcheck-ref-format) : plumbing;;\n-\t\tcheckout-index)   : plumbing;;\n-\t\tcolumn)           : internal helper;;\n-\t\tcommit-tree)      : plumbing;;\n-\t\tcount-objects)    : infrequent;;\n-\t\tcredential)       : credentials;;\n-\t\tcredential-*)     : credentials helper;;\n-\t\tcvsexportcommit)  : export;;\n-\t\tcvsimport)        : import;;\n-\t\tcvsserver)        : daemon;;\n-\t\tdaemon)           : daemon;;\n-\t\tdiff-files)       : plumbing;;\n-\t\tdiff-index)       : plumbing;;\n-\t\tdiff-tree)        : plumbing;;\n-\t\tfast-import)      : import;;\n-\t\tfast-export)      : export;;\n-\t\tfsck-objects)     : plumbing;;\n-\t\tfetch-pack)       : plumbing;;\n-\t\tfmt-merge-msg)    : plumbing;;\n-\t\tfor-each-ref)     : plumbing;;\n-\t\thash-object)      : plumbing;;\n-\t\thttp-*)           : transport;;\n-\t\tindex-pack)       : plumbing;;\n-\t\tinit-db)          : deprecated;;\n-\t\tlocal-fetch)      : plumbing;;\n-\t\tls-files)         : plumbing;;\n-\t\tls-remote)        : plumbing;;\n-\t\tls-tree)          : plumbing;;\n-\t\tmailinfo)         : plumbing;;\n-\t\tmailsplit)        : plumbing;;\n-\t\tmerge-*)          : plumbing;;\n-\t\tmktree)           : plumbing;;\n-\t\tmktag)            : plumbing;;\n-\t\tpack-objects)     : plumbing;;\n-\t\tpack-redundant)   : plumbing;;\n-\t\tpack-refs)        : plumbing;;\n-\t\tparse-remote)     : plumbing;;\n-\t\tpatch-id)         : plumbing;;\n-\t\tprune)            : plumbing;;\n-\t\tprune-packed)     : plumbing;;\n-\t\tquiltimport)      : import;;\n-\t\tread-tree)        : plumbing;;\n-\t\treceive-pack)     : plumbing;;\n-\t\tremote-*)         : transport;;\n-\t\trerere)           : plumbing;;\n-\t\trev-list)         : plumbing;;\n-\t\trev-parse)        : plumbing;;\n-\t\trunstatus)        : plumbing;;\n-\t\tsh-setup)         : internal;;\n-\t\tshell)            : daemon;;\n-\t\tshow-ref)         : plumbing;;\n-\t\tsend-pack)        : plumbing;;\n-\t\tshow-index)       : plumbing;;\n-\t\tssh-*)            : transport;;\n-\t\tstripspace)       : plumbing;;\n-\t\tsymbolic-ref)     : plumbing;;\n-\t\tunpack-file)      : plumbing;;\n-\t\tunpack-objects)   : plumbing;;\n-\t\tupdate-index)     : plumbing;;\n-\t\tupdate-ref)       : plumbing;;\n-\t\tupdate-server-info) : daemon;;\n-\t\tupload-archive)   : plumbing;;\n-\t\tupload-pack)      : plumbing;;\n-\t\twrite-tree)       : plumbing;;\n-\t\tvar)              : infrequent;;\n-\t\tverify-pack)      : infrequent;;\n-\t\tverify-tag)       : plumbing;;\n-\t\t*) echo $i;;\n-\t\tesac\n-\tdone\n-}\n-\n __git_porcelain_commands=\n __git_compute_porcelain_commands ()\n {\n \ttest -n \"$__git_porcelain_commands\" ||\n-\t__git_porcelain_commands=$(__git_list_porcelain_commands)\n+\t__git_porcelain_commands=$(__git_list_all_commands porcelain)\n }\n \n # Lists all set config variables starting with the given section prefix,\ndiff --git a/git.c b/git.c\nindex 2e0c5e17e2..5b09f77792 100644\n--- a/git.c\n+++ b/git.c\n@@ -210,6 +210,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t\tlist_builtins();\n \t\t\telse if (!strcmp(cmd, \"all\"))\n \t\t\t\tlist_all_cmds();\n+\t\t\telse if (!strcmp(cmd, \"porcelain\"))\n+\t\t\t\tlist_porcelain_cmds();\n \t\t\telse\n \t\t\t\tdie(\"unsupported command listing type '%s'\", cmd);\n \t\t\texit(0);\ndiff --git a/help.c b/help.c\nindex 4d07ea3913..cacd8249bb 100644\n--- a/help.c\n+++ b/help.c\n@@ -270,6 +270,18 @@ void list_all_cmds(void)\n \t\tputs(other_cmds.names[i]->name);\n }\n \n+void list_porcelain_cmds(void)\n+{\n+\tint i, nr = ARRAY_SIZE(command_list);\n+\tstruct cmdname_help *cmds = command_list;\n+\n+\tfor (i = 0; i < nr; i++) {\n+\t\tif (cmds[i].category != CAT_mainporcelain)\n+\t\t\tcontinue;\n+\t\tputs(cmds[i].name);\n+\t}\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex 0bf29f8dc5..33e2210ebd 100644\n--- a/help.h\n+++ b/help.h\n@@ -18,6 +18,7 @@ static inline void mput_char(char c, unsigned int num)\n \n extern void list_common_cmds_help(void);\n extern void list_all_cmds(void);\n+extern void list_porcelain_cmds(void);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex e6485feb0a..79a2c6d67d 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1208,8 +1208,6 @@ test_expect_success 'basic' '\n \tgrep -q \"^add \\$\" out &&\n \t# script\n \tgrep -q \"^filter-branch \\$\" out &&\n-\t# plumbing\n-\t! grep -q \"^ls-files \\$\" out &&\n \n \trun_completion \"git f\" &&\n \t! grep -q -v \"^f\" out\n@@ -1272,7 +1270,7 @@ test_expect_success 'general options' '\n \ttest_completion \"git --no-r\" \"--no-replace-objects \"\n '\n \n-test_expect_success 'general options plus command' '\n+test_expect_failure 'general options plus command' '\n \ttest_completion \"git --version check\" \"checkout \" &&\n \ttest_completion \"git --paginate check\" \"checkout \" &&\n \ttest_completion \"git --git-dir=foo check\" \"checkout \" &&\n-- \n2.17.0.rc0.348.gd5a49e0b6f\n\n"},{"id":"344151","messageId":"CAPig+cTZsxazyzsm9HGm4upP4RLcyVWG2XH+jFAVoa=N4_093w@mail.gmail.com","threadId":"48155","inReplyTo":"20180326165520.802-3-pclouds@gmail.com","subject":"Re: [PATCH/RFC 2/5] git.c: implement --list-cmds=all and use it in git-completion.bash","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-09T03:32:31Z","receivedAt":"2018-04-09T03:32:40Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Mar 26, 2018 at 12:55 PM, Nguyễn Thái Ngọc Duy\n<pclouds@gmail.com> wrote:\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/help.c b/help.c\n> @@ -228,6 +228,21 @@ void list_common_cmds_help(void)\n> +void list_all_cmds(void)\n> +{\n> +       struct cmdnames main_cmds, other_cmds;\n> +       int i;\n> +\n> +       memset(&main_cmds, 0, sizeof(main_cmds));\n> +       memset(&other_cmds, 0, sizeof(other_cmds));\n> +       load_command_list(\"git-\", &main_cmds, &other_cmds);\n> +\n> +       for (i = 0; i < main_cmds.cnt; i++)\n> +               puts(main_cmds.names[i]->name);\n> +       for (i = 0; i < other_cmds.cnt; i++)\n> +               puts(other_cmds.names[i]->name);\n\nclean_cmdnames(&main_cmds);\nclean_cmdnames(&other_cmds);\n\n> +}\n"},{"id":"344155","messageId":"CAPig+cQHzB3zLqhRmDKuYk_w8283202x80BcuH7Mu3NqL95cZQ@mail.gmail.com","threadId":"48155","inReplyTo":"20180326165520.802-4-pclouds@gmail.com","subject":"Re: [PATCH/RFC 3/5] generate-cmdlist.sh: keep all information in common-cmds.h","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-09T04:59:37Z","receivedAt":"2018-04-09T04:59:42Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Mar 26, 2018 at 12:55 PM, Nguyễn Thái Ngọc Duy\n<pclouds@gmail.com> wrote:\n> common-cmds.h is used to extract the list of common commands (by\n> group) and a one-line summary of each command. Some information is\n> dropped, for example command category or summary of other commands.\n> Update generate-cmdlist.sh to keep all the information. The extra info\n> will be used shortly.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\n> @@ -2,9 +2,10 @@\n>  struct cmdname_help {\n> -       char name[16];\n> +       char name[32];\n>         char help[80];\n> -       unsigned char group;\n> +       unsigned int category;\n> +       unsigned int group;\n>  };\n> @@ -23,27 +24,50 @@ sed -n '\n> +echo \"#define GROUP_NONE 0xff /* no common group */\"\n> +echo \"#define GROUP_ 0xff /* no common group */\"\n\nMeh, this \"GROUP_\" alias of \"GROUP_NONE\" isn't so nice.\n\n>  n=0\n> -substnum=\n>  while read grp\n>  do\n> -       echo \"^git-..*[         ]$grp\"\n> -       substnum=\"$substnum${substnum:+;}s/[    ]$grp/$n/\"\n> +       echo \"#define GROUP_$grp $n\"\n>         n=$(($n+1))\n> -done <\"$grps\" >\"$match\"\n> +done <\"$grps\"\n\nThis patch drops all use of the file $match. Earlier in this script,\nnot seen in the context, are a couple references to $match which ought\nto be adjusted to take its retirement into account:\n\n    match=match$$.tmp\n    trap \"rm -f '$grps' '$match'\" 0 1 2 3 15\n\nHowever, I'm concerned that this change may be going in the wrong\ndirection. A line in \"### command list\" section looks like this:\n\n    command-name  category [deprecated] [common]\n\nAlthough we don't currently have any commands marked with tag\n\"deprecated\", we very well may have some day. More generally, new\noptional or required tags may be added in the future. As such, the\nline format is relatively free-form. Current clients don't even care\nin what order the tags appears (following 'category') nor how many\ntags there are. The new code added by this patch, however, is far less\nflexible and accommodating since it assumes hard-coded columns for the\ntags (and doesn't even take 'deprecated' into account).\n\nThe point of the $match file was to be able to extract only lines\nwhich mentioned one of the \"common groups\", and the point of the\n'substnum' transformation was to transform the group name into a group\nnumber -- both of these operations were done without caring about the\nexact column the \"common group\" tag occupied.\n\nObviously, one option for addressing this concern would be to change\nthe definition to make the tag columns fixed and non-optional, which\nwould allow the simpler implementation used by this patch. Doing so\nmay require fixing other consumers of command-list.txt (though, I'm\npretty sure existing consumers wouldn't be bothered).\n\n(Perl would be an obvious good choice for retaining the current\nrelatively free-form line definition without having to jump through\nhoops in the shell. Unfortunately, though, a Perl dependency in the\nbuild system can be problematic[1].)\n\n[1]: https://public-inbox.org/git/1440365469-9928-1-git-send-email-sunshine@sunshineco.com/\n\n> -printf 'static struct cmdname_help common_cmds[] = {\\n'\n> -grep -f \"$match\" \"$1\" |\n> +echo '/*'\n> +printf 'static const char *cmd_categories[] = {\\n'\n> +grep '^git-' \"$1\" |\n\nThis \"grep '^git-'\" (and those below) misses some commands, such as\n\"gitk\" and \"gitweb\". Is that intentional? If not, then you'll probably\nneed to grab lines following \"### command list\", as is done earlier in\nthe script. Same comment for the other couple grep's later in the\npatch.\n\n> +awk '{print $2;}' |\n\nAt one time, Junio expressed concerns[2] about having an 'awk'\ndependency in the build system (in fact, with regards to this same\ngeneration process). Whether he still has such concerns is unknown,\nbut it should be easy enough to avoid it here (and below).\n\n[2]: https://public-inbox.org/git/20150519004356.GA12854@flurp.local/\n\n> +sort |\n> +uniq |\n> +while read category; do\n> +       printf '\\t\\\"'$category'\\\",\\n'\n> +done\n> +printf '\\tNULL\\n};\\n\\n'\n> +echo '*/'\n> diff --git a/help.c b/help.c\n> @@ -190,6 +190,28 @@ void list_commands(unsigned int colopts,\n> +static void extract_common_cmds(struct cmdname_help **p_common_cmds,\n> +                               int *p_nr)\n> +{\n> +       int i, nr = 0;\n> +       struct cmdname_help *common_cmds;\n> +\n> +       ALLOC_ARRAY(common_cmds, ARRAY_SIZE(command_list));\n> +\n> +       for (i = 0; i < ARRAY_SIZE(command_list); i++) {\n> +               const struct cmdname_help *cmd = command_list + i;\n> +\n> +               if (cmd->category != CAT_mainporcelain ||\n> +                   cmd->group == GROUP_NONE)\n> +                       continue;\n\nIs the CAT_mainporcelain condition necessary? Before this patch, the\ncommand list would contain only commands with an associated group, so\nit seems that you could get by just with the GROUP_NONE condition.\n\n> +\n> +               common_cmds[nr++] = *cmd;\n> +       }\n> +\n> +       *p_common_cmds = common_cmds;\n> +       *p_nr = nr;\n> +}\n"},{"id":"344156","messageId":"CAPig+cR-WP5z1u-9KG-mNOF0mEUcguMET93O21nfzYixEFWaYw@mail.gmail.com","threadId":"48155","inReplyTo":"20180326165520.802-6-pclouds@gmail.com","subject":"Re: [PATCH/RFC 5/5] help: add \"-a --verbose\" to list all commands with synopsis","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-09T05:08:14Z","receivedAt":"2018-04-09T05:08:19Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Mar 26, 2018 at 12:55 PM, Nguyễn Thái Ngọc Duy\n<pclouds@gmail.com> wrote:\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/help.c b/help.c\n> @@ -282,6 +282,67 @@ void list_porcelain_cmds(void)\n> +static const char *get_category_name(unsigned int category)\n> +{\n> +       switch (category) {\n> +       case CAT_ancillaryinterrogators: return _(\"Ancillary interrogators\");\n> +       case CAT_ancillarymanipulators: return _(\"Ancillary manipulators\");\n> +       case CAT_foreignscminterface: return _(\"Foreign SCM interface\");\n> +       case CAT_mainporcelain: return _(\"Main porcelain\");\n> +       case CAT_plumbinginterrogators: return _(\"Plumbing interrogators\");\n> +       case CAT_plumbingmanipulators: return _(\"Plumbing interrogators\");\n\ns/interrogators\"/manipulators\"/\n\n> +       case CAT_purehelpers: return _(\"Pure helpers\");\n> +       case CAT_synchelpers: return _(\"Sync helpers\");\n> +       case CAT_synchingrepositories: return _(\"Synching repositories\");\n> +       default:\n> +               die(\"BUG: unknown command category %u\", category);\n> +       }\n"},{"id":"344157","messageId":"CAPig+cRvL7-QSx=Ab+pqiSbqBoE0L7JhytpCWFPa8EgkAMe4fA@mail.gmail.com","threadId":"48155","inReplyTo":"CAPig+cQHzB3zLqhRmDKuYk_w8283202x80BcuH7Mu3NqL95cZQ@mail.gmail.com","subject":"Re: [PATCH/RFC 3/5] generate-cmdlist.sh: keep all information in common-cmds.h","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-09T05:12:34Z","receivedAt":"2018-04-09T05:12:39Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Apr 9, 2018 at 12:59 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> However, I'm concerned that this change may be going in the wrong\n> direction. A line in \"### command list\" section looks like this:\n>\n>     command-name  category [deprecated] [common]\n>\n> Although we don't currently have any commands marked with tag\n> \"deprecated\", we very well may have some day. More generally, new\n> optional or required tags may be added in the future. As such, the\n> line format is relatively free-form. Current clients don't even care\n> in what order the tags appears (following 'category') nor how many\n> tags there are. The new code added by this patch, however, is far less\n> flexible and accommodating since it assumes hard-coded columns for the\n> tags (and doesn't even take 'deprecated' into account).\n>\n> The point of the $match file was to be able to extract only lines\n> which mentioned one of the \"common groups\", and the point of the\n> 'substnum' transformation was to transform the group name into a group\n> number -- both of these operations were done without caring about the\n> exact column the \"common group\" tag occupied.\n>\n> Obviously, one option for addressing this concern would be to change\n> the definition to make the tag columns fixed and non-optional, which\n> would allow the simpler implementation used by this patch. Doing so\n> may require fixing other consumers of command-list.txt (though, I'm\n> pretty sure existing consumers wouldn't be bothered).\n\nI should follow up by saying that, although the current relatively\nfree-form line definition is nice due to its flexibility, considering\nhow infrequently command-list.txt is edited and how much more complex\nthe script is to support that flexibility, changing to a definition in\nwhich tags are required and at fixed columns seems like the pragmatic\nthing to do.\n"},{"id":"344158","messageId":"CAPig+cTW7KRzXXY7vP-GZ23effYd5jLhiL15KqdRam4rNELCWw@mail.gmail.com","threadId":"48155","inReplyTo":"20180326165520.802-1-pclouds@gmail.com","subject":"Re: [PATCH/RFC 0/5] Keep all info in command-list.txt in git binary","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-09T05:17:50Z","receivedAt":"2018-04-09T05:17:56Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Mar 26, 2018 at 12:55 PM, Nguyễn Thái Ngọc Duy\n<pclouds@gmail.com> wrote:\n> This is pretty rough but I'd like to see how people feel about this\n> first.\n>\n> I notice we have two places for command classification. One in\n> command-list.txt, one in __git_list_porcelain_commands() in\n> git-completion.bash. People who are following nd/parseopt-completion\n> probably know that I'm try to reduce duplication in this script as\n> much as possible, this is another step towards that.\n>\n> By keeping all information of command-list.txt in git binary, we could\n> provide the porcelain list to git-completion.bash via \"git\n> --list-cmds=porcelain\", so we don't neeed a separate command\n> classification in git-completion.bash anymore.\n\nI like the direction this series is taking.\n\n> Because we have all command synopsis as a side effect, we could\n> now support \"git help -a --verbose\" which prints something like \"git\n> help\", a command name and a description, but we could do it for _all_\n> recognized commands. This could help people look for a command even if\n> we don't provide \"git appropos\".\n\nNice idea, and you practically get this for free (aside from the the\nobvious new code) since generate-cmdlist.sh already plucks the summary\nfor each command directly from Documentation/git-*.txt.\n"},{"id":"344187","messageId":"xmqqh8ok679l.fsf@gitster-ct.c.googlers.com","threadId":"48155","inReplyTo":"CAPig+cR-WP5z1u-9KG-mNOF0mEUcguMET93O21nfzYixEFWaYw@mail.gmail.com","subject":"Re: [PATCH/RFC 5/5] help: add \"-a --verbose\" to list all commands with synopsis","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-04-09T09:47:34Z","receivedAt":"2018-04-09T09:47:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> On Mon, Mar 26, 2018 at 12:55 PM, Nguyễn Thái Ngọc Duy\n> <pclouds@gmail.com> wrote:\n>> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n>> ---\n>> diff --git a/help.c b/help.c\n>> @@ -282,6 +282,67 @@ void list_porcelain_cmds(void)\n>> +static const char *get_category_name(unsigned int category)\n>> +{\n>> +       switch (category) {\n>> +       case CAT_ancillaryinterrogators: return _(\"Ancillary interrogators\");\n>> +       case CAT_ancillarymanipulators: return _(\"Ancillary manipulators\");\n>> +       case CAT_foreignscminterface: return _(\"Foreign SCM interface\");\n>> +       case CAT_mainporcelain: return _(\"Main porcelain\");\n>> +       case CAT_plumbinginterrogators: return _(\"Plumbing interrogators\");\n>> +       case CAT_plumbingmanipulators: return _(\"Plumbing interrogators\");\n>\n> s/interrogators\"/manipulators\"/\n>\n>> +       case CAT_purehelpers: return _(\"Pure helpers\");\n>> +       case CAT_synchelpers: return _(\"Sync helpers\");\n>> +       case CAT_synchingrepositories: return _(\"Synching repositories\");\n>> +       default:\n>> +               die(\"BUG: unknown command category %u\", category);\n>> +       }\n\nSomehow this screams \"an array of strings\" at me.  Aren't this\nCAT_things small and dense enum?\n"},{"id":"344188","messageId":"CAPig+cSwDpWOz2_PAZOCmdhoYXYhYR0fHsw8POgNDfd9nD2Q1A@mail.gmail.com","threadId":"48155","inReplyTo":"xmqqh8ok679l.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH/RFC 5/5] help: add \"-a --verbose\" to list all commands with synopsis","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-09T09:55:26Z","receivedAt":"2018-04-09T09:55:32Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Apr 9, 2018 at 5:47 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Eric Sunshine <sunshine@sunshineco.com> writes:\n>> On Mon, Mar 26, 2018 at 12:55 PM, Nguyễn Thái Ngọc Duy\n>> <pclouds@gmail.com> wrote:\n>>> +       switch (category) {\n>>> +       case CAT_ancillaryinterrogators: return _(\"Ancillary interrogators\");\n>>> +       case CAT_ancillarymanipulators: return _(\"Ancillary manipulators\");\n>>> +       case CAT_foreignscminterface: return _(\"Foreign SCM interface\");\n>>> +       case CAT_mainporcelain: return _(\"Main porcelain\");\n>>> +       case CAT_plumbinginterrogators: return _(\"Plumbing interrogators\");\n>>> +       case CAT_plumbingmanipulators: return _(\"Plumbing interrogators\");\n>>\n>> s/interrogators\"/manipulators\"/\n>>\n>>> +       case CAT_purehelpers: return _(\"Pure helpers\");\n>>> +       case CAT_synchelpers: return _(\"Sync helpers\");\n>>> +       case CAT_synchingrepositories: return _(\"Synching repositories\");\n>\n> Somehow this screams \"an array of strings\" at me.  Aren't this\n> CAT_things small and dense enum?\n\nDuy's modified generate-cmdlist.sh does actually output an array of\nstrings for these, but the (generated) array is commented out in this\nRFC. I suppose the reason it's not presently used is because the array\nlooks like this:\n\nstatic const char *cmd_categories[] = {\n    \"ancillaryinterrogators\",\n    \"ancillarymanipulators\",\n    \"foreignscminterface\",\n    \"mainporcelain\",\n    \"plumbinginterrogators\",\n    \"plumbingmanipulators\",\n    \"purehelpers\",\n    \"synchelpers\",\n    \"synchingrepositories\",\n     NULL\n};\n\nwhich doesn't give quite the human-friendly output he'd like. The\nseries is RFC, after all.\n\nA possible approach to fix it would be to add a new \"### categories\"\nsection to command-list.txt which associates those category tags\n(\"ancillaryinterrogators\") with human-readable counterparts\n(\"Ancillary interrogators\").\n"},{"id":"344198","messageId":"CACsJy8Dk5vBn+xY25PiTFvre_8HoveZ2eGSD8HOPmonGW99+8w@mail.gmail.com","threadId":"48155","inReplyTo":"CAPig+cSwDpWOz2_PAZOCmdhoYXYhYR0fHsw8POgNDfd9nD2Q1A@mail.gmail.com","subject":"Re: [PATCH/RFC 5/5] help: add \"-a --verbose\" to list all commands with synopsis","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-09T15:15:02Z","receivedAt":"2018-04-09T15:16:03Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Apr 9, 2018 at 11:55 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Mon, Apr 9, 2018 at 5:47 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Eric Sunshine <sunshine@sunshineco.com> writes:\n>>> On Mon, Mar 26, 2018 at 12:55 PM, Nguyễn Thái Ngọc Duy\n>>> <pclouds@gmail.com> wrote:\n>>>> +       switch (category) {\n>>>> +       case CAT_ancillaryinterrogators: return _(\"Ancillary interrogators\");\n>>>> +       case CAT_ancillarymanipulators: return _(\"Ancillary manipulators\");\n>>>> +       case CAT_foreignscminterface: return _(\"Foreign SCM interface\");\n>>>> +       case CAT_mainporcelain: return _(\"Main porcelain\");\n>>>> +       case CAT_plumbinginterrogators: return _(\"Plumbing interrogators\");\n>>>> +       case CAT_plumbingmanipulators: return _(\"Plumbing interrogators\");\n>>>\n>>> s/interrogators\"/manipulators\"/\n>>>\n>>>> +       case CAT_purehelpers: return _(\"Pure helpers\");\n>>>> +       case CAT_synchelpers: return _(\"Sync helpers\");\n>>>> +       case CAT_synchingrepositories: return _(\"Synching repositories\");\n>>\n>> Somehow this screams \"an array of strings\" at me.  Aren't this\n>> CAT_things small and dense enum?\n>\n> Duy's modified generate-cmdlist.sh does actually output an array of\n> strings for these, but the (generated) array is commented out in this\n> RFC. I suppose the reason it's not presently used is because the array\n> looks like this:\n>\n> static const char *cmd_categories[] = {\n>     \"ancillaryinterrogators\",\n>     \"ancillarymanipulators\",\n>     \"foreignscminterface\",\n>     \"mainporcelain\",\n>     \"plumbinginterrogators\",\n>     \"plumbingmanipulators\",\n>     \"purehelpers\",\n>     \"synchelpers\",\n>     \"synchingrepositories\",\n>      NULL\n> };\n>\n> which doesn't give quite the human-friendly output he'd like. The\n> series is RFC, after all.\n\nYep.\n\n> A possible approach to fix it would be to add a new \"### categories\"\n> section to command-list.txt which associates those category tags\n> (\"ancillaryinterrogators\") with human-readable counterparts\n> (\"Ancillary interrogators\").\n\nOr extract the headlines from git.txt but that's not easy since it's\nnot consistent. We could manually recreate the same grouping as in\ngit.txt too, it's probably nicer than just printing groups sorted by\ncategory id.\n-- \nDuy\n"},{"id":"344201","messageId":"CACsJy8DQEZ_wYWWRQLeLNwJoWhkAwN++Uaxnp=tDvCd_u4gFaQ@mail.gmail.com","threadId":"48155","inReplyTo":"CAPig+cQHzB3zLqhRmDKuYk_w8283202x80BcuH7Mu3NqL95cZQ@mail.gmail.com","subject":"Re: [PATCH/RFC 3/5] generate-cmdlist.sh: keep all information in common-cmds.h","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-09T16:16:45Z","receivedAt":"2018-04-09T16:17:22Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Apr 9, 2018 at 6:59 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Mon, Mar 26, 2018 at 12:55 PM, Nguyễn Thái Ngọc Duy\n> <pclouds@gmail.com> wrote:\n>> common-cmds.h is used to extract the list of common commands (by\n>> group) and a one-line summary of each command. Some information is\n>> dropped, for example command category or summary of other commands.\n>> Update generate-cmdlist.sh to keep all the information. The extra info\n>> will be used shortly.\n>>\n>> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n>> ---\n>> diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\n>> @@ -2,9 +2,10 @@\n>>  struct cmdname_help {\n>> -       char name[16];\n>> +       char name[32];\n>>         char help[80];\n>> -       unsigned char group;\n>> +       unsigned int category;\n>> +       unsigned int group;\n>>  };\n>> @@ -23,27 +24,50 @@ sed -n '\n>> +echo \"#define GROUP_NONE 0xff /* no common group */\"\n>> +echo \"#define GROUP_ 0xff /* no common group */\"\n>\n> Meh, this \"GROUP_\" alias of \"GROUP_NONE\" isn't so nice.\n\nYeah. I don't want to mess too much with shell script. I wonder if we\nshould instead kill this script and extend Documentation/cmd-list.perl\nto handle this task too. It would be much nicer to write and maintain\nthe script. The downside is NO_PERL builds will have no commands in\n\"git help\".\n-- \nDuy\n"},{"id":"344502","messageId":"FBB059C530054EEAB2E989D86CBE3BD5@PhilipOakley","threadId":"48155","inReplyTo":"CAPig+cTW7KRzXXY7vP-GZ23effYd5jLhiL15KqdRam4rNELCWw@mail.gmail.com","subject":"Re: [PATCH/RFC 0/5] Keep all info in command-list.txt in git binary","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2018-04-11T22:06:30Z","receivedAt":"2018-04-11T22:06:36Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Eric Sunshine\" <sunshine@sunshineco.com> Monday, April 09, 2018 6:17 \nAM\nOn Mon, Mar 26, 2018 at 12:55 PM, Nguyễn Thái Ngọc Duy\n<pclouds@gmail.com> wrote:\n> This is pretty rough but I'd like to see how people feel about this\n> first.\n>\n> I notice we have two places for command classification. One in\n> command-list.txt, one in __git_list_porcelain_commands() in\n> git-completion.bash. People who are following nd/parseopt-completion\n> probably know that I'm try to reduce duplication in this script as\n> much as possible, this is another step towards that.\n>\n> By keeping all information of command-list.txt in git binary, we could\n> provide the porcelain list to git-completion.bash via \"git\n> --list-cmds=porcelain\", so we don't neeed a separate command\n> classification in git-completion.bash anymore.\n\nI like the direction this series is taking.\n\n> Because we have all command synopsis as a side effect, we could\n> now support \"git help -a --verbose\" which prints something like \"git\n> help\", a command name and a description, but we could do it for _all_\n> recognized commands. This could help people look for a command even if\n> we don't provide \"git appropos\".\n\nNice idea, and you practically get this for free (aside from the the\nobvious new code) since generate-cmdlist.sh already plucks the summary\nfor each command directly from Documentation/git-*.txt.\n\nI'm only just catching up, but does/can this series also capture the \nnon-command guides that are available in git so that the 'git help -g' can \nbegin to list them all?\n\nIt was something I looked at some years ago (when I added the -g option) but \nat the time the idea of updating the command-list.txt was too invasive.\n\nJust a thought.\n\nPhilip\n\n"},{"id":"344687","messageId":"CACsJy8BqoW_YWBiMoOks+WM5XY7Mmadkd0LUBoUWLDXehx1GZQ@mail.gmail.com","threadId":"48155","inReplyTo":"FBB059C530054EEAB2E989D86CBE3BD5@PhilipOakley","subject":"Re: [PATCH/RFC 0/5] Keep all info in command-list.txt in git binary","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-14T15:44:13Z","receivedAt":"2018-04-14T15:44:48Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Apr 12, 2018 at 12:06 AM, Philip Oakley <philipoakley@iee.org> wrote:\n> I'm only just catching up, but does/can this series also capture the\n> non-command guides that are available in git so that the 'git help -g' can\n> begin to list them all?\n\nIt currently does not. But I don't see why it should not. This should\nallow git.txt to list all the guides too, for people who skip \"git\nhelp\" and go hard core mode with \"man git\". Thanks for bringing this\nup.\n-- \nDuy\n"},{"id":"344725","messageId":"CACsJy8Drekqn7J0S1F1awaxwLGzrhHy8eUgGQqKAsT-eL-wmMQ@mail.gmail.com","threadId":"48155","inReplyTo":"CAPig+cQHzB3zLqhRmDKuYk_w8283202x80BcuH7Mu3NqL95cZQ@mail.gmail.com","subject":"Re: [PATCH/RFC 3/5] generate-cmdlist.sh: keep all information in common-cmds.h","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-15T16:04:23Z","receivedAt":"2018-04-15T16:05:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Apr 9, 2018 at 6:59 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>> +awk '{print $2;}' |\n>\n> At one time, Junio expressed concerns[2] about having an 'awk'\n> dependency in the build system (in fact, with regards to this same\n> generation process). Whether he still has such concerns is unknown,\n> but it should be easy enough to avoid it here (and below).\n>\n> [2]: https://public-inbox.org/git/20150519004356.GA12854@flurp.local/\n\nI'll stick with awk to avoid too much headache with regular\nexpressions (replacements are welcome though). We do use awk in our\ntest suite so it should be ok (who builds git and runs it without\ntesting?)\n-- \nDuy\n"},{"id":"344726","messageId":"20180415164238.9107-1-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180326165520.802-1-pclouds@gmail.com","subject":"[PATCH v2 0/6] Keep all info in command-list.txt in git binary","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-15T16:42:32Z","receivedAt":"2018-04-15T16:45:50Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"v2 changes\n\n- bug fixes spotted by Eric\n- keep 'git help -av' layout close to what's in git.txt\n- enable pager for 'git help -av' because it's usually long\n- move guide list (aka 'help -g') to command-list.txt\n\nNguyễn Thái Ngọc Duy (6):\n  git.c: convert --list-builtins to --list-cmds=builtins\n  git.c: implement --list-cmds=all and use it in git-completion.bash\n  generate-cmdlist.sh: keep all information in common-cmds.h\n  git.c: implement --list-cmds=porcelain\n  help: add \"-a --verbose\" to list all commands with synopsis\n  help: use command-list.txt for the source of guides\n\n Documentation/git-help.txt             |   4 +-\n Documentation/gitattributes.txt        |   2 +-\n Documentation/gitmodules.txt           |   2 +-\n Documentation/gitrevisions.txt         |   2 +-\n builtin/help.c                         |  39 ++----\n command-list.txt                       |   8 ++\n contrib/completion/git-completion.bash |  96 +--------------\n generate-cmdlist.sh                    |  65 +++++++---\n git.c                                  |  16 ++-\n help.c                                 | 163 ++++++++++++++++++++++++-\n help.h                                 |   4 +\n t/t0012-help.sh                        |   2 +-\n t/t9902-completion.sh                  |   4 +-\n 13 files changed, 249 insertions(+), 158 deletions(-)\n\n-- \n2.17.0.367.g5dd2e386c3\n\n"},{"id":"344727","messageId":"20180415164238.9107-2-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180415164238.9107-1-pclouds@gmail.com","subject":"[PATCH v2 1/6] git.c: convert --list-builtins to --list-cmds=builtins","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-15T16:42:33Z","receivedAt":"2018-04-15T16:45:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Even if this is a hidden option, let's make it a bit more generic\nsince we're introducing more listing types.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash |  2 +-\n git.c                                  | 12 +++++++-----\n t/t0012-help.sh                        |  2 +-\n 3 files changed, 9 insertions(+), 7 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex a757073945..3556838759 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -3049,7 +3049,7 @@ __git_complete_common () {\n __git_cmds_with_parseopt_helper=\n __git_support_parseopt_helper () {\n \ttest -n \"$__git_cmds_with_parseopt_helper\" ||\n-\t\t__git_cmds_with_parseopt_helper=\"$(__git --list-parseopt-builtins)\"\n+\t\t__git_cmds_with_parseopt_helper=\"$(__git --list-cmds=parseopt)\"\n \n \tcase \" $__git_cmds_with_parseopt_helper \" in\n \t*\" $1 \"*)\ndiff --git a/git.c b/git.c\nindex 3a89893712..28bfa96d87 100644\n--- a/git.c\n+++ b/git.c\n@@ -223,11 +223,13 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t}\n \t\t\t(*argv)++;\n \t\t\t(*argc)--;\n-\t\t} else if (!strcmp(cmd, \"--list-builtins\")) {\n-\t\t\tlist_builtins(0, '\\n');\n-\t\t\texit(0);\n-\t\t} else if (!strcmp(cmd, \"--list-parseopt-builtins\")) {\n-\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n+\t\t} else if (skip_prefix(cmd, \"--list-cmds=\", &cmd)) {\n+\t\t\tif (!strcmp(cmd, \"builtins\"))\n+\t\t\t\tlist_builtins(0, '\\n');\n+\t\t\telse if (!strcmp(cmd, \"parseopt\"))\n+\t\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n+\t\t\telse\n+\t\t\t\tdie(\"unsupported command listing type '%s'\", cmd);\n \t\t\texit(0);\n \t\t} else {\n \t\t\tfprintf(stderr, _(\"unknown option: %s\\n\"), cmd);\ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex 487b92a5de..fd2a7f27dc 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -50,7 +50,7 @@ test_expect_success \"--help does not work for guides\" \"\n \"\n \n test_expect_success 'generate builtin list' '\n-\tgit --list-builtins >builtins\n+\tgit --list-cmds=builtins >builtins\n '\n \n while read builtin\n-- \n2.17.0.367.g5dd2e386c3\n\n"},{"id":"344728","messageId":"20180415164238.9107-5-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180415164238.9107-1-pclouds@gmail.com","subject":"[PATCH v2 4/6] git.c: implement --list-cmds=porcelain","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-15T16:42:36Z","receivedAt":"2018-04-15T16:46:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is useful for git-completion.bash because it needs this set of\ncommands. Right now we have to maintain a separate command category in\nthere.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash | 94 ++------------------------\n git.c                                  |  2 +\n help.c                                 | 12 ++++\n help.h                                 |  1 +\n t/t9902-completion.sh                  |  4 +-\n 5 files changed, 20 insertions(+), 93 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex a5f13ade20..9f17703aa7 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -839,14 +839,15 @@ __git_commands () {\n \tthen\n \t\tprintf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n \telse\n-\t\tgit --list-cmds=all\n+\t\tgit --list-cmds=$1\n \tfi\n }\n \n __git_list_all_commands ()\n {\n \tlocal i IFS=\" \"$'\\n'\n-\tfor i in $(__git_commands)\n+\tlocal category=${1-all}\n+\tfor i in $(__git_commands $category)\n \tdo\n \t\tcase $i in\n \t\t*--*)             : helper pattern;;\n@@ -862,98 +863,11 @@ __git_compute_all_commands ()\n \t__git_all_commands=$(__git_list_all_commands)\n }\n \n-__git_list_porcelain_commands ()\n-{\n-\tlocal i IFS=\" \"$'\\n'\n-\t__git_compute_all_commands\n-\tfor i in $__git_all_commands\n-\tdo\n-\t\tcase $i in\n-\t\t*--*)             : helper pattern;;\n-\t\tapplymbox)        : ask gittus;;\n-\t\tapplypatch)       : ask gittus;;\n-\t\tarchimport)       : import;;\n-\t\tcat-file)         : plumbing;;\n-\t\tcheck-attr)       : plumbing;;\n-\t\tcheck-ignore)     : plumbing;;\n-\t\tcheck-mailmap)    : plumbing;;\n-\t\tcheck-ref-format) : plumbing;;\n-\t\tcheckout-index)   : plumbing;;\n-\t\tcolumn)           : internal helper;;\n-\t\tcommit-tree)      : plumbing;;\n-\t\tcount-objects)    : infrequent;;\n-\t\tcredential)       : credentials;;\n-\t\tcredential-*)     : credentials helper;;\n-\t\tcvsexportcommit)  : export;;\n-\t\tcvsimport)        : import;;\n-\t\tcvsserver)        : daemon;;\n-\t\tdaemon)           : daemon;;\n-\t\tdiff-files)       : plumbing;;\n-\t\tdiff-index)       : plumbing;;\n-\t\tdiff-tree)        : plumbing;;\n-\t\tfast-import)      : import;;\n-\t\tfast-export)      : export;;\n-\t\tfsck-objects)     : plumbing;;\n-\t\tfetch-pack)       : plumbing;;\n-\t\tfmt-merge-msg)    : plumbing;;\n-\t\tfor-each-ref)     : plumbing;;\n-\t\thash-object)      : plumbing;;\n-\t\thttp-*)           : transport;;\n-\t\tindex-pack)       : plumbing;;\n-\t\tinit-db)          : deprecated;;\n-\t\tlocal-fetch)      : plumbing;;\n-\t\tls-files)         : plumbing;;\n-\t\tls-remote)        : plumbing;;\n-\t\tls-tree)          : plumbing;;\n-\t\tmailinfo)         : plumbing;;\n-\t\tmailsplit)        : plumbing;;\n-\t\tmerge-*)          : plumbing;;\n-\t\tmktree)           : plumbing;;\n-\t\tmktag)            : plumbing;;\n-\t\tpack-objects)     : plumbing;;\n-\t\tpack-redundant)   : plumbing;;\n-\t\tpack-refs)        : plumbing;;\n-\t\tparse-remote)     : plumbing;;\n-\t\tpatch-id)         : plumbing;;\n-\t\tprune)            : plumbing;;\n-\t\tprune-packed)     : plumbing;;\n-\t\tquiltimport)      : import;;\n-\t\tread-tree)        : plumbing;;\n-\t\treceive-pack)     : plumbing;;\n-\t\tremote-*)         : transport;;\n-\t\trerere)           : plumbing;;\n-\t\trev-list)         : plumbing;;\n-\t\trev-parse)        : plumbing;;\n-\t\trunstatus)        : plumbing;;\n-\t\tsh-setup)         : internal;;\n-\t\tshell)            : daemon;;\n-\t\tshow-ref)         : plumbing;;\n-\t\tsend-pack)        : plumbing;;\n-\t\tshow-index)       : plumbing;;\n-\t\tssh-*)            : transport;;\n-\t\tstripspace)       : plumbing;;\n-\t\tsymbolic-ref)     : plumbing;;\n-\t\tunpack-file)      : plumbing;;\n-\t\tunpack-objects)   : plumbing;;\n-\t\tupdate-index)     : plumbing;;\n-\t\tupdate-ref)       : plumbing;;\n-\t\tupdate-server-info) : daemon;;\n-\t\tupload-archive)   : plumbing;;\n-\t\tupload-pack)      : plumbing;;\n-\t\twrite-tree)       : plumbing;;\n-\t\tvar)              : infrequent;;\n-\t\tverify-pack)      : infrequent;;\n-\t\tverify-tag)       : plumbing;;\n-\t\t*) echo $i;;\n-\t\tesac\n-\tdone\n-}\n-\n __git_porcelain_commands=\n __git_compute_porcelain_commands ()\n {\n \ttest -n \"$__git_porcelain_commands\" ||\n-\t__git_porcelain_commands=$(__git_list_porcelain_commands)\n+\t__git_porcelain_commands=$(__git_list_all_commands porcelain)\n }\n \n # Lists all set config variables starting with the given section prefix,\ndiff --git a/git.c b/git.c\nindex 64f67e7f7f..153f56fb95 100644\n--- a/git.c\n+++ b/git.c\n@@ -230,6 +230,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n \t\t\telse if (!strcmp(cmd, \"all\"))\n \t\t\t\tlist_all_cmds();\n+\t\t\telse if (!strcmp(cmd, \"porcelain\"))\n+\t\t\t\tlist_porcelain_cmds();\n \t\t\telse\n \t\t\t\tdie(\"unsupported command listing type '%s'\", cmd);\n \t\t\texit(0);\ndiff --git a/help.c b/help.c\nindex b5da7fa013..1523ca175c 100644\n--- a/help.c\n+++ b/help.c\n@@ -272,6 +272,18 @@ void list_all_cmds(void)\n \tclean_cmdnames(&other_cmds);\n }\n \n+void list_porcelain_cmds(void)\n+{\n+\tint i, nr = ARRAY_SIZE(command_list);\n+\tstruct cmdname_help *cmds = command_list;\n+\n+\tfor (i = 0; i < nr; i++) {\n+\t\tif (cmds[i].category != CAT_mainporcelain)\n+\t\t\tcontinue;\n+\t\tputs(cmds[i].name);\n+\t}\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex 0bf29f8dc5..33e2210ebd 100644\n--- a/help.h\n+++ b/help.h\n@@ -18,6 +18,7 @@ static inline void mput_char(char c, unsigned int num)\n \n extern void list_common_cmds_help(void);\n extern void list_all_cmds(void);\n+extern void list_porcelain_cmds(void);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 1b34caa1e1..4bfd26ddf9 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1208,8 +1208,6 @@ test_expect_success 'basic' '\n \tgrep -q \"^add \\$\" out &&\n \t# script\n \tgrep -q \"^filter-branch \\$\" out &&\n-\t# plumbing\n-\t! grep -q \"^ls-files \\$\" out &&\n \n \trun_completion \"git f\" &&\n \t! grep -q -v \"^f\" out\n@@ -1272,7 +1270,7 @@ test_expect_success 'general options' '\n \ttest_completion \"git --no-r\" \"--no-replace-objects \"\n '\n \n-test_expect_success 'general options plus command' '\n+test_expect_failure 'general options plus command' '\n \ttest_completion \"git --version check\" \"checkout \" &&\n \ttest_completion \"git --paginate check\" \"checkout \" &&\n \ttest_completion \"git --git-dir=foo check\" \"checkout \" &&\n-- \n2.17.0.367.g5dd2e386c3\n\n"},{"id":"344729","messageId":"20180415164238.9107-4-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180415164238.9107-1-pclouds@gmail.com","subject":"[PATCH v2 3/6] generate-cmdlist.sh: keep all information in common-cmds.h","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-15T16:42:35Z","receivedAt":"2018-04-15T16:46:02Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"common-cmds.h is used to extract the list of common commands (by\ngroup) and a one-line summary of each command. Some information is\ndropped, for example command category or summary of other commands.\nUpdate generate-cmdlist.sh to keep all the information. The extra info\nwill be used shortly.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n generate-cmdlist.sh | 61 +++++++++++++++++++++++++++++++++------------\n help.c              | 42 ++++++++++++++++++++++++++-----\n 2 files changed, 81 insertions(+), 22 deletions(-)\n\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex eeea4b67ea..e0893e979a 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -1,17 +1,30 @@\n #!/bin/sh\n \n+# Don't let locale affect this script.\n+LC_ALL=C\n+LANG=C\n+export LC_ALL LANG\n+\n+command_list () {\n+\tsed '1,/^### command list/d;/^#/d' \"$1\"\n+}\n+\n+category_list () {\n+\tcommand_list \"$1\" | awk '{print $2;}' | sort | uniq\n+}\n+\n echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n-\tchar name[16];\n+\tchar name[32];\n \tchar help[80];\n-\tunsigned char group;\n+\tunsigned int category;\n+\tunsigned int group;\n };\n \n static const char *common_cmd_groups[] = {\"\n \n grps=grps$$.tmp\n-match=match$$.tmp\n-trap \"rm -f '$grps' '$match'\" 0 1 2 3 15\n+trap \"rm -f '$grps'\" 0 1 2 3 15\n \n sed -n '\n \t1,/^### common groups/b\n@@ -23,28 +36,44 @@ sed -n '\n \t' \"$1\"\n printf '};\\n\\n'\n \n+echo \"#define GROUP_NONE 0xff /* no common group */\"\n n=0\n-substnum=\n while read grp\n do\n-\techo \"^git-..*[ \t]$grp\"\n-\tsubstnum=\"$substnum${substnum:+;}s/[ \t]$grp/$n/\"\n+\techo \"#define GROUP_${grp:-NONE} $n\"\n \tn=$(($n+1))\n-done <\"$grps\" >\"$match\"\n+done <\"$grps\"\n+echo\n+\n+echo '/*'\n+printf 'static const char *cmd_categories[] = {\\n'\n+category_list \"$1\" |\n+while read category; do\n+\tprintf '\\t\\\"'$category'\\\",\\n'\n+done\n+printf '\\tNULL\\n};\\n\\n'\n+echo '*/'\n+\n+n=0\n+category_list \"$1\" |\n+while read category; do\n+\techo \"#define CAT_$category $n\"\n+\tn=$(($n+1))\n+done\n+echo\n \n-printf 'static struct cmdname_help common_cmds[] = {\\n'\n-grep -f \"$match\" \"$1\" |\n-sed 's/^git-//' |\n+printf 'static struct cmdname_help command_list[] = {\\n'\n+command_list \"$1\" |\n sort |\n-while read cmd tags\n+while read cmd category tags\n do\n-\ttag=$(echo \"$tags\" | sed \"$substnum; s/[^0-9]//g\")\n+\tname=${cmd/git-}\n \tsed -n '\n-\t\t/^NAME/,/git-'\"$cmd\"'/H\n+\t\t/^NAME/,/'\"$cmd\"'/H\n \t\t${\n \t\t\tx\n-\t\t\ts/.*git-'\"$cmd\"' - \\(.*\\)/\t{\"'\"$cmd\"'\", N_(\"\\1\"), '$tag'},/\n+\t\t\ts/.*'\"$cmd\"' - \\(.*\\)/\t{\"'\"$name\"'\", N_(\"\\1\"), CAT_'$category', GROUP_'${tags:-NONE}' },/\n \t\t\tp\n-\t\t}' \"Documentation/git-$cmd.txt\"\n+\t\t}' \"Documentation/$cmd.txt\"\n done\n echo \"};\"\ndiff --git a/help.c b/help.c\nindex e155c39870..b5da7fa013 100644\n--- a/help.c\n+++ b/help.c\n@@ -190,6 +190,27 @@ void list_commands(unsigned int colopts,\n \t}\n }\n \n+static void extract_common_cmds(struct cmdname_help **p_common_cmds,\n+\t\t\t\tint *p_nr)\n+{\n+\tint i, nr = 0;\n+\tstruct cmdname_help *common_cmds;\n+\n+\tALLOC_ARRAY(common_cmds, ARRAY_SIZE(command_list));\n+\n+\tfor (i = 0; i < ARRAY_SIZE(command_list); i++) {\n+\t\tconst struct cmdname_help *cmd = command_list + i;\n+\n+\t\tif (cmd->category != CAT_mainporcelain)\n+\t\t\tcontinue;\n+\n+\t\tcommon_cmds[nr++] = *cmd;\n+\t}\n+\n+\t*p_common_cmds = common_cmds;\n+\t*p_nr = nr;\n+}\n+\n static int cmd_group_cmp(const void *elem1, const void *elem2)\n {\n \tconst struct cmdname_help *e1 = elem1;\n@@ -206,17 +227,21 @@ void list_common_cmds_help(void)\n {\n \tint i, longest = 0;\n \tint current_grp = -1;\n+\tint nr = 0;\n+\tstruct cmdname_help *common_cmds;\n+\n+\textract_common_cmds(&common_cmds, &nr);\n \n-\tfor (i = 0; i < ARRAY_SIZE(common_cmds); i++) {\n+\tfor (i = 0; i < nr; i++) {\n \t\tif (longest < strlen(common_cmds[i].name))\n \t\t\tlongest = strlen(common_cmds[i].name);\n \t}\n \n-\tQSORT(common_cmds, ARRAY_SIZE(common_cmds), cmd_group_cmp);\n+\tQSORT(common_cmds, nr, cmd_group_cmp);\n \n \tputs(_(\"These are common Git commands used in various situations:\"));\n \n-\tfor (i = 0; i < ARRAY_SIZE(common_cmds); i++) {\n+\tfor (i = 0; i < nr; i++) {\n \t\tif (common_cmds[i].group != current_grp) {\n \t\t\tprintf(\"\\n%s\\n\", _(common_cmd_groups[common_cmds[i].group]));\n \t\t\tcurrent_grp = common_cmds[i].group;\n@@ -226,6 +251,7 @@ void list_common_cmds_help(void)\n \t\tmput_char(' ', longest - strlen(common_cmds[i].name));\n \t\tputs(_(common_cmds[i].help));\n \t}\n+\tfree(common_cmds);\n }\n \n void list_all_cmds(void)\n@@ -301,8 +327,9 @@ static const char bad_interpreter_advice[] =\n \n const char *help_unknown_cmd(const char *cmd)\n {\n-\tint i, n, best_similarity = 0;\n+\tint i, n, best_similarity = 0, nr_common;\n \tstruct cmdnames main_cmds, other_cmds;\n+\tstruct cmdname_help *common_cmds;\n \n \tmemset(&main_cmds, 0, sizeof(main_cmds));\n \tmemset(&other_cmds, 0, sizeof(other_cmds));\n@@ -317,6 +344,8 @@ const char *help_unknown_cmd(const char *cmd)\n \tQSORT(main_cmds.names, main_cmds.cnt, cmdname_compare);\n \tuniq(&main_cmds);\n \n+\textract_common_cmds(&common_cmds, &nr_common);\n+\n \t/* This abuses cmdname->len for levenshtein distance */\n \tfor (i = 0, n = 0; i < main_cmds.cnt; i++) {\n \t\tint cmp = 0; /* avoid compiler stupidity */\n@@ -331,10 +360,10 @@ const char *help_unknown_cmd(const char *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\twhile (n < nr_common &&\n \t\t       (cmp = strcmp(common_cmds[n].name, candidate)) < 0)\n \t\t\tn++;\n-\t\tif ((n < ARRAY_SIZE(common_cmds)) && !cmp) {\n+\t\tif ((n < nr_common) && !cmp) {\n \t\t\t/* Yes, this is one of the common commands */\n \t\t\tn++; /* use the entry from common_cmds[] */\n \t\t\tif (starts_with(candidate, cmd)) {\n@@ -347,6 +376,7 @@ const char *help_unknown_cmd(const char *cmd)\n \t\tmain_cmds.names[i]->len =\n \t\t\tlevenshtein(cmd, candidate, 0, 2, 1, 3) + 1;\n \t}\n+\tFREE_AND_NULL(common_cmds);\n \n \tQSORT(main_cmds.names, main_cmds.cnt, levenshtein_compare);\n \n-- \n2.17.0.367.g5dd2e386c3\n\n"},{"id":"344730","messageId":"20180415164238.9107-7-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180415164238.9107-1-pclouds@gmail.com","subject":"[PATCH v2 6/6] help: use command-list.txt for the source of guides","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-15T16:42:38Z","receivedAt":"2018-04-15T16:46:05Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The help command currently hard codes the list of guides and their\nsummary in C. Let's move this list to command-list.txt. This lets us\nextract summary lines from Documentation/git*.txt. This also\npotentially lets us lists guides in git.txt, but I'll leave that for\nnow.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/gitattributes.txt |  2 +-\n Documentation/gitmodules.txt    |  2 +-\n Documentation/gitrevisions.txt  |  2 +-\n builtin/help.c                  | 32 --------------------------------\n command-list.txt                |  8 ++++++++\n generate-cmdlist.sh             |  6 +++++-\n help.c                          | 22 ++++++++++++++++++++++\n help.h                          |  1 +\n 8 files changed, 39 insertions(+), 36 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex 1094fe2b5b..083c2f380d 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -3,7 +3,7 @@ gitattributes(5)\n \n NAME\n ----\n-gitattributes - defining attributes per path\n+gitattributes - Defining attributes per path\n \n SYNOPSIS\n --------\ndiff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt\nindex db5d47eb19..4d63def206 100644\n--- a/Documentation/gitmodules.txt\n+++ b/Documentation/gitmodules.txt\n@@ -3,7 +3,7 @@ gitmodules(5)\n \n NAME\n ----\n-gitmodules - defining submodule properties\n+gitmodules - Defining submodule properties\n \n SYNOPSIS\n --------\ndiff --git a/Documentation/gitrevisions.txt b/Documentation/gitrevisions.txt\nindex 27dec5b91d..1f6cceaefb 100644\n--- a/Documentation/gitrevisions.txt\n+++ b/Documentation/gitrevisions.txt\n@@ -3,7 +3,7 @@ gitrevisions(7)\n \n NAME\n ----\n-gitrevisions - specifying revisions and ranges for Git\n+gitrevisions - Specifying revisions and ranges for Git\n \n SYNOPSIS\n --------\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 0e0af8426a..5727fb5e51 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -402,38 +402,6 @@ static void show_html_page(const char *git_cmd)\n \topen_html(page_path.buf);\n }\n \n-static struct {\n-\tconst char *name;\n-\tconst char *help;\n-} common_guides[] = {\n-\t{ \"attributes\", N_(\"Defining attributes per path\") },\n-\t{ \"everyday\", N_(\"Everyday Git With 20 Commands Or So\") },\n-\t{ \"glossary\", N_(\"A Git glossary\") },\n-\t{ \"ignore\", N_(\"Specifies intentionally untracked files to ignore\") },\n-\t{ \"modules\", N_(\"Defining submodule properties\") },\n-\t{ \"revisions\", N_(\"Specifying revisions and ranges for Git\") },\n-\t{ \"tutorial\", N_(\"A tutorial introduction to Git (for version 1.5.1 or newer)\") },\n-\t{ \"workflows\", N_(\"An overview of recommended workflows with Git\") },\n-};\n-\n-static void list_common_guides_help(void)\n-{\n-\tint i, longest = 0;\n-\n-\tfor (i = 0; i < ARRAY_SIZE(common_guides); i++) {\n-\t\tif (longest < strlen(common_guides[i].name))\n-\t\t\tlongest = strlen(common_guides[i].name);\n-\t}\n-\n-\tputs(_(\"The common Git guides are:\\n\"));\n-\tfor (i = 0; i < ARRAY_SIZE(common_guides); i++) {\n-\t\tprintf(\"   %s   \", common_guides[i].name);\n-\t\tmput_char(' ', longest - strlen(common_guides[i].name));\n-\t\tputs(_(common_guides[i].help));\n-\t}\n-\tputchar('\\n');\n-}\n-\n static const char *check_git_cmd(const char* cmd)\n {\n \tchar *alias;\ndiff --git a/command-list.txt b/command-list.txt\nindex a1fad28fd8..0809a19184 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -149,3 +149,11 @@ gitweb                                  ancillaryinterrogators\n git-whatchanged                         ancillaryinterrogators\n git-worktree                            mainporcelain\n git-write-tree                          plumbingmanipulators\n+gitattributes                           guide\n+giteveryday                             guide\n+gitglossary                             guide\n+gitignore                               guide\n+gitmodules                              guide\n+gitrevisions                            guide\n+gittutorial                             guide\n+gitworkflows                            guide\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex e0893e979a..e35f3e357b 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -67,7 +67,11 @@ command_list \"$1\" |\n sort |\n while read cmd category tags\n do\n-\tname=${cmd/git-}\n+\tif [ \"$category\" = guide ]; then\n+\t\tname=${cmd/git}\n+\telse\n+\t\tname=${cmd/git-}\n+\tfi\n \tsed -n '\n \t\t/^NAME/,/'\"$cmd\"'/H\n \t\t${\ndiff --git a/help.c b/help.c\nindex 7f72051641..a44f4a113e 100644\n--- a/help.c\n+++ b/help.c\n@@ -313,6 +313,28 @@ static void list_commands_by_category(int cat, struct cmdname_help *cmds,\n \t}\n }\n \n+void list_common_guides_help(void)\n+{\n+\tint i, longest = 0;\n+\tint nr = ARRAY_SIZE(command_list);\n+\tstruct cmdname_help *cmds = command_list;\n+\n+\tQSORT(cmds, nr, cmd_category_cmp);\n+\n+\tfor (i = 0; i < nr; i++) {\n+\t\tstruct cmdname_help *cmd = cmds + i;\n+\n+\t\tif (cmd->category != CAT_guide)\n+\t\t\tcontinue;\n+\t\tif (longest < strlen(cmd->name))\n+\t\t\tlongest = strlen(cmd->name);\n+\t}\n+\n+\tputs(_(\"The common Git guides are:\\n\"));\n+\tlist_commands_by_category(CAT_guide, cmds, nr, longest);\n+\tputchar('\\n');\n+}\n+\n void list_all_cmds_help(void)\n {\n \tint i, longest = 0;\ndiff --git a/help.h b/help.h\nindex 62449f1b7e..de094e9e65 100644\n--- a/help.h\n+++ b/help.h\n@@ -18,6 +18,7 @@ static inline void mput_char(char c, unsigned int num)\n \n extern void list_common_cmds_help(void);\n extern void list_all_cmds_help(void);\n+extern void list_common_guides_help(void);\n extern void list_all_cmds(void);\n extern void list_porcelain_cmds(void);\n extern const char *help_unknown_cmd(const char *cmd);\n-- \n2.17.0.367.g5dd2e386c3\n\n"},{"id":"344731","messageId":"20180415164238.9107-3-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180415164238.9107-1-pclouds@gmail.com","subject":"[PATCH v2 2/6] git.c: implement --list-cmds=all and use it in git-completion.bash","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-15T16:42:34Z","receivedAt":"2018-04-15T16:46:07Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash |  2 +-\n git.c                                  |  2 ++\n help.c                                 | 18 ++++++++++++++++++\n help.h                                 |  1 +\n 4 files changed, 22 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 3556838759..a5f13ade20 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -839,7 +839,7 @@ __git_commands () {\n \tthen\n \t\tprintf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n \telse\n-\t\tgit help -a|egrep '^  [a-zA-Z0-9]'\n+\t\tgit --list-cmds=all\n \tfi\n }\n \ndiff --git a/git.c b/git.c\nindex 28bfa96d87..64f67e7f7f 100644\n--- a/git.c\n+++ b/git.c\n@@ -228,6 +228,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t\tlist_builtins(0, '\\n');\n \t\t\telse if (!strcmp(cmd, \"parseopt\"))\n \t\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n+\t\t\telse if (!strcmp(cmd, \"all\"))\n+\t\t\t\tlist_all_cmds();\n \t\t\telse\n \t\t\t\tdie(\"unsupported command listing type '%s'\", cmd);\n \t\t\texit(0);\ndiff --git a/help.c b/help.c\nindex 60071a9bea..e155c39870 100644\n--- a/help.c\n+++ b/help.c\n@@ -228,6 +228,24 @@ void list_common_cmds_help(void)\n \t}\n }\n \n+void list_all_cmds(void)\n+{\n+\tstruct cmdnames main_cmds, other_cmds;\n+\tint i;\n+\n+\tmemset(&main_cmds, 0, sizeof(main_cmds));\n+\tmemset(&other_cmds, 0, sizeof(other_cmds));\n+\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n+\n+\tfor (i = 0; i < main_cmds.cnt; i++)\n+\t\tputs(main_cmds.names[i]->name);\n+\tfor (i = 0; i < other_cmds.cnt; i++)\n+\t\tputs(other_cmds.names[i]->name);\n+\n+\tclean_cmdnames(&main_cmds);\n+\tclean_cmdnames(&other_cmds);\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex b21d7c94e8..0bf29f8dc5 100644\n--- a/help.h\n+++ b/help.h\n@@ -17,6 +17,7 @@ static inline void mput_char(char c, unsigned int num)\n }\n \n extern void list_common_cmds_help(void);\n+extern void list_all_cmds(void);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\n-- \n2.17.0.367.g5dd2e386c3\n\n"},{"id":"344732","messageId":"20180415164238.9107-6-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180415164238.9107-1-pclouds@gmail.com","subject":"[PATCH v2 5/6] help: add \"-a --verbose\" to list all commands with synopsis","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-15T16:42:37Z","receivedAt":"2018-04-15T16:46:09Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This lists all recognized commands [1] by category. The group order\nfollows closely git.txt.\n\n[1] We may actually show commands that are not built (e.g. if you set\nNO_PERL you don't have git-instaweb but it's still listed here). I\nignore the problem because on Linux a git package could be split\nanyway. The \"git-core\" package may not contain git-instaweb even if\nit's built because it may end up in a separate package. We can't know\nanyway.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-help.txt |  4 ++-\n builtin/help.c             |  7 ++++\n help.c                     | 69 ++++++++++++++++++++++++++++++++++++++\n help.h                     |  1 +\n 4 files changed, 80 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-help.txt b/Documentation/git-help.txt\nindex 40d328a4b3..a40fc38d8b 100644\n--- a/Documentation/git-help.txt\n+++ b/Documentation/git-help.txt\n@@ -8,7 +8,7 @@ git-help - Display help information about Git\n SYNOPSIS\n --------\n [verse]\n-'git help' [-a|--all] [-g|--guide]\n+'git help' [-a|--all [--verbose]] [-g|--guide]\n \t   [-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE]\n \n DESCRIPTION\n@@ -42,6 +42,8 @@ OPTIONS\n --all::\n \tPrints all the available commands on the standard output. This\n \toption overrides any given command or guide name.\n+\tWhen used with `--verbose` print description for all recognized\n+\tcommands.\n \n -g::\n --guides::\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 598867cfea..0e0af8426a 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -36,6 +36,7 @@ static const char *html_path;\n \n static int show_all = 0;\n static int show_guides = 0;\n+static int verbose;\n static unsigned int colopts;\n static enum help_format help_format = HELP_FORMAT_NONE;\n static int exclude_guides;\n@@ -48,6 +49,7 @@ static struct option builtin_help_options[] = {\n \t\t\tHELP_FORMAT_WEB),\n \tOPT_SET_INT('i', \"info\", &help_format, N_(\"show info page\"),\n \t\t\tHELP_FORMAT_INFO),\n+\tOPT__VERBOSE(&verbose, N_(\"print command description\")),\n \tOPT_END(),\n };\n \n@@ -463,6 +465,11 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \tif (show_all) {\n \t\tgit_config(git_help_config, NULL);\n+\t\tif (verbose) {\n+\t\t\tsetup_pager();\n+\t\t\tlist_all_cmds_help();\n+\t\t\treturn 0;\n+\t\t}\n \t\tprintf(_(\"usage: %s%s\"), _(git_usage_string), \"\\n\\n\");\n \t\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n \t\tlist_commands(colopts, &main_cmds, &other_cmds);\ndiff --git a/help.c b/help.c\nindex 1523ca175c..7f72051641 100644\n--- a/help.c\n+++ b/help.c\n@@ -284,6 +284,75 @@ void list_porcelain_cmds(void)\n \t}\n }\n \n+static int cmd_category_cmp(const void *elem1, const void *elem2)\n+{\n+\tconst struct cmdname_help *e1 = elem1;\n+\tconst struct cmdname_help *e2 = elem2;\n+\n+\tif (e1->category < e2->category)\n+\t\treturn -1;\n+\tif (e1->category > e2->category)\n+\t\treturn 1;\n+\treturn strcmp(e1->name, e2->name);\n+}\n+\n+static void list_commands_by_category(int cat, struct cmdname_help *cmds,\n+\t\t\t\t      int nr, int longest)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < nr; i++) {\n+\t\tstruct cmdname_help *cmd = cmds + i;\n+\n+\t\tif (cmd->category != cat)\n+\t\t\tcontinue;\n+\n+\t\tprintf(\"   %s   \", cmd->name);\n+\t\tmput_char(' ', longest - strlen(cmd->name));\n+\t\tputs(_(cmd->help));\n+\t}\n+}\n+\n+void list_all_cmds_help(void)\n+{\n+\tint i, longest = 0;\n+\tint nr = ARRAY_SIZE(command_list);\n+\tstruct cmdname_help *cmds = command_list;\n+\n+\tfor (i = 0; i < nr; i++) {\n+\t\tstruct cmdname_help *cmd = cmds + i;\n+\n+\t\tif (longest < strlen(cmd->name))\n+\t\t\tlongest = strlen(cmd->name);\n+\t}\n+\n+\tQSORT(cmds, nr, cmd_category_cmp);\n+\n+\tprintf(\"%s\\n\\n\", _(\"Main Porcelain Commands\"));\n+\tlist_commands_by_category(CAT_mainporcelain, cmds, nr, longest);\n+\n+\tprintf(\"\\n%s\\n\\n\", _(\"Ancillary Commands / Manipulators\"));\n+\tlist_commands_by_category(CAT_ancillarymanipulators, cmds, nr, longest);\n+\n+\tprintf(\"\\n%s\\n\\n\", _(\"Ancillary Commands / Interrogators\"));\n+\tlist_commands_by_category(CAT_ancillaryinterrogators, cmds, nr, longest);\n+\n+\tprintf(\"\\n%s\\n\\n\", _(\"Interacting with Others\"));\n+\tlist_commands_by_category(CAT_foreignscminterface, cmds, nr, longest);\n+\n+\tprintf(\"\\n%s\\n\\n\", _(\"Low-level Commands / Manipulators\"));\n+\tlist_commands_by_category(CAT_plumbingmanipulators, cmds, nr, longest);\n+\n+\tprintf(\"\\n%s\\n\\n\", _(\"Low-level Commands / Interrogators\"));\n+\tlist_commands_by_category(CAT_plumbinginterrogators, cmds, nr, longest);\n+\n+\tprintf(\"\\n%s\\n\\n\", _(\"Low-level Commands / Synching Repositories\"));\n+\tlist_commands_by_category(CAT_synchingrepositories, cmds, nr, longest);\n+\n+\tprintf(\"\\n%s\\n\\n\", _(\"Low-level Commands / Internal Helpers\"));\n+\tlist_commands_by_category(CAT_purehelpers, cmds, nr, longest);\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex 33e2210ebd..62449f1b7e 100644\n--- a/help.h\n+++ b/help.h\n@@ -17,6 +17,7 @@ static inline void mput_char(char c, unsigned int num)\n }\n \n extern void list_common_cmds_help(void);\n+extern void list_all_cmds_help(void);\n extern void list_all_cmds(void);\n extern void list_porcelain_cmds(void);\n extern const char *help_unknown_cmd(const char *cmd);\n-- \n2.17.0.367.g5dd2e386c3\n\n"},{"id":"344756","messageId":"A9B6B3A17C4844C69F8865C01BCFC51A@PhilipOakley","threadId":"48155","inReplyTo":"CACsJy8BqoW_YWBiMoOks+WM5XY7Mmadkd0LUBoUWLDXehx1GZQ@mail.gmail.com","subject":"Re: [PATCH/RFC 0/5] Keep all info in command-list.txt in git binary","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2018-04-15T21:21:04Z","receivedAt":"2018-04-15T21:21:09Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Duy Nguyen\" <pclouds@gmail.com> : Saturday, April 14, 2018 4:44 PM\n> On Thu, Apr 12, 2018 at 12:06 AM, Philip Oakley <philipoakley@iee.org>\n> wrote:\n>> I'm only just catching up, but does/can this series also capture the\n>> non-command guides that are available in git so that the 'git help -g'\n>> can\n>> begin to list them all?\n>\n> It currently does not. But I don't see why it should not. This should\n> allow git.txt to list all the guides too, for people who skip \"git\n> help\" and go hard core mode with \"man git\". Thanks for bringing this\n> up.\n> -- \n> Duy\n>\nIs that something I should add to my todo to add a 'guide' category etc.?\n\nA quick search of public-inbox suggests\nhttps://public-inbox.org/git/1361660761-1932-1-git-send-email-philipoakley@iee.org/\nas being where I first made the suggestions, but it got trimmed back to not\nupdate (be embedded in) the command-list.txt\n\nPhilip\n\n"},{"id":"344769","messageId":"xmqqy3hnyjbr.fsf@gitster-ct.c.googlers.com","threadId":"48155","inReplyTo":"20180415164238.9107-3-pclouds@gmail.com","subject":"Re: [PATCH v2 2/6] git.c: implement --list-cmds=all and use it in git-completion.bash","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-04-16T02:30:00Z","receivedAt":"2018-04-16T02:30:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  contrib/completion/git-completion.bash |  2 +-\n>  git.c                                  |  2 ++\n>  help.c                                 | 18 ++++++++++++++++++\n>  help.h                                 |  1 +\n>  4 files changed, 22 insertions(+), 1 deletion(-)\n>\n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> index 3556838759..a5f13ade20 100644\n> --- a/contrib/completion/git-completion.bash\n> +++ b/contrib/completion/git-completion.bash\n> @@ -839,7 +839,7 @@ __git_commands () {\n>  \tthen\n>  \t\tprintf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n>  \telse\n> -\t\tgit help -a|egrep '^  [a-zA-Z0-9]'\n> +\t\tgit --list-cmds=all\n>  \tfi\n>  }\n\nTo those of us who install a copy of git-completion.bash somewhere\nin $HOME and forget about it, while installing different versions of\nGit all the time for testing, may see breakage caused by an invalid\ncombination of having new completion script with Git that does not\nknow about --list=cmds=<all> option.  I do not think it matters too\nmuch, though ;-)\n\n> +void list_all_cmds(void)\n> +{\n> +\tstruct cmdnames main_cmds, other_cmds;\n> +\tint i;\n> +\n> +\tmemset(&main_cmds, 0, sizeof(main_cmds));\n> +\tmemset(&other_cmds, 0, sizeof(other_cmds));\n> +\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n> +\n> +\tfor (i = 0; i < main_cmds.cnt; i++)\n> +\t\tputs(main_cmds.names[i]->name);\n> +\tfor (i = 0; i < other_cmds.cnt; i++)\n> +\t\tputs(other_cmds.names[i]->name);\n> +\n> +\tclean_cmdnames(&main_cmds);\n> +\tclean_cmdnames(&other_cmds);\n> +}\n> +\n\nOK.\n\nBy reusing load_command_list(), the duplicate-removal logic at its\nend that is used for \"help -a\" kicks in; the above looks good.\n"},{"id":"344770","messageId":"xmqqr2nfyix9.fsf@gitster-ct.c.googlers.com","threadId":"48155","inReplyTo":"20180415164238.9107-4-pclouds@gmail.com","subject":"Re: [PATCH v2 3/6] generate-cmdlist.sh: keep all information in common-cmds.h","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-04-16T02:38:42Z","receivedAt":"2018-04-16T02:38:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> +category_list () {\n> +\tcommand_list \"$1\" | awk '{print $2;}' | sort | uniq\n> +}\n\nPiping output of awk to sort/uniq, instead of processing all inside\nawk within the END block of the script, means that we are wasting\ntwo processes---I do not think we care too much about it, but some\npeople might.\n"},{"id":"344777","messageId":"xmqq36zvy8a5.fsf@gitster-ct.c.googlers.com","threadId":"48155","inReplyTo":"20180415164238.9107-4-pclouds@gmail.com","subject":"Re: [PATCH v2 3/6] generate-cmdlist.sh: keep all information in common-cmds.h","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-04-16T06:28:34Z","receivedAt":"2018-04-16T06:28:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> @@ -23,28 +36,44 @@ sed -n '\n>  \t' \"$1\"\n>  printf '};\\n\\n'\n>  \n> +echo \"#define GROUP_NONE 0xff /* no common group */\"\n\nSome later code forgets about this value, and causes \"git<ENTER>\" to\nsegfault at the end of this entire series.\n\nNamely, here:\n\n> -\tfor (i = 0; i < ARRAY_SIZE(common_cmds); i++) {\n> +\tfor (i = 0; i < nr; i++) {\n>  \t\tif (common_cmds[i].group != current_grp) {\n>  \t\t\tprintf(\"\\n%s\\n\", _(common_cmd_groups[common_cmds[i].group]));\n>  \t\t\tcurrent_grp = common_cmds[i].group;\n\nwhere common_cmd_groups[] gets overrun.\n\nHere is a squash I'll queue on top to keep the tip of 'pu' at least\nbuildable.\n\n help.c | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/help.c b/help.c\nindex a44f4a113e..74591d5ebc 100644\n--- a/help.c\n+++ b/help.c\n@@ -242,7 +242,9 @@ void list_common_cmds_help(void)\n \tputs(_(\"These are common Git commands used in various situations:\"));\n \n \tfor (i = 0; i < nr; i++) {\n-\t\tif (common_cmds[i].group != current_grp) {\n+\t\tif (ARRAY_SIZE(common_cmd_groups) <= common_cmds[i].group)\n+\t\t\t; /* skip */\n+\t\telse if (common_cmds[i].group != current_grp) {\n \t\t\tprintf(\"\\n%s\\n\", _(common_cmd_groups[common_cmds[i].group]));\n \t\t\tcurrent_grp = common_cmds[i].group;\n \t\t}\n\n\n"},{"id":"344796","messageId":"CAM0VKjkns+AsVyMSe2fxzT8a8oqYdNX3qO8mnw2juOgFC7LHYA@mail.gmail.com","threadId":"48155","inReplyTo":"20180415164238.9107-4-pclouds@gmail.com","subject":"Re: [PATCH v2 3/6] generate-cmdlist.sh: keep all information in common-cmds.h","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-04-16T15:43:09Z","receivedAt":"2018-04-16T15:43:15Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Sun, Apr 15, 2018 at 6:42 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> common-cmds.h is used to extract the list of common commands (by\n> group) and a one-line summary of each command. Some information is\n> dropped, for example command category or summary of other commands.\n> Update generate-cmdlist.sh to keep all the information. The extra info\n> will be used shortly.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  generate-cmdlist.sh | 61 +++++++++++++++++++++++++++++++++------------\n>  help.c              | 42 ++++++++++++++++++++++++++-----\n>  2 files changed, 81 insertions(+), 22 deletions(-)\n>\n> diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\n> index eeea4b67ea..e0893e979a 100755\n> --- a/generate-cmdlist.sh\n> +++ b/generate-cmdlist.sh\n\n> -printf 'static struct cmdname_help common_cmds[] = {\\n'\n> -grep -f \"$match\" \"$1\" |\n> -sed 's/^git-//' |\n> +printf 'static struct cmdname_help command_list[] = {\\n'\n> +command_list \"$1\" |\n>  sort |\n> -while read cmd tags\n> +while read cmd category tags\n>  do\n> -       tag=$(echo \"$tags\" | sed \"$substnum; s/[^0-9]//g\")\n> +       name=${cmd/git-}\n\nThere are two issues with this line:\n\n- This is a \"regular\" shell script, therefore it must not use pattern\n  substitution.\n\n- The pattern substitution would remove the string \"git-\" in the middle of\n  the variable as well; I suspect this is undesired.\n\nI think that the remove matching prefix pattern substitution should be\nused here.\n"},{"id":"344797","messageId":"CACsJy8DHRjtWOC+Mt=gW95-UuyswHmGMM=eM0rFguQXeAsoZyA@mail.gmail.com","threadId":"48155","inReplyTo":"xmqq36zvy8a5.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 3/6] generate-cmdlist.sh: keep all information in common-cmds.h","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-16T15:43:24Z","receivedAt":"2018-04-16T15:43:59Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Apr 16, 2018 at 8:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n>\n>> @@ -23,28 +36,44 @@ sed -n '\n>>       ' \"$1\"\n>>  printf '};\\n\\n'\n>>\n>> +echo \"#define GROUP_NONE 0xff /* no common group */\"\n>\n> Some later code forgets about this value, and causes \"git<ENTER>\" to\n> segfault at the end of this entire series.\n>\n> Namely, here:\n>\n>> -     for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {\n>> +     for (i = 0; i < nr; i++) {\n>>               if (common_cmds[i].group != current_grp) {\n>>                       printf(\"\\n%s\\n\", _(common_cmd_groups[common_cmds[i].group]));\n>>                       current_grp = common_cmds[i].group;\n>\n> where common_cmd_groups[] gets overrun.\n\nArgh!! I thought I tested everything. Sorry for the sloppy quality.\n\n>\n> Here is a squash I'll queue on top to keep the tip of 'pu' at least\n> buildable.\n\nThanks. It's actually interesting that we have main porcelain commands\nthat belong to no group. I'll try to classify them so that they show\nup as well.\n\n\n-- \nDuy\n"},{"id":"344805","messageId":"9f5d2533-1012-aaf6-2703-88525236800f@ramsayjones.plus.com","threadId":"48155","inReplyTo":"CAM0VKjkns+AsVyMSe2fxzT8a8oqYdNX3qO8mnw2juOgFC7LHYA@mail.gmail.com","subject":"Re: [PATCH v2 3/6] generate-cmdlist.sh: keep all information in common-cmds.h","fromName":"Ramsay Jones","fromEmail":"ramsay@ramsayjones.plus.com","sentAt":"2018-04-16T16:25:39Z","receivedAt":"2018-04-16T16:25:47Z","isPatch":true,"sender":{"key":"ramsay@ramsayjones.plus.com","avatar":"https://avatars.githubusercontent.com/u/33702710?v=4"},"body":"\n\nOn 16/04/18 16:43, SZEDER Gábor wrote:\n> On Sun, Apr 15, 2018 at 6:42 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n>> common-cmds.h is used to extract the list of common commands (by\n>> group) and a one-line summary of each command. Some information is\n>> dropped, for example command category or summary of other commands.\n>> Update generate-cmdlist.sh to keep all the information. The extra info\n>> will be used shortly.\n>>\n>> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n>> ---\n>>  generate-cmdlist.sh | 61 +++++++++++++++++++++++++++++++++------------\n>>  help.c              | 42 ++++++++++++++++++++++++++-----\n>>  2 files changed, 81 insertions(+), 22 deletions(-)\n>>\n>> diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\n>> index eeea4b67ea..e0893e979a 100755\n>> --- a/generate-cmdlist.sh\n>> +++ b/generate-cmdlist.sh\n> \n>> -printf 'static struct cmdname_help common_cmds[] = {\\n'\n>> -grep -f \"$match\" \"$1\" |\n>> -sed 's/^git-//' |\n>> +printf 'static struct cmdname_help command_list[] = {\\n'\n>> +command_list \"$1\" |\n>>  sort |\n>> -while read cmd tags\n>> +while read cmd category tags\n>>  do\n>> -       tag=$(echo \"$tags\" | sed \"$substnum; s/[^0-9]//g\")\n>> +       name=${cmd/git-}\n> \n> There are two issues with this line:\n> \n> - This is a \"regular\" shell script, therefore it must not use pattern\n>   substitution.\n> \n> - The pattern substitution would remove the string \"git-\" in the middle of\n>   the variable as well; I suspect this is undesired.\n> \n> I think that the remove matching prefix pattern substitution should be\n> used here.\n\n\nThis also, apparently, doesn't work with dash. On cygwin, which has\nbash as /bin/sh, this builds common-cmds.h just fine. On linux, which\nhas dash as /bin/sh, this fails, leaving a truncated file:\n\n  $ bash generate-cmdlist.sh command-list.txt >zzz\n  $ tail -3 zzz\n  \t{\"gitweb\", N_(\"Git web interface (web frontend to Git repositories)\"), CAT_ancillaryinterrogators, GROUP_NONE },\n  \t{\"workflows\", N_(\"An overview of recommended workflows with Git\"), CAT_guide, GROUP_NONE },\n  };\n\n  $ dash generate-cmdlist.sh command-list.txt >zzz\n  generate-cmdlist.sh: 73: generate-cmdlist.sh: Bad substitution\n  $ tail -3 zzz\n\n  static struct cmdname_help command_list[] = {\n  };\n  $ \n\nThis leads to a very broken 'git help'.\n\nATB,\nRamsay Jones\n\n\n"},{"id":"344840","messageId":"xmqqr2newz7k.fsf@gitster-ct.c.googlers.com","threadId":"48155","inReplyTo":"CAM0VKjkns+AsVyMSe2fxzT8a8oqYdNX3qO8mnw2juOgFC7LHYA@mail.gmail.com","subject":"Re: [PATCH v2 3/6] generate-cmdlist.sh: keep all information in common-cmds.h","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-04-16T22:42:07Z","receivedAt":"2018-04-16T22:42:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder.dev@gmail.com> writes:\n\n>> +while read cmd category tags\n>>  do\n>> -       tag=$(echo \"$tags\" | sed \"$substnum; s/[^0-9]//g\")\n>> +       name=${cmd/git-}\n>\n> There are two issues with this line:\n>\n> - This is a \"regular\" shell script, therefore it must not use pattern\n>   substitution.\n\nOops.  I missed that.  Thanks.\n\n>\n> - The pattern substitution would remove the string \"git-\" in the middle of\n>   the variable as well; I suspect this is undesired.\n>\n> I think that the remove matching prefix pattern substitution should be\n> used here.\n"},{"id":"344873","messageId":"CACsJy8BTX=6FsH7-Dc86ExQRfBSNVn9yxD5JrNZyLT9VDQOPEg@mail.gmail.com","threadId":"48155","inReplyTo":"A9B6B3A17C4844C69F8865C01BCFC51A@PhilipOakley","subject":"Re: [PATCH/RFC 0/5] Keep all info in command-list.txt in git binary","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-17T16:24:41Z","receivedAt":"2018-04-17T16:25:17Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Apr 15, 2018 at 11:21 PM, Philip Oakley <philipoakley@iee.org> wrote:\n> From: \"Duy Nguyen\" <pclouds@gmail.com> : Saturday, April 14, 2018 4:44 PM\n>\n>> On Thu, Apr 12, 2018 at 12:06 AM, Philip Oakley <philipoakley@iee.org>\n>> wrote:\n>>>\n>>> I'm only just catching up, but does/can this series also capture the\n>>> non-command guides that are available in git so that the 'git help -g'\n>>> can\n>>> begin to list them all?\n>>\n>>\n>> It currently does not. But I don't see why it should not. This should\n>> allow git.txt to list all the guides too, for people who skip \"git\n>> help\" and go hard core mode with \"man git\". Thanks for bringing this\n>> up.\n>> --\n>> Duy\n>>\n> Is that something I should add to my todo to add a 'guide' category etc.?\n\nI added it too [1]. Not sure if you want anything more on top though.\n\n[1] https://public-inbox.org/git/20180415164238.9107-7-pclouds@gmail.com/T/#u\n-- \nDuy\n"},{"id":"344882","messageId":"20180417164831.GA18563@duynguyen.home","threadId":"48155","inReplyTo":"CACsJy8BTX=6FsH7-Dc86ExQRfBSNVn9yxD5JrNZyLT9VDQOPEg@mail.gmail.com","subject":"Re: [PATCH/RFC 0/5] Keep all info in command-list.txt in git binary","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-17T16:48:31Z","receivedAt":"2018-04-17T16:48:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Apr 17, 2018 at 06:24:41PM +0200, Duy Nguyen wrote:\n> On Sun, Apr 15, 2018 at 11:21 PM, Philip Oakley <philipoakley@iee.org> wrote:\n> > From: \"Duy Nguyen\" <pclouds@gmail.com> : Saturday, April 14, 2018 4:44 PM\n> >\n> >> On Thu, Apr 12, 2018 at 12:06 AM, Philip Oakley <philipoakley@iee.org>\n> >> wrote:\n> >>>\n> >>> I'm only just catching up, but does/can this series also capture the\n> >>> non-command guides that are available in git so that the 'git help -g'\n> >>> can\n> >>> begin to list them all?\n> >>\n> >>\n> >> It currently does not. But I don't see why it should not. This should\n> >> allow git.txt to list all the guides too, for people who skip \"git\n> >> help\" and go hard core mode with \"man git\". Thanks for bringing this\n> >> up.\n> >> --\n> >> Duy\n> >>\n> > Is that something I should add to my todo to add a 'guide' category etc.?\n> \n> I added it too [1]. Not sure if you want anything more on top though.\n\nThe \"anything more\" that at least I had in mind was something like\nthis. Though I'm not sure if it's a good thing to replace a hand\ncrafted section with an automatedly generated one. This patch on top\ncombines the \"SEE ALSO\" and \"FURTHER DOCUMENT\" into one with most of\ndocuments/guides are extracted from command-list.txt\n\n-- 8< --\ndiff --git a/Documentation/Makefile b/Documentation/Makefile\nindex 6232143cb9..3e0ecd2e11 100644\n--- a/Documentation/Makefile\n+++ b/Documentation/Makefile\n@@ -292,6 +292,7 @@ doc.dep : $(docdep_prereqs) $(wildcard *.txt) build-docdep.perl\n \n cmds_txt = cmds-ancillaryinterrogators.txt \\\n \tcmds-ancillarymanipulators.txt \\\n+\tcmds-guide.txt \\\n \tcmds-mainporcelain.txt \\\n \tcmds-plumbinginterrogators.txt \\\n \tcmds-plumbingmanipulators.txt \\\ndiff --git a/Documentation/cmd-list.perl b/Documentation/cmd-list.perl\nindex 5aa73cfe45..e158bd9b96 100755\n--- a/Documentation/cmd-list.perl\n+++ b/Documentation/cmd-list.perl\n@@ -54,6 +54,7 @@ for (sort <>) {\n \n for my $cat (qw(ancillaryinterrogators\n \t\tancillarymanipulators\n+\t\tguide\n \t\tmainporcelain\n \t\tplumbinginterrogators\n \t\tplumbingmanipulators\ndiff --git a/Documentation/git.txt b/Documentation/git.txt\nindex 4767860e72..d60d2ae0c7 100644\n--- a/Documentation/git.txt\n+++ b/Documentation/git.txt\n@@ -808,29 +808,6 @@ The index is also capable of storing multiple entries (called \"stages\")\n for a given pathname.  These stages are used to hold the various\n unmerged version of a file when a merge is in progress.\n \n-FURTHER DOCUMENTATION\n----------------------\n-\n-See the references in the \"description\" section to get started\n-using Git.  The following is probably more detail than necessary\n-for a first-time user.\n-\n-The link:user-manual.html#git-concepts[Git concepts chapter of the\n-user-manual] and linkgit:gitcore-tutorial[7] both provide\n-introductions to the underlying Git architecture.\n-\n-See linkgit:gitworkflows[7] for an overview of recommended workflows.\n-\n-See also the link:howto-index.html[howto] documents for some useful\n-examples.\n-\n-The internals are documented in the\n-link:technical/api-index.html[Git API documentation].\n-\n-Users migrating from CVS may also want to\n-read linkgit:gitcvs-migration[7].\n-\n-\n Authors\n -------\n Git was started by Linus Torvalds, and is currently maintained by Junio\n@@ -854,11 +831,16 @@ the Git Security mailing list <git-security@googlegroups.com>.\n \n SEE ALSO\n --------\n-linkgit:gittutorial[7], linkgit:gittutorial-2[7],\n-linkgit:giteveryday[7], linkgit:gitcvs-migration[7],\n-linkgit:gitglossary[7], linkgit:gitcore-tutorial[7],\n-linkgit:gitcli[7], link:user-manual.html[The Git User's Manual],\n-linkgit:gitworkflows[7]\n+\n+See the references in the \"description\" section to get started\n+using Git.  The following is probably more detail than necessary\n+for a first-time user.\n+\n+include::cmds-guide.txt[]\n+\n+See also the link:howto-index.html[howto] documents for some useful\n+examples. The internals are documented in the\n+link:technical/api-index.html[Git API documentation].\n \n GIT\n ---\ndiff --git a/command-list.txt b/command-list.txt\nindex 1835f1a928..f26b8acd52 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -150,10 +150,14 @@ git-whatchanged                         ancillaryinterrogators\n git-worktree                            mainporcelain\n git-write-tree                          plumbingmanipulators\n gitattributes                           guide\n+gitcvs-migration                        guide\n+gitcli                                  guide\n+gitcore-tutorial                        guide\n giteveryday                             guide\n gitglossary                             guide\n gitignore                               guide\n gitmodules                              guide\n gitrevisions                            guide\n gittutorial                             guide\n+gittutorial-2                           guide\n gitworkflows                            guide\n-- 8< --\n"},{"id":"344951","messageId":"8F15D4F40F164250987F5DD3896AD825@PhilipOakley","threadId":"48155","inReplyTo":"20180417164831.GA18563@duynguyen.home","subject":"Re: [PATCH/RFC 0/5] Keep all info in command-list.txt in git binary","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2018-04-17T22:47:15Z","receivedAt":"2018-04-17T22:47:29Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Duy Nguyen\" <pclouds@gmail.com> : Tuesday, April 17, 2018 5:48 PM\n> On Tue, Apr 17, 2018 at 06:24:41PM +0200, Duy Nguyen wrote:\n>> On Sun, Apr 15, 2018 at 11:21 PM, Philip Oakley <philipoakley@iee.org> \n>> wrote:\n>> > From: \"Duy Nguyen\" <pclouds@gmail.com> : Saturday, April 14, 2018 4:44 \n>> > PM\n>> >\n>> >> On Thu, Apr 12, 2018 at 12:06 AM, Philip Oakley <philipoakley@iee.org>\n>> >> wrote:\n>> >>>\n>> >>> I'm only just catching up, but does/can this series also capture the\n>> >>> non-command guides that are available in git so that the 'git \n>> >>> help -g'\n>> >>> can\n>> >>> begin to list them all?\n>> >>\n>> >>\n>> >> It currently does not. But I don't see why it should not. This should\n>> >> allow git.txt to list all the guides too, for people who skip \"git\n>> >> help\" and go hard core mode with \"man git\". Thanks for bringing this\n>> >> up.\n>> >> --\n>> >> Duy\n>> >>\n>> > Is that something I should add to my todo to add a 'guide' category \n>> > etc.?\n>>\n>> I added it too [1]. Not sure if you want anything more on top though.\n\nWhat I've seen is looking good - I've not had as much time as I'd like..\n\nI'm not sure of the status of the git/generate-cmdlist.sh though. Should \nthat also be updated, or did I miss that?\n--\nPhilip\n\n>\n> The \"anything more\" that at least I had in mind was something like\n> this. Though I'm not sure if it's a good thing to replace a hand\n> crafted section with an automatedly generated one. This patch on top\n> combines the \"SEE ALSO\" and \"FURTHER DOCUMENT\" into one with most of\n> documents/guides are extracted from command-list.txt\n>\n> -- 8< --\n> diff --git a/Documentation/Makefile b/Documentation/Makefile\n> index 6232143cb9..3e0ecd2e11 100644\n> --- a/Documentation/Makefile\n> +++ b/Documentation/Makefile\n> @@ -292,6 +292,7 @@ doc.dep : $(docdep_prereqs) $(wildcard *.txt) \n> build-docdep.perl\n>\n> cmds_txt = cmds-ancillaryinterrogators.txt \\\n>  cmds-ancillarymanipulators.txt \\\n> + cmds-guide.txt \\\n>  cmds-mainporcelain.txt \\\n>  cmds-plumbinginterrogators.txt \\\n>  cmds-plumbingmanipulators.txt \\\n> diff --git a/Documentation/cmd-list.perl b/Documentation/cmd-list.perl\n> index 5aa73cfe45..e158bd9b96 100755\n> --- a/Documentation/cmd-list.perl\n> +++ b/Documentation/cmd-list.perl\n> @@ -54,6 +54,7 @@ for (sort <>) {\n>\n> for my $cat (qw(ancillaryinterrogators\n>  ancillarymanipulators\n> + guide\n>  mainporcelain\n>  plumbinginterrogators\n>  plumbingmanipulators\n> diff --git a/Documentation/git.txt b/Documentation/git.txt\n> index 4767860e72..d60d2ae0c7 100644\n> --- a/Documentation/git.txt\n> +++ b/Documentation/git.txt\n> @@ -808,29 +808,6 @@ The index is also capable of storing multiple entries \n> (called \"stages\")\n> for a given pathname.  These stages are used to hold the various\n> unmerged version of a file when a merge is in progress.\n>\n> -FURTHER DOCUMENTATION\n> ----------------------\n> -\n> -See the references in the \"description\" section to get started\n> -using Git.  The following is probably more detail than necessary\n> -for a first-time user.\n> -\n> -The link:user-manual.html#git-concepts[Git concepts chapter of the\n> -user-manual] and linkgit:gitcore-tutorial[7] both provide\n> -introductions to the underlying Git architecture.\n> -\n> -See linkgit:gitworkflows[7] for an overview of recommended workflows.\n> -\n> -See also the link:howto-index.html[howto] documents for some useful\n> -examples.\n> -\n> -The internals are documented in the\n> -link:technical/api-index.html[Git API documentation].\n> -\n> -Users migrating from CVS may also want to\n> -read linkgit:gitcvs-migration[7].\n> -\n> -\n> Authors\n> -------\n> Git was started by Linus Torvalds, and is currently maintained by Junio\n> @@ -854,11 +831,16 @@ the Git Security mailing list \n> <git-security@googlegroups.com>.\n>\n> SEE ALSO\n> --------\n> -linkgit:gittutorial[7], linkgit:gittutorial-2[7],\n> -linkgit:giteveryday[7], linkgit:gitcvs-migration[7],\n> -linkgit:gitglossary[7], linkgit:gitcore-tutorial[7],\n> -linkgit:gitcli[7], link:user-manual.html[The Git User's Manual],\n> -linkgit:gitworkflows[7]\n> +\n> +See the references in the \"description\" section to get started\n> +using Git.  The following is probably more detail than necessary\n> +for a first-time user.\n> +\n> +include::cmds-guide.txt[]\n> +\n> +See also the link:howto-index.html[howto] documents for some useful\n> +examples. The internals are documented in the\n> +link:technical/api-index.html[Git API documentation].\n>\n> GIT\n> ---\n> diff --git a/command-list.txt b/command-list.txt\n> index 1835f1a928..f26b8acd52 100644\n> --- a/command-list.txt\n> +++ b/command-list.txt\n> @@ -150,10 +150,14 @@ git-whatchanged \n> ancillaryinterrogators\n> git-worktree                            mainporcelain\n> git-write-tree                          plumbingmanipulators\n> gitattributes                           guide\n> +gitcvs-migration                        guide\n> +gitcli                                  guide\n> +gitcore-tutorial                        guide\n> giteveryday                             guide\n> gitglossary                             guide\n> gitignore                               guide\n> gitmodules                              guide\n> gitrevisions                            guide\n> gittutorial                             guide\n> +gittutorial-2                           guide\n> gitworkflows                            guide\n> -- 8< --\n> \n\n"},{"id":"344971","messageId":"07E7F55C217E47F9A321BC23CF769019@PhilipOakley","threadId":"48155","inReplyTo":"8F15D4F40F164250987F5DD3896AD825@PhilipOakley","subject":"Re: [PATCH/RFC 0/5] Keep all info in command-list.txt in git binary","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2018-04-18T06:38:05Z","receivedAt":"2018-04-18T06:38:14Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Philip Oakley\" <philipoakley@iee.org> : Tuesday, April 17, 2018 11:47\nPM\n> From: \"Duy Nguyen\" <pclouds@gmail.com> : Tuesday, April 17, 2018 5:48 PM\n>> On Tue, Apr 17, 2018 at 06:24:41PM +0200, Duy Nguyen wrote:\n>>> On Sun, Apr 15, 2018 at 11:21 PM, Philip Oakley <philipoakley@iee.org>\n>>> wrote:\n>>> > From: \"Duy Nguyen\" <pclouds@gmail.com> : Saturday, April 14, 2018 4:44\n>>> > PM\n>>> >\n>>> >> On Thu, Apr 12, 2018 at 12:06 AM, Philip Oakley\n>>> >> <philipoakley@iee.org>\n>>> >> wrote:\n>>> >>>\n>>> >>> I'm only just catching up, but does/can this series also capture the\n>>> >>> non-command guides that are available in git so that the 'git\n>>> >>> help -g'\n>>> >>> can\n>>> >>> begin to list them all?\n>>> >>\n>>> >>\n>>> >> It currently does not. But I don't see why it should not. This should\n>>> >> allow git.txt to list all the guides too, for people who skip \"git\n>>> >> help\" and go hard core mode with \"man git\". Thanks for bringing this\n>>> >> up.\n>>> >> --\n>>> >> Duy\n>>> >>\n>>> > Is that something I should add to my todo to add a 'guide' category\n>>> > etc.?\n>>>\n>>> I added it too [1]. Not sure if you want anything more on top though.\n>\n> What I've seen is looking good - I've not had as much time as I'd like..\n>\n> I'm not sure of the status of the git/generate-cmdlist.sh though. Should\n> that also be updated, or did I miss that?\n> --\n> Philip\n\nI may be miss-remembering the order that the `git help` determines the list\nof commands and guides. There was at least one place where the list of\ncommands was generated programatically that I may be confused with (I've not\nhad time to delve into the code :-(\n--\n\n\n>\n>>\n>> The \"anything more\" that at least I had in mind was something like\n>> this. Though I'm not sure if it's a good thing to replace a hand\n>> crafted section with an automatedly generated one. This patch on top\n>> combines the \"SEE ALSO\" and \"FURTHER DOCUMENT\" into one with most of\n>> documents/guides are extracted from command-list.txt\n>>\n>> -- 8< --\n>> diff --git a/Documentation/Makefile b/Documentation/Makefile\n>> index 6232143cb9..3e0ecd2e11 100644\n>> --- a/Documentation/Makefile\n>> +++ b/Documentation/Makefile\n>> @@ -292,6 +292,7 @@ doc.dep : $(docdep_prereqs) $(wildcard *.txt)\n>> build-docdep.perl\n>>\n>> cmds_txt = cmds-ancillaryinterrogators.txt \\\n>>  cmds-ancillarymanipulators.txt \\\n>> + cmds-guide.txt \\\n>>  cmds-mainporcelain.txt \\\n>>  cmds-plumbinginterrogators.txt \\\n>>  cmds-plumbingmanipulators.txt \\\n>> diff --git a/Documentation/cmd-list.perl b/Documentation/cmd-list.perl\n>> index 5aa73cfe45..e158bd9b96 100755\n>> --- a/Documentation/cmd-list.perl\n>> +++ b/Documentation/cmd-list.perl\n>> @@ -54,6 +54,7 @@ for (sort <>) {\n>>\n>> for my $cat (qw(ancillaryinterrogators\n>>  ancillarymanipulators\n>> + guide\n>>  mainporcelain\n>>  plumbinginterrogators\n>>  plumbingmanipulators\n>> diff --git a/Documentation/git.txt b/Documentation/git.txt\n>> index 4767860e72..d60d2ae0c7 100644\n>> --- a/Documentation/git.txt\n>> +++ b/Documentation/git.txt\n>> @@ -808,29 +808,6 @@ The index is also capable of storing multiple\n>> entries (called \"stages\")\n>> for a given pathname.  These stages are used to hold the various\n>> unmerged version of a file when a merge is in progress.\n>>\n>> -FURTHER DOCUMENTATION\n>> ----------------------\n>> -\n>> -See the references in the \"description\" section to get started\n>> -using Git.  The following is probably more detail than necessary\n>> -for a first-time user.\n>> -\n>> -The link:user-manual.html#git-concepts[Git concepts chapter of the\n>> -user-manual] and linkgit:gitcore-tutorial[7] both provide\n>> -introductions to the underlying Git architecture.\n>> -\n>> -See linkgit:gitworkflows[7] for an overview of recommended workflows.\n>> -\n>> -See also the link:howto-index.html[howto] documents for some useful\n>> -examples.\n>> -\n>> -The internals are documented in the\n>> -link:technical/api-index.html[Git API documentation].\n>> -\n>> -Users migrating from CVS may also want to\n>> -read linkgit:gitcvs-migration[7].\n>> -\n>> -\n>> Authors\n>> -------\n>> Git was started by Linus Torvalds, and is currently maintained by Junio\n>> @@ -854,11 +831,16 @@ the Git Security mailing list\n>> <git-security@googlegroups.com>.\n>>\n>> SEE ALSO\n>> --------\n>> -linkgit:gittutorial[7], linkgit:gittutorial-2[7],\n>> -linkgit:giteveryday[7], linkgit:gitcvs-migration[7],\n>> -linkgit:gitglossary[7], linkgit:gitcore-tutorial[7],\n>> -linkgit:gitcli[7], link:user-manual.html[The Git User's Manual],\n>> -linkgit:gitworkflows[7]\n>> +\n>> +See the references in the \"description\" section to get started\n>> +using Git.  The following is probably more detail than necessary\n>> +for a first-time user.\n>> +\n>> +include::cmds-guide.txt[]\n>> +\n>> +See also the link:howto-index.html[howto] documents for some useful\n>> +examples. The internals are documented in the\n>> +link:technical/api-index.html[Git API documentation].\n>>\n>> GIT\n>> ---\n>> diff --git a/command-list.txt b/command-list.txt\n>> index 1835f1a928..f26b8acd52 100644\n>> --- a/command-list.txt\n>> +++ b/command-list.txt\n>> @@ -150,10 +150,14 @@ git-whatchanged ancillaryinterrogators\n>> git-worktree                            mainporcelain\n>> git-write-tree                          plumbingmanipulators\n>> gitattributes                           guide\n>> +gitcvs-migration                        guide\n>> +gitcli                                  guide\n>> +gitcore-tutorial                        guide\n>> giteveryday                             guide\n>> gitglossary                             guide\n>> gitignore                               guide\n>> gitmodules                              guide\n>> gitrevisions                            guide\n>> gittutorial                             guide\n>> +gittutorial-2                           guide\n>> gitworkflows                            guide\n>> -- 8< --\n>>\n>\n>\n\n"},{"id":"344992","messageId":"CACsJy8APfzL_VchsUT0KgKooijARbMqkcFd6rC4A2v5LV84Gww@mail.gmail.com","threadId":"48155","inReplyTo":"8F15D4F40F164250987F5DD3896AD825@PhilipOakley","subject":"Re: [PATCH/RFC 0/5] Keep all info in command-list.txt in git binary","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-18T15:33:36Z","receivedAt":"2018-04-18T15:34:11Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Apr 18, 2018 at 12:47 AM, Philip Oakley <philipoakley@iee.org> wrote:\n>>> > Is that something I should add to my todo to add a 'guide' category >\n>>> > etc.?\n>>>\n>>> I added it too [1]. Not sure if you want anything more on top though.\n>\n>\n> What I've seen is looking good - I've not had as much time as I'd like..\n>\n> I'm not sure of the status of the git/generate-cmdlist.sh though. Should\n> that also be updated, or did I miss that?\n\nYes it's updated by other patches in the same thread.\n-- \nDuy\n"},{"id":"345067","messageId":"32318E6BB2994998ADFEF47E05F839D4@PhilipOakley","threadId":"48155","inReplyTo":"CACsJy8APfzL_VchsUT0KgKooijARbMqkcFd6rC4A2v5LV84Gww@mail.gmail.com","subject":"Re: [PATCH/RFC 0/5] Keep all info in command-list.txt in git binary","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2018-04-19T07:47:42Z","receivedAt":"2018-04-19T07:47:51Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Duy Nguyen\" <pclouds@gmail.com>\n> On Wed, Apr 18, 2018 at 12:47 AM, Philip Oakley <philipoakley@iee.org>\n> wrote:\n>>>> > Is that something I should add to my todo to add a 'guide' category >\n>>>> > etc.?\n>>>>\n>>>> I added it too [1]. Not sure if you want anything more on top though.\n>>\n>>\n>> What I've seen is looking good - I've not had as much time as I'd like..\n>>\n>> I'm not sure of the status of the git/generate-cmdlist.sh though. Should\n>> that also be updated, or did I miss that?\n>\n> Yes it's updated by other patches in the same thread.\n> -- \nThanks. Hopefully I'll have some time this weekend/coming week as my wife is\naway....\nPhilip\n\n"},{"id":"345085","messageId":"20180419103725.GB19591@ruderich.org","threadId":"48155","inReplyTo":"20180326165520.802-1-pclouds@gmail.com","subject":"Re: [PATCH/RFC 0/5] Keep all info in command-list.txt in git binary","fromName":"Simon Ruderich","fromEmail":"simon@ruderich.org","sentAt":"2018-04-19T10:37:25Z","receivedAt":"2018-04-19T10:42:50Z","isPatch":true,"sender":{"key":"simon@ruderich.org","avatar":"https://avatars.githubusercontent.com/u/390994?v=4"},"body":"Hello,\n\nWhen running make -j$(nproc) with the current pu f9f8c1f765\n(Merge branch 'hn/bisect-first-parent' into pu) I see the\nfollowing error:\n\nGIT_VERSION = 2.17.0.732.gf9f8c1f765\n    * new build flags\n    * new prefix flags\n    GEN common-cmds.h\n    * new link flags\n    CC ident.o\n    CC hex.o\n    CC json-writer.o\n./generate-cmdlist.sh: 73: ./generate-cmdlist.sh: Bad substitution\n\nThis doesn't occur on a non-parallel build.\n\nRegards\nSimon\n-- \n+ privacy is necessary\n+ using gnupg http://gnupg.org\n+ public key id: 0x92FEFDB7E44C32F9\n"},{"id":"345086","messageId":"CAM0VKjkJJv2qLu_8Lx3pY7S1Hu8GCzYbsEw-8wXvBK6XC=KewQ@mail.gmail.com","threadId":"48155","inReplyTo":"20180419103725.GB19591@ruderich.org","subject":"Re: [PATCH/RFC 0/5] Keep all info in command-list.txt in git binary","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-04-19T11:26:18Z","receivedAt":"2018-04-19T11:26:23Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Thu, Apr 19, 2018 at 12:37 PM, Simon Ruderich <simon@ruderich.org> wrote:\n> When running make -j$(nproc) with the current pu f9f8c1f765\n> (Merge branch 'hn/bisect-first-parent' into pu) I see the\n> following error:\n>\n> GIT_VERSION = 2.17.0.732.gf9f8c1f765\n>     * new build flags\n>     * new prefix flags\n>     GEN common-cmds.h\n>     * new link flags\n>     CC ident.o\n>     CC hex.o\n>     CC json-writer.o\n> ./generate-cmdlist.sh: 73: ./generate-cmdlist.sh: Bad substitution\n>\n> This doesn't occur on a non-parallel build.\n\nIt does occur in non-parallel builds, too.\n\nSee:\n\n  https://public-inbox.org/git/CAM0VKjkns+AsVyMSe2fxzT8a8oqYdNX3qO8mnw2juOgFC7LHYA@mail.gmail.com/\n"},{"id":"345189","messageId":"20180420070512.GA13462@ruderich.org","threadId":"48155","inReplyTo":"CAM0VKjkJJv2qLu_8Lx3pY7S1Hu8GCzYbsEw-8wXvBK6XC=KewQ@mail.gmail.com","subject":"Re: [PATCH/RFC 0/5] Keep all info in command-list.txt in git binary","fromName":"Simon Ruderich","fromEmail":"simon@ruderich.org","sentAt":"2018-04-20T07:05:12Z","receivedAt":"2018-04-20T07:05:17Z","isPatch":true,"sender":{"key":"simon@ruderich.org","avatar":"https://avatars.githubusercontent.com/u/390994?v=4"},"body":"On Thu, Apr 19, 2018 at 01:26:18PM +0200, SZEDER Gábor wrote:\n> On Thu, Apr 19, 2018 at 12:37 PM, Simon Ruderich wrote:\n>> This doesn't occur on a non-parallel build.\n>\n> It does occur in non-parallel builds, too.\n>\n> See:\n>\n>   https://public-inbox.org/git/CAM0VKjkns+AsVyMSe2fxzT8a8oqYdNX3qO8mnw2juOgFC7LHYA@mail.gmail.com/\n\nThanks for the correction. I noticed it at the beginning of make\n-j run and incorrectly assummed it would occur quickly in the\nnon-parallel run as well.\n\nRegards\nSimon\n-- \n+ privacy is necessary\n+ using gnupg http://gnupg.org\n+ public key id: 0x92FEFDB7E44C32F9\n"},{"id":"345369","messageId":"20180421165414.30051-1-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180415164238.9107-1-pclouds@gmail.com","subject":"[PATCH v3 0/6] Keep all info in command-list.txt in git binary","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-21T16:54:08Z","receivedAt":"2018-04-21T16:54:34Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Changes:\n\n- remove the deprecated column in command-list.txt. My change break it\n  anyway if anyone uses it.\n- fix up failed tests that I marked in the RFC and kinda forgot about it.\n- fix bashisms in generate-cmdlist.sh\n- fix segfaul in \"git help\"\n\nNguyễn Thái Ngọc Duy (6):\n  git.c: convert --list-*builtins to --list-cmds=*\n  git.c: implement --list-cmds=all and use it in git-completion.bash\n  generate-cmdlist.sh: keep all information in common-cmds.h\n  git.c: implement --list-cmds=porcelain\n  help: add \"-a --verbose\" to list all commands with synopsis\n  help: use command-list.txt for the source of guides\n\n Documentation/git-help.txt             |   4 +-\n Documentation/gitattributes.txt        |   2 +-\n Documentation/gitmodules.txt           |   2 +-\n Documentation/gitrevisions.txt         |   2 +-\n builtin/help.c                         |  39 ++----\n command-list.txt                       |  10 +-\n contrib/completion/git-completion.bash | 108 ++--------------\n generate-cmdlist.sh                    |  57 ++++++---\n git.c                                  |  16 ++-\n help.c                                 | 164 ++++++++++++++++++++++++-\n help.h                                 |   4 +\n t/t0012-help.sh                        |  11 +-\n t/t9902-completion.sh                  |   6 +-\n 13 files changed, 263 insertions(+), 162 deletions(-)\n\n-- \n2.17.0.367.g5dd2e386c3\n\n"},{"id":"345370","messageId":"20180421165414.30051-2-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180421165414.30051-1-pclouds@gmail.com","subject":"[PATCH v3 1/6] git.c: convert --list-*builtins to --list-cmds=*","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-21T16:54:09Z","receivedAt":"2018-04-21T16:54:39Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Even if these are hidden options, let's make them a bit more generic\nsince we're introducing more listing types shortly.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash |  2 +-\n git.c                                  | 12 +++++++-----\n t/t0012-help.sh                        |  2 +-\n 3 files changed, 9 insertions(+), 7 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex a757073945..3556838759 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -3049,7 +3049,7 @@ __git_complete_common () {\n __git_cmds_with_parseopt_helper=\n __git_support_parseopt_helper () {\n \ttest -n \"$__git_cmds_with_parseopt_helper\" ||\n-\t\t__git_cmds_with_parseopt_helper=\"$(__git --list-parseopt-builtins)\"\n+\t\t__git_cmds_with_parseopt_helper=\"$(__git --list-cmds=parseopt)\"\n \n \tcase \" $__git_cmds_with_parseopt_helper \" in\n \t*\" $1 \"*)\ndiff --git a/git.c b/git.c\nindex 3a89893712..28bfa96d87 100644\n--- a/git.c\n+++ b/git.c\n@@ -223,11 +223,13 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t}\n \t\t\t(*argv)++;\n \t\t\t(*argc)--;\n-\t\t} else if (!strcmp(cmd, \"--list-builtins\")) {\n-\t\t\tlist_builtins(0, '\\n');\n-\t\t\texit(0);\n-\t\t} else if (!strcmp(cmd, \"--list-parseopt-builtins\")) {\n-\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n+\t\t} else if (skip_prefix(cmd, \"--list-cmds=\", &cmd)) {\n+\t\t\tif (!strcmp(cmd, \"builtins\"))\n+\t\t\t\tlist_builtins(0, '\\n');\n+\t\t\telse if (!strcmp(cmd, \"parseopt\"))\n+\t\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n+\t\t\telse\n+\t\t\t\tdie(\"unsupported command listing type '%s'\", cmd);\n \t\t\texit(0);\n \t\t} else {\n \t\t\tfprintf(stderr, _(\"unknown option: %s\\n\"), cmd);\ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex 487b92a5de..fd2a7f27dc 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -50,7 +50,7 @@ test_expect_success \"--help does not work for guides\" \"\n \"\n \n test_expect_success 'generate builtin list' '\n-\tgit --list-builtins >builtins\n+\tgit --list-cmds=builtins >builtins\n '\n \n while read builtin\n-- \n2.17.0.367.g5dd2e386c3\n\n"},{"id":"345371","messageId":"20180421165414.30051-3-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180421165414.30051-1-pclouds@gmail.com","subject":"[PATCH v3 2/6] git.c: implement --list-cmds=all and use it in git-completion.bash","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-21T16:54:10Z","receivedAt":"2018-04-21T16:54:40Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash |  2 +-\n git.c                                  |  2 ++\n help.c                                 | 18 ++++++++++++++++++\n help.h                                 |  1 +\n 4 files changed, 22 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 3556838759..a5f13ade20 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -839,7 +839,7 @@ __git_commands () {\n \tthen\n \t\tprintf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n \telse\n-\t\tgit help -a|egrep '^  [a-zA-Z0-9]'\n+\t\tgit --list-cmds=all\n \tfi\n }\n \ndiff --git a/git.c b/git.c\nindex 28bfa96d87..64f67e7f7f 100644\n--- a/git.c\n+++ b/git.c\n@@ -228,6 +228,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t\tlist_builtins(0, '\\n');\n \t\t\telse if (!strcmp(cmd, \"parseopt\"))\n \t\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n+\t\t\telse if (!strcmp(cmd, \"all\"))\n+\t\t\t\tlist_all_cmds();\n \t\t\telse\n \t\t\t\tdie(\"unsupported command listing type '%s'\", cmd);\n \t\t\texit(0);\ndiff --git a/help.c b/help.c\nindex 60071a9bea..e155c39870 100644\n--- a/help.c\n+++ b/help.c\n@@ -228,6 +228,24 @@ void list_common_cmds_help(void)\n \t}\n }\n \n+void list_all_cmds(void)\n+{\n+\tstruct cmdnames main_cmds, other_cmds;\n+\tint i;\n+\n+\tmemset(&main_cmds, 0, sizeof(main_cmds));\n+\tmemset(&other_cmds, 0, sizeof(other_cmds));\n+\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n+\n+\tfor (i = 0; i < main_cmds.cnt; i++)\n+\t\tputs(main_cmds.names[i]->name);\n+\tfor (i = 0; i < other_cmds.cnt; i++)\n+\t\tputs(other_cmds.names[i]->name);\n+\n+\tclean_cmdnames(&main_cmds);\n+\tclean_cmdnames(&other_cmds);\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex b21d7c94e8..0bf29f8dc5 100644\n--- a/help.h\n+++ b/help.h\n@@ -17,6 +17,7 @@ static inline void mput_char(char c, unsigned int num)\n }\n \n extern void list_common_cmds_help(void);\n+extern void list_all_cmds(void);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\n-- \n2.17.0.367.g5dd2e386c3\n\n"},{"id":"345372","messageId":"20180421165414.30051-4-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180421165414.30051-1-pclouds@gmail.com","subject":"[PATCH v3 3/6] generate-cmdlist.sh: keep all information in common-cmds.h","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-21T16:54:11Z","receivedAt":"2018-04-21T16:54:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"common-cmds.h is used to extract the list of common commands (by\ngroup) and a one-line summary of each command. Some information is\ndropped, for example command category or summary of other commands.\nUpdate generate-cmdlist.sh to keep all the information. The extra info\nwill be used shortly.\n\nThe \"deprecated\" column is dropped from command-list.txt since it's\nnot really used and the new parsing code can't deal with it. When we\ndo need deprecated attribute, we could add it back and adjust\ngenerate-cmdlist.sh at the same time.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n command-list.txt    |  2 +-\n generate-cmdlist.sh | 53 +++++++++++++++++++++++++++++++--------------\n help.c              | 43 +++++++++++++++++++++++++++++++-----\n 3 files changed, 75 insertions(+), 23 deletions(-)\n\ndiff --git a/command-list.txt b/command-list.txt\nindex a1fad28fd8..2c81d8db74 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -9,7 +9,7 @@ history      grow, mark and tweak your common history\n remote       collaborate (see also: git help workflows)\n \n ### command list (do not change this line)\n-# command name                          category [deprecated] [common]\n+# command name                          category                [common]\n git-add                                 mainporcelain           worktree\n git-am                                  mainporcelain\n git-annotate                            ancillaryinterrogators\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex eeea4b67ea..05722b1392 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -1,17 +1,30 @@\n #!/bin/sh\n \n+# Don't let locale affect this script.\n+LC_ALL=C\n+LANG=C\n+export LC_ALL LANG\n+\n+command_list () {\n+\tsed '1,/^### command list/d;/^#/d' \"$1\"\n+}\n+\n+category_list () {\n+\tcommand_list \"$1\" | awk '{print $2;}' | sort | uniq\n+}\n+\n echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n-\tchar name[16];\n+\tchar name[32];\n \tchar help[80];\n-\tunsigned char group;\n+\tunsigned int category;\n+\tunsigned int group;\n };\n \n static const char *common_cmd_groups[] = {\"\n \n grps=grps$$.tmp\n-match=match$$.tmp\n-trap \"rm -f '$grps' '$match'\" 0 1 2 3 15\n+trap \"rm -f '$grps'\" 0 1 2 3 15\n \n sed -n '\n \t1,/^### common groups/b\n@@ -23,28 +36,36 @@ sed -n '\n \t' \"$1\"\n printf '};\\n\\n'\n \n+echo \"#define GROUP_NONE 0xff\"\n n=0\n-substnum=\n while read grp\n do\n-\techo \"^git-..*[ \t]$grp\"\n-\tsubstnum=\"$substnum${substnum:+;}s/[ \t]$grp/$n/\"\n+\techo \"#define GROUP_${grp:-NONE} $n\"\n \tn=$(($n+1))\n-done <\"$grps\" >\"$match\"\n+done <\"$grps\"\n+echo\n+\n+n=0\n+category_list \"$1\" |\n+while read category; do\n+\techo \"#define CAT_$category $n\"\n+\tn=$(($n+1))\n+done\n+echo\n \n-printf 'static struct cmdname_help common_cmds[] = {\\n'\n-grep -f \"$match\" \"$1\" |\n-sed 's/^git-//' |\n+printf 'static struct cmdname_help command_list[] = {\\n'\n+command_list \"$1\" |\n sort |\n-while read cmd tags\n+while read cmd category tags\n do\n-\ttag=$(echo \"$tags\" | sed \"$substnum; s/[^0-9]//g\")\n+\tprefix=git-\n+\tname=$(echo $cmd | sed \"s/^${prefix}//\")\n \tsed -n '\n-\t\t/^NAME/,/git-'\"$cmd\"'/H\n+\t\t/^NAME/,/'\"$cmd\"'/H\n \t\t${\n \t\t\tx\n-\t\t\ts/.*git-'\"$cmd\"' - \\(.*\\)/\t{\"'\"$cmd\"'\", N_(\"\\1\"), '$tag'},/\n+\t\t\ts/.*'\"$cmd\"' - \\(.*\\)/\t{\"'\"$name\"'\", N_(\"\\1\"), CAT_'$category', GROUP_'${tags:-NONE}' },/\n \t\t\tp\n-\t\t}' \"Documentation/git-$cmd.txt\"\n+\t\t}' \"Documentation/$cmd.txt\"\n done\n echo \"};\"\ndiff --git a/help.c b/help.c\nindex e155c39870..e63006c333 100644\n--- a/help.c\n+++ b/help.c\n@@ -190,6 +190,28 @@ void list_commands(unsigned int colopts,\n \t}\n }\n \n+static void extract_common_cmds(struct cmdname_help **p_common_cmds,\n+\t\t\t\tint *p_nr)\n+{\n+\tint i, nr = 0;\n+\tstruct cmdname_help *common_cmds;\n+\n+\tALLOC_ARRAY(common_cmds, ARRAY_SIZE(command_list));\n+\n+\tfor (i = 0; i < ARRAY_SIZE(command_list); i++) {\n+\t\tconst struct cmdname_help *cmd = command_list + i;\n+\n+\t\tif (cmd->category != CAT_mainporcelain ||\n+\t\t    cmd->group == GROUP_NONE)\n+\t\t\tcontinue;\n+\n+\t\tcommon_cmds[nr++] = *cmd;\n+\t}\n+\n+\t*p_common_cmds = common_cmds;\n+\t*p_nr = nr;\n+}\n+\n static int cmd_group_cmp(const void *elem1, const void *elem2)\n {\n \tconst struct cmdname_help *e1 = elem1;\n@@ -206,17 +228,21 @@ void list_common_cmds_help(void)\n {\n \tint i, longest = 0;\n \tint current_grp = -1;\n+\tint nr = 0;\n+\tstruct cmdname_help *common_cmds;\n+\n+\textract_common_cmds(&common_cmds, &nr);\n \n-\tfor (i = 0; i < ARRAY_SIZE(common_cmds); i++) {\n+\tfor (i = 0; i < nr; i++) {\n \t\tif (longest < strlen(common_cmds[i].name))\n \t\t\tlongest = strlen(common_cmds[i].name);\n \t}\n \n-\tQSORT(common_cmds, ARRAY_SIZE(common_cmds), cmd_group_cmp);\n+\tQSORT(common_cmds, nr, cmd_group_cmp);\n \n \tputs(_(\"These are common Git commands used in various situations:\"));\n \n-\tfor (i = 0; i < ARRAY_SIZE(common_cmds); i++) {\n+\tfor (i = 0; i < nr; i++) {\n \t\tif (common_cmds[i].group != current_grp) {\n \t\t\tprintf(\"\\n%s\\n\", _(common_cmd_groups[common_cmds[i].group]));\n \t\t\tcurrent_grp = common_cmds[i].group;\n@@ -226,6 +252,7 @@ void list_common_cmds_help(void)\n \t\tmput_char(' ', longest - strlen(common_cmds[i].name));\n \t\tputs(_(common_cmds[i].help));\n \t}\n+\tfree(common_cmds);\n }\n \n void list_all_cmds(void)\n@@ -301,8 +328,9 @@ static const char bad_interpreter_advice[] =\n \n const char *help_unknown_cmd(const char *cmd)\n {\n-\tint i, n, best_similarity = 0;\n+\tint i, n, best_similarity = 0, nr_common;\n \tstruct cmdnames main_cmds, other_cmds;\n+\tstruct cmdname_help *common_cmds;\n \n \tmemset(&main_cmds, 0, sizeof(main_cmds));\n \tmemset(&other_cmds, 0, sizeof(other_cmds));\n@@ -317,6 +345,8 @@ const char *help_unknown_cmd(const char *cmd)\n \tQSORT(main_cmds.names, main_cmds.cnt, cmdname_compare);\n \tuniq(&main_cmds);\n \n+\textract_common_cmds(&common_cmds, &nr_common);\n+\n \t/* This abuses cmdname->len for levenshtein distance */\n \tfor (i = 0, n = 0; i < main_cmds.cnt; i++) {\n \t\tint cmp = 0; /* avoid compiler stupidity */\n@@ -331,10 +361,10 @@ const char *help_unknown_cmd(const char *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\twhile (n < nr_common &&\n \t\t       (cmp = strcmp(common_cmds[n].name, candidate)) < 0)\n \t\t\tn++;\n-\t\tif ((n < ARRAY_SIZE(common_cmds)) && !cmp) {\n+\t\tif ((n < nr_common) && !cmp) {\n \t\t\t/* Yes, this is one of the common commands */\n \t\t\tn++; /* use the entry from common_cmds[] */\n \t\t\tif (starts_with(candidate, cmd)) {\n@@ -347,6 +377,7 @@ const char *help_unknown_cmd(const char *cmd)\n \t\tmain_cmds.names[i]->len =\n \t\t\tlevenshtein(cmd, candidate, 0, 2, 1, 3) + 1;\n \t}\n+\tFREE_AND_NULL(common_cmds);\n \n \tQSORT(main_cmds.names, main_cmds.cnt, levenshtein_compare);\n \n-- \n2.17.0.367.g5dd2e386c3\n\n"},{"id":"345373","messageId":"20180421165414.30051-7-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180421165414.30051-1-pclouds@gmail.com","subject":"[PATCH v3 6/6] help: use command-list.txt for the source of guides","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-21T16:54:14Z","receivedAt":"2018-04-21T16:54:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The help command currently hard codes the list of guides and their\nsummary in C. Let's move this list to command-list.txt. This lets us\nextract summary lines from Documentation/git*.txt. This also\npotentially lets us lists guides in git.txt, but I'll leave that for\nnow.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/gitattributes.txt |  2 +-\n Documentation/gitmodules.txt    |  2 +-\n Documentation/gitrevisions.txt  |  2 +-\n builtin/help.c                  | 32 --------------------------------\n command-list.txt                |  8 ++++++++\n generate-cmdlist.sh             |  6 +++++-\n help.c                          | 22 ++++++++++++++++++++++\n help.h                          |  1 +\n 8 files changed, 39 insertions(+), 36 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex 1094fe2b5b..083c2f380d 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -3,7 +3,7 @@ gitattributes(5)\n \n NAME\n ----\n-gitattributes - defining attributes per path\n+gitattributes - Defining attributes per path\n \n SYNOPSIS\n --------\ndiff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt\nindex db5d47eb19..4d63def206 100644\n--- a/Documentation/gitmodules.txt\n+++ b/Documentation/gitmodules.txt\n@@ -3,7 +3,7 @@ gitmodules(5)\n \n NAME\n ----\n-gitmodules - defining submodule properties\n+gitmodules - Defining submodule properties\n \n SYNOPSIS\n --------\ndiff --git a/Documentation/gitrevisions.txt b/Documentation/gitrevisions.txt\nindex 27dec5b91d..1f6cceaefb 100644\n--- a/Documentation/gitrevisions.txt\n+++ b/Documentation/gitrevisions.txt\n@@ -3,7 +3,7 @@ gitrevisions(7)\n \n NAME\n ----\n-gitrevisions - specifying revisions and ranges for Git\n+gitrevisions - Specifying revisions and ranges for Git\n \n SYNOPSIS\n --------\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 0e0af8426a..5727fb5e51 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -402,38 +402,6 @@ static void show_html_page(const char *git_cmd)\n \topen_html(page_path.buf);\n }\n \n-static struct {\n-\tconst char *name;\n-\tconst char *help;\n-} common_guides[] = {\n-\t{ \"attributes\", N_(\"Defining attributes per path\") },\n-\t{ \"everyday\", N_(\"Everyday Git With 20 Commands Or So\") },\n-\t{ \"glossary\", N_(\"A Git glossary\") },\n-\t{ \"ignore\", N_(\"Specifies intentionally untracked files to ignore\") },\n-\t{ \"modules\", N_(\"Defining submodule properties\") },\n-\t{ \"revisions\", N_(\"Specifying revisions and ranges for Git\") },\n-\t{ \"tutorial\", N_(\"A tutorial introduction to Git (for version 1.5.1 or newer)\") },\n-\t{ \"workflows\", N_(\"An overview of recommended workflows with Git\") },\n-};\n-\n-static void list_common_guides_help(void)\n-{\n-\tint i, longest = 0;\n-\n-\tfor (i = 0; i < ARRAY_SIZE(common_guides); i++) {\n-\t\tif (longest < strlen(common_guides[i].name))\n-\t\t\tlongest = strlen(common_guides[i].name);\n-\t}\n-\n-\tputs(_(\"The common Git guides are:\\n\"));\n-\tfor (i = 0; i < ARRAY_SIZE(common_guides); i++) {\n-\t\tprintf(\"   %s   \", common_guides[i].name);\n-\t\tmput_char(' ', longest - strlen(common_guides[i].name));\n-\t\tputs(_(common_guides[i].help));\n-\t}\n-\tputchar('\\n');\n-}\n-\n static const char *check_git_cmd(const char* cmd)\n {\n \tchar *alias;\ndiff --git a/command-list.txt b/command-list.txt\nindex 2c81d8db74..1835f1a928 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -149,3 +149,11 @@ gitweb                                  ancillaryinterrogators\n git-whatchanged                         ancillaryinterrogators\n git-worktree                            mainporcelain\n git-write-tree                          plumbingmanipulators\n+gitattributes                           guide\n+giteveryday                             guide\n+gitglossary                             guide\n+gitignore                               guide\n+gitmodules                              guide\n+gitrevisions                            guide\n+gittutorial                             guide\n+gitworkflows                            guide\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 05722b1392..86d59419b3 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -58,7 +58,11 @@ command_list \"$1\" |\n sort |\n while read cmd category tags\n do\n-\tprefix=git-\n+\tif [ \"$category\" = guide ]; then\n+\t\tprefix=git\n+\telse\n+\t\tprefix=git-\n+\tfi\n \tname=$(echo $cmd | sed \"s/^${prefix}//\")\n \tsed -n '\n \t\t/^NAME/,/'\"$cmd\"'/H\ndiff --git a/help.c b/help.c\nindex ae5281601a..88127fdd6f 100644\n--- a/help.c\n+++ b/help.c\n@@ -314,6 +314,28 @@ static void list_commands_by_category(int cat, struct cmdname_help *cmds,\n \t}\n }\n \n+void list_common_guides_help(void)\n+{\n+\tint i, longest = 0;\n+\tint nr = ARRAY_SIZE(command_list);\n+\tstruct cmdname_help *cmds = command_list;\n+\n+\tQSORT(cmds, nr, cmd_category_cmp);\n+\n+\tfor (i = 0; i < nr; i++) {\n+\t\tstruct cmdname_help *cmd = cmds + i;\n+\n+\t\tif (cmd->category != CAT_guide)\n+\t\t\tcontinue;\n+\t\tif (longest < strlen(cmd->name))\n+\t\t\tlongest = strlen(cmd->name);\n+\t}\n+\n+\tputs(_(\"The common Git guides are:\\n\"));\n+\tlist_commands_by_category(CAT_guide, cmds, nr, longest);\n+\tputchar('\\n');\n+}\n+\n void list_all_cmds_help(void)\n {\n \tint i, longest = 0;\ndiff --git a/help.h b/help.h\nindex 62449f1b7e..de094e9e65 100644\n--- a/help.h\n+++ b/help.h\n@@ -18,6 +18,7 @@ static inline void mput_char(char c, unsigned int num)\n \n extern void list_common_cmds_help(void);\n extern void list_all_cmds_help(void);\n+extern void list_common_guides_help(void);\n extern void list_all_cmds(void);\n extern void list_porcelain_cmds(void);\n extern const char *help_unknown_cmd(const char *cmd);\n-- \n2.17.0.367.g5dd2e386c3\n\n"},{"id":"345374","messageId":"20180421165414.30051-6-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180421165414.30051-1-pclouds@gmail.com","subject":"[PATCH v3 5/6] help: add \"-a --verbose\" to list all commands with synopsis","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-21T16:54:13Z","receivedAt":"2018-04-21T16:54:48Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This lists all recognized commands [1] by category. The group order\nfollows closely git.txt.\n\n[1] We may actually show commands that are not built (e.g. if you set\nNO_PERL you don't have git-instaweb but it's still listed here). I\nignore the problem because on Linux a git package could be split\nanyway. The \"git-core\" package may not contain git-instaweb even if\nit's built because it may end up in a separate package. We can't know\nanyway.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-help.txt |  4 ++-\n builtin/help.c             |  7 ++++\n help.c                     | 69 ++++++++++++++++++++++++++++++++++++++\n help.h                     |  1 +\n t/t0012-help.sh            |  9 +++++\n 5 files changed, 89 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-help.txt b/Documentation/git-help.txt\nindex 40d328a4b3..a40fc38d8b 100644\n--- a/Documentation/git-help.txt\n+++ b/Documentation/git-help.txt\n@@ -8,7 +8,7 @@ git-help - Display help information about Git\n SYNOPSIS\n --------\n [verse]\n-'git help' [-a|--all] [-g|--guide]\n+'git help' [-a|--all [--verbose]] [-g|--guide]\n \t   [-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE]\n \n DESCRIPTION\n@@ -42,6 +42,8 @@ OPTIONS\n --all::\n \tPrints all the available commands on the standard output. This\n \toption overrides any given command or guide name.\n+\tWhen used with `--verbose` print description for all recognized\n+\tcommands.\n \n -g::\n --guides::\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 598867cfea..0e0af8426a 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -36,6 +36,7 @@ static const char *html_path;\n \n static int show_all = 0;\n static int show_guides = 0;\n+static int verbose;\n static unsigned int colopts;\n static enum help_format help_format = HELP_FORMAT_NONE;\n static int exclude_guides;\n@@ -48,6 +49,7 @@ static struct option builtin_help_options[] = {\n \t\t\tHELP_FORMAT_WEB),\n \tOPT_SET_INT('i', \"info\", &help_format, N_(\"show info page\"),\n \t\t\tHELP_FORMAT_INFO),\n+\tOPT__VERBOSE(&verbose, N_(\"print command description\")),\n \tOPT_END(),\n };\n \n@@ -463,6 +465,11 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \tif (show_all) {\n \t\tgit_config(git_help_config, NULL);\n+\t\tif (verbose) {\n+\t\t\tsetup_pager();\n+\t\t\tlist_all_cmds_help();\n+\t\t\treturn 0;\n+\t\t}\n \t\tprintf(_(\"usage: %s%s\"), _(git_usage_string), \"\\n\\n\");\n \t\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n \t\tlist_commands(colopts, &main_cmds, &other_cmds);\ndiff --git a/help.c b/help.c\nindex 6688653f99..ae5281601a 100644\n--- a/help.c\n+++ b/help.c\n@@ -285,6 +285,75 @@ void list_porcelain_cmds(void)\n \t}\n }\n \n+static int cmd_category_cmp(const void *elem1, const void *elem2)\n+{\n+\tconst struct cmdname_help *e1 = elem1;\n+\tconst struct cmdname_help *e2 = elem2;\n+\n+\tif (e1->category < e2->category)\n+\t\treturn -1;\n+\tif (e1->category > e2->category)\n+\t\treturn 1;\n+\treturn strcmp(e1->name, e2->name);\n+}\n+\n+static void list_commands_by_category(int cat, struct cmdname_help *cmds,\n+\t\t\t\t      int nr, int longest)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < nr; i++) {\n+\t\tstruct cmdname_help *cmd = cmds + i;\n+\n+\t\tif (cmd->category != cat)\n+\t\t\tcontinue;\n+\n+\t\tprintf(\"   %s   \", cmd->name);\n+\t\tmput_char(' ', longest - strlen(cmd->name));\n+\t\tputs(_(cmd->help));\n+\t}\n+}\n+\n+void list_all_cmds_help(void)\n+{\n+\tint i, longest = 0;\n+\tint nr = ARRAY_SIZE(command_list);\n+\tstruct cmdname_help *cmds = command_list;\n+\n+\tfor (i = 0; i < nr; i++) {\n+\t\tstruct cmdname_help *cmd = cmds + i;\n+\n+\t\tif (longest < strlen(cmd->name))\n+\t\t\tlongest = strlen(cmd->name);\n+\t}\n+\n+\tQSORT(cmds, nr, cmd_category_cmp);\n+\n+\tprintf(\"%s\\n\\n\", _(\"Main Porcelain Commands\"));\n+\tlist_commands_by_category(CAT_mainporcelain, cmds, nr, longest);\n+\n+\tprintf(\"\\n%s\\n\\n\", _(\"Ancillary Commands / Manipulators\"));\n+\tlist_commands_by_category(CAT_ancillarymanipulators, cmds, nr, longest);\n+\n+\tprintf(\"\\n%s\\n\\n\", _(\"Ancillary Commands / Interrogators\"));\n+\tlist_commands_by_category(CAT_ancillaryinterrogators, cmds, nr, longest);\n+\n+\tprintf(\"\\n%s\\n\\n\", _(\"Interacting with Others\"));\n+\tlist_commands_by_category(CAT_foreignscminterface, cmds, nr, longest);\n+\n+\tprintf(\"\\n%s\\n\\n\", _(\"Low-level Commands / Manipulators\"));\n+\tlist_commands_by_category(CAT_plumbingmanipulators, cmds, nr, longest);\n+\n+\tprintf(\"\\n%s\\n\\n\", _(\"Low-level Commands / Interrogators\"));\n+\tlist_commands_by_category(CAT_plumbinginterrogators, cmds, nr, longest);\n+\n+\tprintf(\"\\n%s\\n\\n\", _(\"Low-level Commands / Synching Repositories\"));\n+\tlist_commands_by_category(CAT_synchingrepositories, cmds, nr, longest);\n+\n+\tprintf(\"\\n%s\\n\\n\", _(\"Low-level Commands / Internal Helpers\"));\n+\tlist_commands_by_category(CAT_purehelpers, cmds, nr, longest);\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex 33e2210ebd..62449f1b7e 100644\n--- a/help.h\n+++ b/help.h\n@@ -17,6 +17,7 @@ static inline void mput_char(char c, unsigned int num)\n }\n \n extern void list_common_cmds_help(void);\n+extern void list_all_cmds_help(void);\n extern void list_all_cmds(void);\n extern void list_porcelain_cmds(void);\n extern const char *help_unknown_cmd(const char *cmd);\ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex fd2a7f27dc..53208ab20e 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -25,6 +25,15 @@ test_expect_success \"setup\" '\n \tEOF\n '\n \n+# make sure to exercise these code paths, the output is a bit tricky\n+# to verify\n+test_expect_success 'basic help commands' '\n+\tgit help >/dev/null &&\n+\tgit help -a >/dev/null &&\n+\tgit help -g >/dev/null &&\n+\tgit help -av >/dev/null\n+'\n+\n test_expect_success \"works for commands and guides by default\" '\n \tconfigure_help &&\n \tgit help status &&\n-- \n2.17.0.367.g5dd2e386c3\n\n"},{"id":"345375","messageId":"20180421165414.30051-5-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180421165414.30051-1-pclouds@gmail.com","subject":"[PATCH v3 4/6] git.c: implement --list-cmds=porcelain","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-21T16:54:12Z","receivedAt":"2018-04-21T16:54:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is useful for git-completion.bash because it needs this set of\ncommands. Right now we have to maintain a separate command category in\nthere.\n\nNote that the current completion script incorrectly classifies\nfilter-branch as porcelain and t9902 tests this behavior. We keep it\nthis way in t9902 because this test does not really care which\nparticular command is porcelain or plubmbing, they're just names.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash | 106 +++----------------------\n git.c                                  |   2 +\n help.c                                 |  12 +++\n help.h                                 |   1 +\n t/t9902-completion.sh                  |   6 +-\n 5 files changed, 31 insertions(+), 96 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex a5f13ade20..7d17ca23f6 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -835,18 +835,23 @@ __git_complete_strategy ()\n }\n \n __git_commands () {\n-\tif test -n \"${GIT_TESTING_COMMAND_COMPLETION:-}\"\n+\tif test -n \"$GIT_TESTING_COMPLETION\"\n \tthen\n-\t\tprintf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n+\t\tcase \"$1\" in\n+\t\tporcelain)\n+\t\t\tprintf \"%s\" \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\";;\n+\t\tall)\n+\t\t\tprintf \"%s\" \"$GIT_TESTING_ALL_COMMAND_LIST\";;\n+\t\tesac\n \telse\n-\t\tgit --list-cmds=all\n+\t\tgit --list-cmds=$1\n \tfi\n }\n \n-__git_list_all_commands ()\n+__git_list_commands ()\n {\n \tlocal i IFS=\" \"$'\\n'\n-\tfor i in $(__git_commands)\n+\tfor i in $(__git_commands $1)\n \tdo\n \t\tcase $i in\n \t\t*--*)             : helper pattern;;\n@@ -859,101 +864,14 @@ __git_all_commands=\n __git_compute_all_commands ()\n {\n \ttest -n \"$__git_all_commands\" ||\n-\t__git_all_commands=$(__git_list_all_commands)\n-}\n-\n-__git_list_porcelain_commands ()\n-{\n-\tlocal i IFS=\" \"$'\\n'\n-\t__git_compute_all_commands\n-\tfor i in $__git_all_commands\n-\tdo\n-\t\tcase $i in\n-\t\t*--*)             : helper pattern;;\n-\t\tapplymbox)        : ask gittus;;\n-\t\tapplypatch)       : ask gittus;;\n-\t\tarchimport)       : import;;\n-\t\tcat-file)         : plumbing;;\n-\t\tcheck-attr)       : plumbing;;\n-\t\tcheck-ignore)     : plumbing;;\n-\t\tcheck-mailmap)    : plumbing;;\n-\t\tcheck-ref-format) : plumbing;;\n-\t\tcheckout-index)   : plumbing;;\n-\t\tcolumn)           : internal helper;;\n-\t\tcommit-tree)      : plumbing;;\n-\t\tcount-objects)    : infrequent;;\n-\t\tcredential)       : credentials;;\n-\t\tcredential-*)     : credentials helper;;\n-\t\tcvsexportcommit)  : export;;\n-\t\tcvsimport)        : import;;\n-\t\tcvsserver)        : daemon;;\n-\t\tdaemon)           : daemon;;\n-\t\tdiff-files)       : plumbing;;\n-\t\tdiff-index)       : plumbing;;\n-\t\tdiff-tree)        : plumbing;;\n-\t\tfast-import)      : import;;\n-\t\tfast-export)      : export;;\n-\t\tfsck-objects)     : plumbing;;\n-\t\tfetch-pack)       : plumbing;;\n-\t\tfmt-merge-msg)    : plumbing;;\n-\t\tfor-each-ref)     : plumbing;;\n-\t\thash-object)      : plumbing;;\n-\t\thttp-*)           : transport;;\n-\t\tindex-pack)       : plumbing;;\n-\t\tinit-db)          : deprecated;;\n-\t\tlocal-fetch)      : plumbing;;\n-\t\tls-files)         : plumbing;;\n-\t\tls-remote)        : plumbing;;\n-\t\tls-tree)          : plumbing;;\n-\t\tmailinfo)         : plumbing;;\n-\t\tmailsplit)        : plumbing;;\n-\t\tmerge-*)          : plumbing;;\n-\t\tmktree)           : plumbing;;\n-\t\tmktag)            : plumbing;;\n-\t\tpack-objects)     : plumbing;;\n-\t\tpack-redundant)   : plumbing;;\n-\t\tpack-refs)        : plumbing;;\n-\t\tparse-remote)     : plumbing;;\n-\t\tpatch-id)         : plumbing;;\n-\t\tprune)            : plumbing;;\n-\t\tprune-packed)     : plumbing;;\n-\t\tquiltimport)      : import;;\n-\t\tread-tree)        : plumbing;;\n-\t\treceive-pack)     : plumbing;;\n-\t\tremote-*)         : transport;;\n-\t\trerere)           : plumbing;;\n-\t\trev-list)         : plumbing;;\n-\t\trev-parse)        : plumbing;;\n-\t\trunstatus)        : plumbing;;\n-\t\tsh-setup)         : internal;;\n-\t\tshell)            : daemon;;\n-\t\tshow-ref)         : plumbing;;\n-\t\tsend-pack)        : plumbing;;\n-\t\tshow-index)       : plumbing;;\n-\t\tssh-*)            : transport;;\n-\t\tstripspace)       : plumbing;;\n-\t\tsymbolic-ref)     : plumbing;;\n-\t\tunpack-file)      : plumbing;;\n-\t\tunpack-objects)   : plumbing;;\n-\t\tupdate-index)     : plumbing;;\n-\t\tupdate-ref)       : plumbing;;\n-\t\tupdate-server-info) : daemon;;\n-\t\tupload-archive)   : plumbing;;\n-\t\tupload-pack)      : plumbing;;\n-\t\twrite-tree)       : plumbing;;\n-\t\tvar)              : infrequent;;\n-\t\tverify-pack)      : infrequent;;\n-\t\tverify-tag)       : plumbing;;\n-\t\t*) echo $i;;\n-\t\tesac\n-\tdone\n+\t__git_all_commands=$(__git_list_commands all)\n }\n \n __git_porcelain_commands=\n __git_compute_porcelain_commands ()\n {\n \ttest -n \"$__git_porcelain_commands\" ||\n-\t__git_porcelain_commands=$(__git_list_porcelain_commands)\n+\t__git_porcelain_commands=$(__git_list_commands porcelain)\n }\n \n # Lists all set config variables starting with the given section prefix,\ndiff --git a/git.c b/git.c\nindex 64f67e7f7f..153f56fb95 100644\n--- a/git.c\n+++ b/git.c\n@@ -230,6 +230,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n \t\t\telse if (!strcmp(cmd, \"all\"))\n \t\t\t\tlist_all_cmds();\n+\t\t\telse if (!strcmp(cmd, \"porcelain\"))\n+\t\t\t\tlist_porcelain_cmds();\n \t\t\telse\n \t\t\t\tdie(\"unsupported command listing type '%s'\", cmd);\n \t\t\texit(0);\ndiff --git a/help.c b/help.c\nindex e63006c333..6688653f99 100644\n--- a/help.c\n+++ b/help.c\n@@ -273,6 +273,18 @@ void list_all_cmds(void)\n \tclean_cmdnames(&other_cmds);\n }\n \n+void list_porcelain_cmds(void)\n+{\n+\tint i, nr = ARRAY_SIZE(command_list);\n+\tstruct cmdname_help *cmds = command_list;\n+\n+\tfor (i = 0; i < nr; i++) {\n+\t\tif (cmds[i].category != CAT_mainporcelain)\n+\t\t\tcontinue;\n+\t\tputs(cmds[i].name);\n+\t}\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex 0bf29f8dc5..33e2210ebd 100644\n--- a/help.h\n+++ b/help.h\n@@ -18,6 +18,7 @@ static inline void mput_char(char c, unsigned int num)\n \n extern void list_common_cmds_help(void);\n extern void list_all_cmds(void);\n+extern void list_porcelain_cmds(void);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 1b34caa1e1..5a23a46fcf 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -13,7 +13,7 @@ complete ()\n \treturn 0\n }\n \n-# Be careful when updating this list:\n+# Be careful when updating these lists:\n #\n # (1) The build tree may have build artifact from different branch, or\n #     the user's $PATH may have a random executable that may begin\n@@ -30,7 +30,9 @@ complete ()\n #     completion for \"git <TAB>\", and a plumbing is excluded.  \"add\",\n #     \"filter-branch\" and \"ls-files\" are listed for this.\n \n-GIT_TESTING_COMMAND_COMPLETION='add checkout check-attr filter-branch ls-files'\n+GIT_TESTING_COMPLETION=t\n+GIT_TESTING_ALL_COMMAND_LIST='add checkout check-attr filter-branch ls-files'\n+GIT_TESTING_PORCELAIN_COMMAND_LIST='add checkout filter-branch'\n \n . \"$GIT_BUILD_DIR/contrib/completion/git-completion.bash\"\n \n-- \n2.17.0.367.g5dd2e386c3\n\n"},{"id":"345376","messageId":"20180421165618.GA30287@duynguyen.home","threadId":"48155","inReplyTo":"20180421165414.30051-1-pclouds@gmail.com","subject":"Re: [PATCH v3 0/6] Keep all info in command-list.txt in git binary","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-21T16:56:18Z","receivedAt":"2018-04-21T16:56:26Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sat, Apr 21, 2018 at 06:54:08PM +0200, Nguyễn Thái Ngọc Duy wrote:\n> Changes:\n> \n> - remove the deprecated column in command-list.txt. My change break it\n>   anyway if anyone uses it.\n> - fix up failed tests that I marked in the RFC and kinda forgot about it.\n> - fix bashisms in generate-cmdlist.sh\n> - fix segfaul in \"git help\"\n\nSorry I forgot the interdiff\n\ndiff --git a/command-list.txt b/command-list.txt\nindex 0809a19184..1835f1a928 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -9,7 +9,7 @@ history      grow, mark and tweak your common history\n remote       collaborate (see also: git help workflows)\n \n ### command list (do not change this line)\n-# command name                          category [deprecated] [common]\n+# command name                          category                [common]\n git-add                                 mainporcelain           worktree\n git-am                                  mainporcelain\n git-annotate                            ancillaryinterrogators\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 9f17703aa7..7d17ca23f6 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -835,19 +835,23 @@ __git_complete_strategy ()\n }\n \n __git_commands () {\n-\tif test -n \"${GIT_TESTING_COMMAND_COMPLETION:-}\"\n+\tif test -n \"$GIT_TESTING_COMPLETION\"\n \tthen\n-\t\tprintf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n+\t\tcase \"$1\" in\n+\t\tporcelain)\n+\t\t\tprintf \"%s\" \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\";;\n+\t\tall)\n+\t\t\tprintf \"%s\" \"$GIT_TESTING_ALL_COMMAND_LIST\";;\n+\t\tesac\n \telse\n \t\tgit --list-cmds=$1\n \tfi\n }\n \n-__git_list_all_commands ()\n+__git_list_commands ()\n {\n \tlocal i IFS=\" \"$'\\n'\n-\tlocal category=${1-all}\n-\tfor i in $(__git_commands $category)\n+\tfor i in $(__git_commands $1)\n \tdo\n \t\tcase $i in\n \t\t*--*)             : helper pattern;;\n@@ -860,14 +864,14 @@ __git_all_commands=\n __git_compute_all_commands ()\n {\n \ttest -n \"$__git_all_commands\" ||\n-\t__git_all_commands=$(__git_list_all_commands)\n+\t__git_all_commands=$(__git_list_commands all)\n }\n \n __git_porcelain_commands=\n __git_compute_porcelain_commands ()\n {\n \ttest -n \"$__git_porcelain_commands\" ||\n-\t__git_porcelain_commands=$(__git_list_all_commands porcelain)\n+\t__git_porcelain_commands=$(__git_list_commands porcelain)\n }\n \n # Lists all set config variables starting with the given section prefix,\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex e35f3e357b..86d59419b3 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -36,7 +36,7 @@ sed -n '\n \t' \"$1\"\n printf '};\\n\\n'\n \n-echo \"#define GROUP_NONE 0xff /* no common group */\"\n+echo \"#define GROUP_NONE 0xff\"\n n=0\n while read grp\n do\n@@ -45,15 +45,6 @@ do\n done <\"$grps\"\n echo\n \n-echo '/*'\n-printf 'static const char *cmd_categories[] = {\\n'\n-category_list \"$1\" |\n-while read category; do\n-\tprintf '\\t\\\"'$category'\\\",\\n'\n-done\n-printf '\\tNULL\\n};\\n\\n'\n-echo '*/'\n-\n n=0\n category_list \"$1\" |\n while read category; do\n@@ -68,10 +59,11 @@ sort |\n while read cmd category tags\n do\n \tif [ \"$category\" = guide ]; then\n-\t\tname=${cmd/git}\n+\t\tprefix=git\n \telse\n-\t\tname=${cmd/git-}\n+\t\tprefix=git-\n \tfi\n+\tname=$(echo $cmd | sed \"s/^${prefix}//\")\n \tsed -n '\n \t\t/^NAME/,/'\"$cmd\"'/H\n \t\t${\ndiff --git a/help.c b/help.c\nindex a44f4a113e..88127fdd6f 100644\n--- a/help.c\n+++ b/help.c\n@@ -201,7 +201,8 @@ static void extract_common_cmds(struct cmdname_help **p_common_cmds,\n \tfor (i = 0; i < ARRAY_SIZE(command_list); i++) {\n \t\tconst struct cmdname_help *cmd = command_list + i;\n \n-\t\tif (cmd->category != CAT_mainporcelain)\n+\t\tif (cmd->category != CAT_mainporcelain ||\n+\t\t    cmd->group == GROUP_NONE)\n \t\t\tcontinue;\n \n \t\tcommon_cmds[nr++] = *cmd;\ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex fd2a7f27dc..53208ab20e 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -25,6 +25,15 @@ test_expect_success \"setup\" '\n \tEOF\n '\n \n+# make sure to exercise these code paths, the output is a bit tricky\n+# to verify\n+test_expect_success 'basic help commands' '\n+\tgit help >/dev/null &&\n+\tgit help -a >/dev/null &&\n+\tgit help -g >/dev/null &&\n+\tgit help -av >/dev/null\n+'\n+\n test_expect_success \"works for commands and guides by default\" '\n \tconfigure_help &&\n \tgit help status &&\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 4bfd26ddf9..5a23a46fcf 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -13,7 +13,7 @@ complete ()\n \treturn 0\n }\n \n-# Be careful when updating this list:\n+# Be careful when updating these lists:\n #\n # (1) The build tree may have build artifact from different branch, or\n #     the user's $PATH may have a random executable that may begin\n@@ -30,7 +30,9 @@ complete ()\n #     completion for \"git <TAB>\", and a plumbing is excluded.  \"add\",\n #     \"filter-branch\" and \"ls-files\" are listed for this.\n \n-GIT_TESTING_COMMAND_COMPLETION='add checkout check-attr filter-branch ls-files'\n+GIT_TESTING_COMPLETION=t\n+GIT_TESTING_ALL_COMMAND_LIST='add checkout check-attr filter-branch ls-files'\n+GIT_TESTING_PORCELAIN_COMMAND_LIST='add checkout filter-branch'\n \n . \"$GIT_BUILD_DIR/contrib/completion/git-completion.bash\"\n \n@@ -1208,6 +1210,8 @@ test_expect_success 'basic' '\n \tgrep -q \"^add \\$\" out &&\n \t# script\n \tgrep -q \"^filter-branch \\$\" out &&\n+\t# plumbing\n+\t! grep -q \"^ls-files \\$\" out &&\n \n \trun_completion \"git f\" &&\n \t! grep -q -v \"^f\" out\n@@ -1270,7 +1274,7 @@ test_expect_success 'general options' '\n \ttest_completion \"git --no-r\" \"--no-replace-objects \"\n '\n \n-test_expect_failure 'general options plus command' '\n+test_expect_success 'general options plus command' '\n \ttest_completion \"git --version check\" \"checkout \" &&\n \ttest_completion \"git --paginate check\" \"checkout \" &&\n \ttest_completion \"git --git-dir=foo check\" \"checkout \" &&\n"},{"id":"345392","messageId":"a5dc36f7-fc79-46ba-7e73-e9473cf1aec9@ramsayjones.plus.com","threadId":"48155","inReplyTo":"20180421165618.GA30287@duynguyen.home","subject":"Re: [PATCH v3 0/6] Keep all info in command-list.txt in git binary","fromName":"Ramsay Jones","fromEmail":"ramsay@ramsayjones.plus.com","sentAt":"2018-04-22T14:45:47Z","receivedAt":"2018-04-22T14:45:57Z","isPatch":true,"sender":{"key":"ramsay@ramsayjones.plus.com","avatar":"https://avatars.githubusercontent.com/u/33702710?v=4"},"body":"\n\nOn 21/04/18 17:56, Duy Nguyen wrote:\n> On Sat, Apr 21, 2018 at 06:54:08PM +0200, Nguyễn Thái Ngọc Duy wrote:\n>> Changes:\n>>\n>> - remove the deprecated column in command-list.txt. My change break it\n>>   anyway if anyone uses it.\n>> - fix up failed tests that I marked in the RFC and kinda forgot about it.\n>> - fix bashisms in generate-cmdlist.sh\n>> - fix segfaul in \"git help\"\n> \n> Sorry I forgot the interdiff\n> \n[snip]\n\n> diff --git a/t/t0012-help.sh b/t/t0012-help.sh\n> index fd2a7f27dc..53208ab20e 100755\n> --- a/t/t0012-help.sh\n> +++ b/t/t0012-help.sh\n> @@ -25,6 +25,15 @@ test_expect_success \"setup\" '\n>  \tEOF\n>  '\n>  \n> +# make sure to exercise these code paths, the output is a bit tricky\n> +# to verify\n> +test_expect_success 'basic help commands' '\n> +\tgit help >/dev/null &&\n> +\tgit help -a >/dev/null &&\n> +\tgit help -g >/dev/null &&\n> +\tgit help -av >/dev/null\n> +'\n> +\nI think you need to try a little harder than this! ;-)\n\nThis test would not have noticed the recent failure (what annoyed me was\nthat git build without error and then the test-suite sailed through with\nnary a squeak of complaint). Viz:\n\n  $ ./git help\n  usage: git [--version] [--help] [-C <path>] [-c <name>=<value>]\n             [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n             [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]\n             [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n             <command> [<args>]\n  \n  These are common Git commands used in various situations:\n  \n  'git help -a' and 'git help -g' list available subcommands and some\n  concept guides. See 'git help <command>' or 'git help <concept>'\n  to read about a specific subcommand or concept.\n  $ echo $?\n  0\n  $ \n\n  $ ./git help -g\n  The common Git guides are:\n  \n  \n  'git help -a' and 'git help -g' list available subcommands and some\n  concept guides. See 'git help <command>' or 'git help <concept>'\n  to read about a specific subcommand or concept.\n  $ echo $?\n  0\n  $ \n\n  $ ./git help -av\n  Main Porcelain Commands\n  \n  \n  Ancillary Commands / Manipulators\n  \n  \n  Ancillary Commands / Interrogators\n  \n  \n  Interacting with Others\n  \n  \n  Low-level Commands / Manipulators\n  \n  \n  Low-level Commands / Interrogators\n  \n  \n  Low-level Commands / Synching Repositories\n  \n  \n  Low-level Commands / Internal Helpers\n  \n  $ echo $?\n  0\n  $ \n \nI started to add some tests, like so:\n\n  diff --git a/t/t0012-help.sh b/t/t0012-help.sh\n  index fd2a7f27d..7e10c2862 100755\n  --- a/t/t0012-help.sh\n  +++ b/t/t0012-help.sh\n  @@ -49,6 +49,22 @@ test_expect_success \"--help does not work for guides\" \"\n          test_i18ncmp expect actual\n   \"\n   \n  +test_expect_success 'git help' '\n  +       git help >help.output &&\n  +       test_i18ngrep \"^   clone  \" help.output &&\n  +       test_i18ngrep \"^   add    \" help.output &&\n  +       test_i18ngrep \"^   log    \" help.output &&\n  +       test_i18ngrep \"^   commit \" help.output &&\n  +       test_i18ngrep \"^   fetch  \" help.output\n  +'\n  +\n  +test_expect_success 'git help -g' '\n  +       git help -g >help.output &&\n  +       test_i18ngrep \"^   attributes \" help.output &&\n  +       test_i18ngrep \"^   everyday   \" help.output &&\n  +       test_i18ngrep \"^   tutorial   \" help.output\n  +'\n  +\n   test_expect_success 'generate builtin list' '\n          git --list-cmds=builtins >builtins\n   '\n\nThese tests, while not rigorous, did at least correctly catch the bad\nbuild for me. I was about to add the obvious one for 'git help -av',\nwhen I decided to catch the problem 'at source', viz:\n\n  diff --git a/help.c b/help.c\n  index a47f7e2c4..13790bb54 100644\n  --- a/help.c\n  +++ b/help.c\n  @@ -196,6 +196,9 @@ static void extract_common_cmds(struct cmdname_help **p_common_cmds,\n   \tint i, nr = 0;\n   \tstruct cmdname_help *common_cmds;\n   \n  +\tif (ARRAY_SIZE(command_list) == 0)\n  +\t\tBUG(\"empty command_list\");\n  +\n   \tALLOC_ARRAY(common_cmds, ARRAY_SIZE(command_list));\n   \n   \tfor (i = 0; i < ARRAY_SIZE(command_list); i++) {\n  @@ -279,6 +282,9 @@ void list_porcelain_cmds(void)\n   \tint i, nr = ARRAY_SIZE(command_list);\n   \tstruct cmdname_help *cmds = command_list;\n   \n  +\tif (nr == 0)\n  +\t\tBUG(\"empty command_list\");\n  +\n   \tfor (i = 0; i < nr; i++) {\n   \t\tif (cmds[i].category != CAT_mainporcelain)\n   \t\t\tcontinue;\n  @@ -321,6 +327,9 @@ void list_common_guides_help(void)\n   \tint nr = ARRAY_SIZE(command_list);\n   \tstruct cmdname_help *cmds = command_list;\n   \n  +\tif (nr == 0)\n  +\t\tBUG(\"empty command_list\");\n  +\n   \tQSORT(cmds, nr, cmd_category_cmp);\n   \n   \tfor (i = 0; i < nr; i++) {\n  @@ -343,6 +352,9 @@ void list_all_cmds_help(void)\n   \tint nr = ARRAY_SIZE(command_list);\n   \tstruct cmdname_help *cmds = command_list;\n   \n  +\tif (nr == 0)\n  +\t\tBUG(\"empty command_list\");\n  +\n   \tfor (i = 0; i < nr; i++) {\n   \t\tstruct cmdname_help *cmd = cmds + i;\n   \n  \nThis had a very dramatic effect on the test-suite, since every single\ntest file failed while sourcing 'test-lib.sh'. [The test for having\nbuilt git ('\"$GIT_BUILD_DIR/git\" >/dev/null') tries to output help,\nbecause you haven't given a command, and hits BUG - core dump!]\n\nI haven't tried this patch series yet (I will hopefully find some\ntime tonight), but it looks like it will fix the problem.\n\nATB,\nRamsay Jones\n\n"},{"id":"345395","messageId":"CACsJy8Cj57=p5nKH1T2UZmFbDv2d_JRO+GcAo29SAZcSxgKCkw@mail.gmail.com","threadId":"48155","inReplyTo":"a5dc36f7-fc79-46ba-7e73-e9473cf1aec9@ramsayjones.plus.com","subject":"Re: [PATCH v3 0/6] Keep all info in command-list.txt in git binary","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-22T15:22:55Z","receivedAt":"2018-04-22T15:23:33Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Apr 22, 2018 at 4:45 PM, Ramsay Jones\n<ramsay@ramsayjones.plus.com> wrote:\n>\n>\n> On 21/04/18 17:56, Duy Nguyen wrote:\n>> On Sat, Apr 21, 2018 at 06:54:08PM +0200, Nguyễn Thái Ngọc Duy wrote:\n>>> Changes:\n>>>\n>>> - remove the deprecated column in command-list.txt. My change break it\n>>>   anyway if anyone uses it.\n>>> - fix up failed tests that I marked in the RFC and kinda forgot about it.\n>>> - fix bashisms in generate-cmdlist.sh\n>>> - fix segfaul in \"git help\"\n>>\n>> Sorry I forgot the interdiff\n>>\n> [snip]\n>\n>> diff --git a/t/t0012-help.sh b/t/t0012-help.sh\n>> index fd2a7f27dc..53208ab20e 100755\n>> --- a/t/t0012-help.sh\n>> +++ b/t/t0012-help.sh\n>> @@ -25,6 +25,15 @@ test_expect_success \"setup\" '\n>>       EOF\n>>  '\n>>\n>> +# make sure to exercise these code paths, the output is a bit tricky\n>> +# to verify\n>> +test_expect_success 'basic help commands' '\n>> +     git help >/dev/null &&\n>> +     git help -a >/dev/null &&\n>> +     git help -g >/dev/null &&\n>> +     git help -av >/dev/null\n>> +'\n>> +\n> I think you need to try a little harder than this! ;-)\n\nYeah. I did think about grepping the output but decided not to because\nof gettext poison stuff and column output in \"git help\". If we do want\nto test this, how about I extend --list-cmds= option to take a few\nmore parameters? --list-cmds=common would output all common commands,\n--list-cmds=<category> does the same for other command category. This\nway we can verify without worrying about text formatting, paging or\ntranslation.\n-- \nDuy\n"},{"id":"345397","messageId":"9303a7ef-5895-a974-84dc-98521be14793@ramsayjones.plus.com","threadId":"48155","inReplyTo":"CACsJy8Cj57=p5nKH1T2UZmFbDv2d_JRO+GcAo29SAZcSxgKCkw@mail.gmail.com","subject":"Re: [PATCH v3 0/6] Keep all info in command-list.txt in git binary","fromName":"Ramsay Jones","fromEmail":"ramsay@ramsayjones.plus.com","sentAt":"2018-04-22T15:58:38Z","receivedAt":"2018-04-22T15:58:44Z","isPatch":true,"sender":{"key":"ramsay@ramsayjones.plus.com","avatar":"https://avatars.githubusercontent.com/u/33702710?v=4"},"body":"\n\nOn 22/04/18 16:22, Duy Nguyen wrote:\n> On Sun, Apr 22, 2018 at 4:45 PM, Ramsay Jones\n> <ramsay@ramsayjones.plus.com> wrote:\n>>\n>>\n>> On 21/04/18 17:56, Duy Nguyen wrote:\n>>> On Sat, Apr 21, 2018 at 06:54:08PM +0200, Nguyễn Thái Ngọc Duy wrote:\n>>>> Changes:\n>>>>\n>>>> - remove the deprecated column in command-list.txt. My change break it\n>>>>   anyway if anyone uses it.\n>>>> - fix up failed tests that I marked in the RFC and kinda forgot about it.\n>>>> - fix bashisms in generate-cmdlist.sh\n>>>> - fix segfaul in \"git help\"\n>>>\n>>> Sorry I forgot the interdiff\n>>>\n>> [snip]\n>>\n>>> diff --git a/t/t0012-help.sh b/t/t0012-help.sh\n>>> index fd2a7f27dc..53208ab20e 100755\n>>> --- a/t/t0012-help.sh\n>>> +++ b/t/t0012-help.sh\n>>> @@ -25,6 +25,15 @@ test_expect_success \"setup\" '\n>>>       EOF\n>>>  '\n>>>\n>>> +# make sure to exercise these code paths, the output is a bit tricky\n>>> +# to verify\n>>> +test_expect_success 'basic help commands' '\n>>> +     git help >/dev/null &&\n>>> +     git help -a >/dev/null &&\n>>> +     git help -g >/dev/null &&\n>>> +     git help -av >/dev/null\n>>> +'\n>>> +\n>> I think you need to try a little harder than this! ;-)\n> \n> Yeah. I did think about grepping the output but decided not to because\n> of gettext poison stuff and column output in \"git help\". If we do want\n> to test this, how about I extend --list-cmds= option to take a few\n> more parameters? --list-cmds=common would output all common commands,\n> --list-cmds=<category> does the same for other command category. This\n> way we can verify without worrying about text formatting, paging or\n> translation.\n\nHmm, my immediate reaction would be to prefer my simple tests.\nYes, they are not exactly rigorous and they would be affected \nby changing the help formatting, but they are effective. ;-)\n\n[I don't think the formatting would change that often, or at\nall - whoever submits that patch would get to update the tests!]\n\nWhat did you think about adding the BUG() checks?\n\nATB,\nRamsay Jones\n\n\n"},{"id":"345399","messageId":"CACsJy8AcTkPgVavDo_nUZkwPAFy335j94BY=BwATHbv5sdvu=w@mail.gmail.com","threadId":"48155","inReplyTo":"9303a7ef-5895-a974-84dc-98521be14793@ramsayjones.plus.com","subject":"Re: [PATCH v3 0/6] Keep all info in command-list.txt in git binary","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-22T16:12:14Z","receivedAt":"2018-04-22T16:12:55Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Apr 22, 2018 at 5:58 PM, Ramsay Jones\n<ramsay@ramsayjones.plus.com> wrote:\n>>> I think you need to try a little harder than this! ;-)\n>>\n>> Yeah. I did think about grepping the output but decided not to because\n>> of gettext poison stuff and column output in \"git help\". If we do want\n>> to test this, how about I extend --list-cmds= option to take a few\n>> more parameters? --list-cmds=common would output all common commands,\n>> --list-cmds=<category> does the same for other command category. This\n>> way we can verify without worrying about text formatting, paging or\n>> translation.\n>\n> Hmm, my immediate reaction would be to prefer my simple tests.\n> Yes, they are not exactly rigorous and they would be affected\n> by changing the help formatting, but they are effective. ;-)\n>\n> [I don't think the formatting would change that often, or at\n> all - whoever submits that patch would get to update the tests!]\n\nHmm.. for non-column output that's true. \"git help\" with column output\nshould probably fine as well because even though we add more and more\ncommands every month, these are not marked common (and unlikely so).\nSo yeah I agree.\n\n> What did you think about adding the BUG() checks?\n\nI was thinking if there was a way to fail the build after running\n./generate-cmds.sh and generating empty output but it does not sound\neasy to do. So yeah, BUG() checks sound good.\n\n-- \nDuy\n"},{"id":"345400","messageId":"9625f486-cbec-634f-10b6-f4b53a341b56@ramsayjones.plus.com","threadId":"48155","inReplyTo":"CACsJy8AcTkPgVavDo_nUZkwPAFy335j94BY=BwATHbv5sdvu=w@mail.gmail.com","subject":"Re: [PATCH v3 0/6] Keep all info in command-list.txt in git binary","fromName":"Ramsay Jones","fromEmail":"ramsay@ramsayjones.plus.com","sentAt":"2018-04-22T16:36:47Z","receivedAt":"2018-04-22T16:36:52Z","isPatch":true,"sender":{"key":"ramsay@ramsayjones.plus.com","avatar":"https://avatars.githubusercontent.com/u/33702710?v=4"},"body":"\n\nOn 22/04/18 17:12, Duy Nguyen wrote:\n> On Sun, Apr 22, 2018 at 5:58 PM, Ramsay Jones\n> <ramsay@ramsayjones.plus.com> wrote:\n>>>> I think you need to try a little harder than this! ;-)\n>>>\n>>> Yeah. I did think about grepping the output but decided not to because\n>>> of gettext poison stuff and column output in \"git help\". If we do want\n>>> to test this, how about I extend --list-cmds= option to take a few\n>>> more parameters? --list-cmds=common would output all common commands,\n>>> --list-cmds=<category> does the same for other command category. This\n>>> way we can verify without worrying about text formatting, paging or\n>>> translation.\n>>\n>> Hmm, my immediate reaction would be to prefer my simple tests.\n>> Yes, they are not exactly rigorous and they would be affected\n>> by changing the help formatting, but they are effective. ;-)\n>>\n>> [I don't think the formatting would change that often, or at\n>> all - whoever submits that patch would get to update the tests!]\n> \n> Hmm.. for non-column output that's true. \"git help\" with column output\n> should probably fine as well because even though we add more and more\n> commands every month, these are not marked common (and unlikely so).\n> So yeah I agree.\n> \n>> What did you think about adding the BUG() checks?\n> \n> I was thinking if there was a way to fail the build after running\n> ./generate-cmds.sh and generating empty output but it does not sound\n> easy to do. So yeah, BUG() checks sound good.\n\nYeah, failing the build would be preferable, but I didn't get\nthat far. ;-)\n\n[BTW, I just applied your patch series to the 'next' branch\n(I just couldn't be bothered to revert your last series from\nthe 'pu' branch, etc.) and, as expected, everything built OK,\npassed the test-suite and 'git help' is working just fine.]\n\nThanks!\n\nATB,\nRamsay Jones\n\n"},{"id":"345446","messageId":"CAPig+cQnmpR_WGZqb+A8zoH3D60VeJ0CWZkR0hXA_fgJSjWLUQ@mail.gmail.com","threadId":"48155","inReplyTo":"20180421165414.30051-7-pclouds@gmail.com","subject":"Re: [PATCH v3 6/6] help: use command-list.txt for the source of guides","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-23T06:07:55Z","receivedAt":"2018-04-23T06:07:59Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Apr 21, 2018 at 12:54 PM, Nguyễn Thái Ngọc Duy\n<pclouds@gmail.com> wrote:\n> The help command currently hard codes the list of guides and their\n> summary in C. Let's move this list to command-list.txt. This lets us\n> extract summary lines from Documentation/git*.txt. This also\n> potentially lets us lists guides in git.txt, but I'll leave that for\n> now.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\n> @@ -58,7 +58,11 @@ command_list \"$1\" |\n>  do\n> -       prefix=git-\n> +       if [ \"$category\" = guide ]; then\n\nStyle:\n\n    if test \"$category\" = guide\n    then\n        ...\n\n> +               prefix=git\n> +       else\n> +               prefix=git-\n> +       fi\n"},{"id":"345450","messageId":"20180423082318.27314-1-oystwa@gmail.com","threadId":"48155","inReplyTo":"xmqqr2nfyix9.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 3/6] generate-cmdlist.sh: keep all information in common-cmds.h","fromName":"Øystein Walle","fromEmail":"oystwa@gmail.com","sentAt":"2018-04-23T08:23:18Z","receivedAt":"2018-04-23T08:23:34Z","isPatch":true,"sender":{"key":"oystwa@gmail.com","avatar":"https://avatars.githubusercontent.com/u/794585?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n> \n> > +category_list () {\n> > +\tcommand_list \"$1\" | awk '{print $2;}' | sort | uniq\n> > +}\n> \n> Piping output of awk to sort/uniq, instead of processing all inside\n> awk within the END block of the script, means that we are wasting\n> two processes---I do not think we care too much about it, but some\n> people might.\n> \n\nCan be written as:\n\n    command_list \"$1\" | awk '!seen[$2]++ {print $2}'\n\nThis doesn't actually sort it, though, which I'm not sure whether is a\ngood thing or a bad thing in this case. But it is less work, and being fast is\nnice for completion scripts.\n\nØsse\n"},{"id":"345451","messageId":"20180423095927.2077-1-szeder.dev@gmail.com","threadId":"48155","inReplyTo":"20180423082318.27314-1-oystwa@gmail.com","subject":"Re: [PATCH v2 3/6] generate-cmdlist.sh: keep all information in common-cmds.h","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-04-23T09:59:27Z","receivedAt":"2018-04-23T09:59:39Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"\n> Junio C Hamano <gitster@pobox.com> writes:\n> \n> > Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n> > \n> > > +category_list () {\n> > > +\tcommand_list \"$1\" | awk '{print $2;}' | sort | uniq\n> > > +}\n> > \n> > Piping output of awk to sort/uniq, instead of processing all inside\n> > awk within the END block of the script, means that we are wasting\n> > two processes---I do not think we care too much about it, but some\n> > people might.\n> > \n> \n> Can be written as:\n> \n>     command_list \"$1\" | awk '!seen[$2]++ {print $2}'\n> \n> This doesn't actually sort it, though, which I'm not sure whether is a\n> good thing or a bad thing in this case. But it is less work, and being fast is\n> nice for completion scripts.\n\nThis script is run during the build process, not during completion.\n\n(The order wouldn't matter for completion, because the shell would\nsort possible completion words anyway.)\n\n"},{"id":"345453","messageId":"CAM0VKjk_vvVgUHAQDRAs6+dyBd55qKO+ZG_-X2DgaqnNtPjGUg@mail.gmail.com","threadId":"48155","inReplyTo":"20180421165414.30051-3-pclouds@gmail.com","subject":"Re: [PATCH v3 2/6] git.c: implement --list-cmds=all and use it in git-completion.bash","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-04-23T11:20:19Z","receivedAt":"2018-04-23T11:20:23Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Sat, Apr 21, 2018 at 6:54 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n\nOh, look, an empty commit message! :)\nSo what does this option do and why use it in the completion script?\n"},{"id":"345460","messageId":"CAM0VKjkd7OZspeTPumi4NVOM=7yXEq=nSjCNntkJ9d-8mPfR2w@mail.gmail.com","threadId":"48155","inReplyTo":"20180421165414.30051-5-pclouds@gmail.com","subject":"Re: [PATCH v3 4/6] git.c: implement --list-cmds=porcelain","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-04-23T13:32:50Z","receivedAt":"2018-04-23T13:33:04Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Sat, Apr 21, 2018 at 6:54 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> This is useful for git-completion.bash because it needs this set of\n> commands. Right now we have to maintain a separate command category in\n> there.\n\nI don't really understand this paragraph, in particular its second\nsentence.  I would have described this change like this:\n\n  To get the list of commands offered after 'git <TAB>', the\n  completion script filters out plumbing commands from the list of all\n  git commands.  To do so, it contains a long hard-coded list of the\n  names of all known plumbing commands, which is redundant with the\n  categorization in 'command-list.txt', is a maintenance burden, and\n  tends to get out-of-sync when new plumbing commands are added.\n\n  Implement 'git --list-cmds=porcelain' to list only commands\n  categorized as porcelains, so we can get rid of that long hard-coded\n  command list from the completion script.\n\nBut then I noticed that it's not an accurate description of the\ncurrent situation, because there is a wide grey area between\nporcelains and plumbing, and the completion script doesn't \"filter out\nplumbing commands\", but rather filters out commands that can be\nconsidered too low-level to be useful for \"general\" usage.\nConsequently, after 'git <TAB>' we also list:\n\n  - some 'ancillaryinterrogators': blame, annotate, difftool, fsck,\n    help\n  - some 'ancillarymanipulators': config, mergetool, remote\n  - some 'foreignscminterface': p4, request-pull, svn, send-email\n  - even some plumbing: apply, name-rev (though 'name-rev' could be\n    omitted; we have 'git describe')\n  - and also all \"unknown\" 'git-foo' commands that can be found in\n    $PATH, which can be the user's own git scripts or other\n    git-related tools ('git-annex', Git LFS, etc.).\n\nWith this change we wouldn't list any of the above commands, but only\nthose that are explicitly categorized as 'mainporcelain'.  I'd much\nprefer the current behaviour.\n\n\n> Note that the current completion script incorrectly classifies\n> filter-branch as porcelain and t9902 tests this behavior. We keep it\n> this way in t9902 because this test does not really care which\n> particular command is porcelain or plubmbing, they're just names.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  contrib/completion/git-completion.bash | 106 +++----------------------\n>  git.c                                  |   2 +\n>  help.c                                 |  12 +++\n>  help.h                                 |   1 +\n>  t/t9902-completion.sh                  |   6 +-\n>  5 files changed, 31 insertions(+), 96 deletions(-)\n>\n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> index a5f13ade20..7d17ca23f6 100644\n> --- a/contrib/completion/git-completion.bash\n> +++ b/contrib/completion/git-completion.bash\n\n\n> @@ -859,101 +864,14 @@ __git_all_commands=\n>  __git_compute_all_commands ()\n>  {\n>         test -n \"$__git_all_commands\" ||\n> -       __git_all_commands=$(__git_list_all_commands)\n> -}\n> -\n> -__git_list_porcelain_commands ()\n> -{\n> -       local i IFS=\" \"$'\\n'\n> -       __git_compute_all_commands\n> -       for i in $__git_all_commands\n> -       do\n> -               case $i in\n> -               *--*)             : helper pattern;;\n> -               applymbox)        : ask gittus;;\n<...>\n> -               verify-tag)       : plumbing;;\n\nI will be glad to see this enormous list go.\n\n> -               *) echo $i;;\n> -               esac\n> -       done\n> +       __git_all_commands=$(__git_list_commands all)\n>  }\n"},{"id":"345646","messageId":"CACsJy8B0bFzh5h+QE+NMgCHfoShfu8MvCzmxPPCVi-g_Ud3sUw@mail.gmail.com","threadId":"48155","inReplyTo":"CAM0VKjkd7OZspeTPumi4NVOM=7yXEq=nSjCNntkJ9d-8mPfR2w@mail.gmail.com","subject":"Re: [PATCH v3 4/6] git.c: implement --list-cmds=porcelain","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-24T16:12:41Z","receivedAt":"2018-04-24T16:13:18Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Apr 23, 2018 at 3:32 PM, SZEDER Gábor <szeder.dev@gmail.com> wrote:\n> But then I noticed that it's not an accurate description of the\n> current situation, because there is a wide grey area between\n> porcelains and plumbing, and the completion script doesn't \"filter out\n> plumbing commands\", but rather filters out commands that can be\n> considered too low-level to be useful for \"general\" usage.\n> Consequently, after 'git <TAB>' we also list:\n>\n>   - some 'ancillaryinterrogators': blame, annotate, difftool, fsck,\n>     help\n>   - some 'ancillarymanipulators': config, mergetool, remote\n>   - some 'foreignscminterface': p4, request-pull, svn, send-email\n>   - even some plumbing: apply, name-rev (though 'name-rev' could be\n>     omitted; we have 'git describe')\n>   - and also all \"unknown\" 'git-foo' commands that can be found in\n>     $PATH, which can be the user's own git scripts or other\n>     git-related tools ('git-annex', Git LFS, etc.).\n>\n> With this change we wouldn't list any of the above commands, but only\n> those that are explicitly categorized as 'mainporcelain'.  I'd much\n> prefer the current behaviour.\n\nYeah I noticed this (kinda) with filter-branch but I did not look\nfurther to see all this. It's good that you review this series then :)\n\nFor the first group (known commands), how about we add a new category\n\"completion\" in command-list.txt? Each command may belong to multiple\ncategories (and my updated script has to deal with that [1]). For the\nsecond group, we could also have a special \"external\" category that is\nproduced at run time, not specified in command-list.txt. --list-cmds\noption either has to accept multiple values, or we accept multiple\n--list-cmds=<category> options.\n\ngit-completion.bash will be updated to ask git \"give me the commands\nin the mainporcelain, completable or external category\". This also\naddresses another thing that bugs me: I wanted an option to let me\ncomplete all commands instead of just porcelain. This approach kinda\ngeneralizes that and it would be easy to let the user choose what\ncategory they want to complete.\n\n[1] which also means I could bring \"deprecated\" category back.\n-- \nDuy\n"},{"id":"345647","messageId":"CACsJy8DWcofCqg=QKo2pLcLQ91GKohnS71Wns8siVZ_sufjgUA@mail.gmail.com","threadId":"48155","inReplyTo":"CACsJy8B0bFzh5h+QE+NMgCHfoShfu8MvCzmxPPCVi-g_Ud3sUw@mail.gmail.com","subject":"Re: [PATCH v3 4/6] git.c: implement --list-cmds=porcelain","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-24T16:17:24Z","receivedAt":"2018-04-24T16:17:59Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Apr 24, 2018 at 6:12 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n> git-completion.bash will be updated to ask git \"give me the commands\n> in the mainporcelain, completable or external category\". This also\n> addresses another thing that bugs me: I wanted an option to let me\n> complete all commands instead of just porcelain. This approach kinda\n> generalizes that and it would be easy to let the user choose what\n> category they want to complete.\n\nTo complete this: there could also be yet another special category\n\"custom\", where --list-cmds=custom simply returns a list of commands\nspecified in config file. With this the user can pick the \"custom\"\ncategory to have total control of what command shows up at \"git <tab>\"\nif they are not satisfied with the predefined categories.\n-- \nDuy\n"},{"id":"345784","messageId":"CAM0VKjmZeVF6GV9ZRXLdwZJJyFi8oLnGvKe7tQYi_QRLoAk4Og@mail.gmail.com","threadId":"48155","inReplyTo":"20180421165414.30051-5-pclouds@gmail.com","subject":"Re: [PATCH v3 4/6] git.c: implement --list-cmds=porcelain","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-04-25T13:06:52Z","receivedAt":"2018-04-25T13:06:57Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Sat, Apr 21, 2018 at 6:54 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> index a5f13ade20..7d17ca23f6 100644\n> --- a/contrib/completion/git-completion.bash\n> +++ b/contrib/completion/git-completion.bash\n> @@ -835,18 +835,23 @@ __git_complete_strategy ()\n\n> +__git_list_commands ()\n\nPlease add a comment before this function to mention its mandatory\nargument and that is should correspond to a category in\n'command-list.txt'\n\n\n> -__git_list_all_commands ()\n\n> -__git_list_porcelain_commands ()\n\nUsers can have their own completion scriptlets for their own git\ncommands, and these should be able to rely on helper functions in\ngit-completion.bash to do things like refs completion and what not.\nTherefore, we tend not to remove or alter those helper functions in a\nbackwards incompatible way, because we don't want to break those\ncompletion scriptlets.\n\nYour patch removes these two functions.  At first I let it slide,\nbecause first I thought that anyone who needs the list of all git\ncommands is better off calling __git_compute_all_commands() and then\nusing $__git_all_commands (same goes for porcelains), because it\ninvolves less fork()ed subshells and external processes.  Then I\nthought why would anyone possibly need the list of git commands in a\ncustom completion scriptlet in the first place...  what for?!\n\nWell, it turns out that there is at least one completion script out\nthere that does rely on __git_list_all_commands() [1].\n\nPlease keep these two functions as a thin wrapper around\n__git_list_commands().\n\n[1] And in a rather curious way at that:\n\n    https://github.com/github/hub/blob/master/etc/hub.bash_completion.sh#L12\n"},{"id":"345785","messageId":"CAM0VKjnD4ZnZjwO6M=P1NcJCfJCfJb=tR5CKwSOeCBvUbjcB=Q@mail.gmail.com","threadId":"48155","inReplyTo":"CACsJy8DWcofCqg=QKo2pLcLQ91GKohnS71Wns8siVZ_sufjgUA@mail.gmail.com","subject":"Re: [PATCH v3 4/6] git.c: implement --list-cmds=porcelain","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-04-25T13:46:26Z","receivedAt":"2018-04-25T13:46:30Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Tue, Apr 24, 2018 at 6:17 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Tue, Apr 24, 2018 at 6:12 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n>> git-completion.bash will be updated to ask git \"give me the commands\n>> in the mainporcelain, completable or external category\". This also\n>> addresses another thing that bugs me: I wanted an option to let me\n>> complete all commands instead of just porcelain. This approach kinda\n>> generalizes that and it would be easy to let the user choose what\n>> category they want to complete.\n>\n> To complete this: there could also be yet another special category\n> \"custom\", where --list-cmds=custom simply returns a list of commands\n> specified in config file. With this the user can pick the \"custom\"\n> category to have total control of what command shows up at \"git <tab>\"\n> if they are not satisfied with the predefined categories.\n\nNote that config settings can be repository-specific, which might\ncause surprises if the user sets a custom command list in one\nrepository's config file, but not (or a different one!) in others.\nThen the list of completed commands will depend on where the user\nhappened to be when first hitting 'git <TAB>'.  Unless you forgo\ncaching the list of commands and run 'git --list-cmds=...' every time\nthe user hits 'git <TAB>', but that will add the overhead of fork()ing\na subshell and a git command.\n\nOnce upon a time I toyed with the idea of introducing environment\nvariables like $GIT_COMPLETION_EXCLUDE_COMMANDS and\n$GIT_COMPLETION_INCLUDE_COMMANDS, to exclude and include commands from\n'git <TAB>'.  I wanted to exclude 'git cherry', because I have never\never used it but it's always in the way when I want to cherry-pick.\nAnd I wanted to include 'git for-each-ref' back when I was running it\nfrequently while working on speeding up refs completion, but it\nwouldn't have brought that much benefits, because I have a 'git\nfor-each-commit' script, too.\nNever really pursued it, though, just patched the long list in\n__git_list_porcelain_commands() in my git clone :)\n"},{"id":"345798","messageId":"CACsJy8Chk5C8BgHsZfhYugBAAwzAUJXQLhq0EYmT2m9us6E6xA@mail.gmail.com","threadId":"48155","inReplyTo":"CAM0VKjmZeVF6GV9ZRXLdwZJJyFi8oLnGvKe7tQYi_QRLoAk4Og@mail.gmail.com","subject":"Re: [PATCH v3 4/6] git.c: implement --list-cmds=porcelain","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-25T14:39:34Z","receivedAt":"2018-04-25T14:40:11Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Apr 25, 2018 at 3:06 PM, SZEDER Gábor <szeder.dev@gmail.com> wrote:\n>> -__git_list_all_commands ()\n>\n>> -__git_list_porcelain_commands ()\n>\n> Users can have their own completion scriptlets for their own git\n> commands, and these should be able to rely on helper functions in\n> git-completion.bash to do things like refs completion and what not.\n> Therefore, we tend not to remove or alter those helper functions in a\n> backwards incompatible way, because we don't want to break those\n> completion scriptlets.\n\nWhat kind of \"API\" guarantee do we provide here? I don't mind adding\nthe wrappers, but for me it's hard for new contributors (like me) to\nsee which one should be stable and which one is internal.\n-- \nDuy\n"},{"id":"345801","messageId":"CACsJy8Bw0+Zdq6yhw4J0W=HccB57_ssFHaHgShuM5bWiDyhtMg@mail.gmail.com","threadId":"48155","inReplyTo":"CAM0VKjnD4ZnZjwO6M=P1NcJCfJCfJb=tR5CKwSOeCBvUbjcB=Q@mail.gmail.com","subject":"Re: [PATCH v3 4/6] git.c: implement --list-cmds=porcelain","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-25T14:44:42Z","receivedAt":"2018-04-25T14:45:16Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Apr 25, 2018 at 3:46 PM, SZEDER Gábor <szeder.dev@gmail.com> wrote:\n> On Tue, Apr 24, 2018 at 6:17 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n>> On Tue, Apr 24, 2018 at 6:12 PM, Duy Nguyen <pclouds@gmail.com> wrote:\n>>> git-completion.bash will be updated to ask git \"give me the commands\n>>> in the mainporcelain, completable or external category\". This also\n>>> addresses another thing that bugs me: I wanted an option to let me\n>>> complete all commands instead of just porcelain. This approach kinda\n>>> generalizes that and it would be easy to let the user choose what\n>>> category they want to complete.\n>>\n>> To complete this: there could also be yet another special category\n>> \"custom\", where --list-cmds=custom simply returns a list of commands\n>> specified in config file. With this the user can pick the \"custom\"\n>> category to have total control of what command shows up at \"git <tab>\"\n>> if they are not satisfied with the predefined categories.\n>\n> Note that config settings can be repository-specific, which might\n> cause surprises if the user sets a custom command list in one\n> repository's config file, but not (or a different one!) in others.\n> Then the list of completed commands will depend on where the user\n> happened to be when first hitting 'git <TAB>'.\n\nI think that is expected when the word \"config file\" is mentioned.\nIt's no different than aliases, which could also be repo specific and\naffects completion.\n\n> Unless you forgo\n> caching the list of commands and run 'git --list-cmds=...' every time\n> the user hits 'git <TAB>', but that will add the overhead of fork()ing\n> a subshell and a git command.\n\nThis is a good point. I'd rather forgo caching iff the \"custom\"\nstrategy is used (technically we could still cache if we know the\nsource if $HOME/.gitconfig or higher but it's not worth the effort).\nJust make it clear to the user that if they go with \"custom\" strategy\nthen they may hit some performance hit.\n\n> Once upon a time I toyed with the idea of introducing environment\n> variables like $GIT_COMPLETION_EXCLUDE_COMMANDS and\n> $GIT_COMPLETION_INCLUDE_COMMANDS, to exclude and include commands from\n> 'git <TAB>'.  I wanted to exclude 'git cherry', because I have never\n> ever used it but it's always in the way when I want to cherry-pick.\n> And I wanted to include 'git for-each-ref' back when I was running it\n> frequently while working on speeding up refs completion, but it\n> wouldn't have brought that much benefits, because I have a 'git\n> for-each-commit' script, too.\n> Never really pursued it, though, just patched the long list in\n> __git_list_porcelain_commands() in my git clone :)\n\nI'm tempted to support \"delta custom list\" (e.g. \"+cherry-pick\" in the\nconfig variable means \"add that command on the existing list\", or\n\"-blame\" means exclude it) but that's probably too much work.\n-- \nDuy\n"},{"id":"345811","messageId":"20180425163107.10399-1-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180421165414.30051-1-pclouds@gmail.com","subject":"[PATCH v4/wip 00/12] Keep all info in command-list.txt in git binary","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-25T16:30:55Z","receivedAt":"2018-04-25T16:31:31Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is not exactly v4 and likely broken. But I've made several\ndebatable changes and would like your opinions before making even more\nchanges in this direction.\n\nIn 03/12 I made a format change in command-list.txt. The group\ndescription is no longer in this file but in help.c instead. This\nsimplifies the format. However it may be harder for people to know\nwhat category means what (but then it's already so for a lot more\ncategories).\n\nIn 11/12 I added the new \"complete\" category to command-list.txt so\nthat we could replace the giant list in git-completion.bash. This is\nreally questionable because several commands will NOT be completable\nanymore. These are listed there so we can discuss.\n\nAnother thing I wonder is, whether I should tag \"nocomplete\" instead\nof \"complete\" in command-list.txt, similar to parseopt's nocomplete\nstrategy: commands are completable by default then we just exclude\nsome of them. The \"complete\" tag goes the opposite direction, we only\nshow ones that are either external, \"complete\" or mainporcelain.\n\nI think we would go with whitelist than blacklist though to avoid\nhelper commands showing up by default...\n\nAlso in 02/12 I moved to fixed column format. Strictly speaking I\ndo not need that (but it makes the code slightly more complex). If you\nare really against fixed column format, speak up now.\n\nNguyễn Thái Ngọc Duy (12):\n  generate-cmds.sh: factor out synopsis extract code\n  generate-cmds.sh: export all commands to command-list.h\n  help: use command-list.h for common command list\n  Remove common-cmds.h\n  git.c: convert --list-*builtins to --list-cmds=*\n  git: accept multiple --list-cmds options\n  completion: implement and use --list-cmds=all\n  git: support --list-cmds=<category>\n  help: add \"-a --verbose\" to list all commands with synopsis\n  help: use command-list.txt for the source of guides\n  command-list.txt: add new category \"complete\"\n  completion: let git provide the completable command list\n\n .gitignore                             |   2 +-\n Documentation/git-help.txt             |   4 +-\n Documentation/gitattributes.txt        |   2 +-\n Documentation/gitmodules.txt           |   2 +-\n Documentation/gitrevisions.txt         |   2 +-\n Makefile                               |  16 +--\n builtin/help.c                         |  39 +-----\n command-list.txt                       |  55 ++++----\n contrib/completion/git-completion.bash | 121 +++-------------\n generate-cmdlist.sh                    | 128 +++++++++++------\n git.c                                  |  19 ++-\n help.c                                 | 186 +++++++++++++++++++++----\n help.h                                 |   4 +\n t/t0012-help.sh                        |  11 +-\n t/t9902-completion.sh                  |   5 +-\n 15 files changed, 344 insertions(+), 252 deletions(-)\n\n-- \n2.17.0.519.gb89679a4aa\n\n"},{"id":"345812","messageId":"20180425163107.10399-2-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-1-pclouds@gmail.com","subject":"[PATCH v4/wip 01/12] generate-cmds.sh: factor out synopsis extract code","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-25T16:30:56Z","receivedAt":"2018-04-25T16:31:34Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This makes it easier to reuse the same code in another place (very\nsoon).\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n generate-cmdlist.sh | 20 +++++++++++++-------\n 1 file changed, 13 insertions(+), 7 deletions(-)\n\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex eeea4b67ea..17d6809ef5 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -1,5 +1,17 @@\n #!/bin/sh\n \n+get_synopsis () {\n+\tlocal cmd=\"$1\"\n+\n+\tsed -n '\n+\t\t/^NAME/,/'\"$cmd\"'/H\n+\t\t${\n+\t\t\tx\n+\t\t\ts/.*'\"$cmd\"' - \\(.*\\)/N_(\"\\1\")/\n+\t\t\tp\n+\t\t}' \"Documentation/$cmd.txt\"\n+}\n+\n echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n \tchar name[16];\n@@ -39,12 +51,6 @@ sort |\n while read cmd tags\n do\n \ttag=$(echo \"$tags\" | sed \"$substnum; s/[^0-9]//g\")\n-\tsed -n '\n-\t\t/^NAME/,/git-'\"$cmd\"'/H\n-\t\t${\n-\t\t\tx\n-\t\t\ts/.*git-'\"$cmd\"' - \\(.*\\)/\t{\"'\"$cmd\"'\", N_(\"\\1\"), '$tag'},/\n-\t\t\tp\n-\t\t}' \"Documentation/git-$cmd.txt\"\n+\techo \"\t{\\\"$cmd\\\", $(get_synopsis git-$cmd), $tag},\"\n done\n echo \"};\"\n-- \n2.17.0.519.gb89679a4aa\n\n"},{"id":"345813","messageId":"20180425163107.10399-3-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-1-pclouds@gmail.com","subject":"[PATCH v4/wip 02/12] generate-cmds.sh: export all commands to command-list.h","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-25T16:30:57Z","receivedAt":"2018-04-25T16:31:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The current generate-cmds.sh generates just enough to print \"git help\"\noutput. That is, it only extracts help text for common commands.\n\nThe script is now updated to extract help text for all commands and\nkeep command classification a new file, command-list.h. This will be\nuseful later:\n\n- \"git help -a\" could print a short summary of all commands instead of\n  just the common ones.\n\n- \"git\" could produce a list of commands of one or more category. One\n  of its use is to reduce another command classification embedded in\n  git-completion.bash.\n\nThe new file can be generated but is not used anywhere yet. The plan\nis we migrate away from common-cmds.h. Then we can kill off\ncommon-cmds.h build rules and generation code (and also delete\nduplicate content in command-list.h which we keep for now to not mess\ngenerate-cmds.sh up too much).\n\nPS. The new fixed column requirement on command-list.txt is\ntechnically not needed. But it helps simplify the code a bit at this\nstage. We could lift this restriction later if we want to.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n .gitignore          |  1 +\n Makefile            | 13 ++++++---\n command-list.txt    |  4 +--\n generate-cmdlist.sh | 67 ++++++++++++++++++++++++++++++++++++++++++---\n 4 files changed, 75 insertions(+), 10 deletions(-)\n\ndiff --git a/.gitignore b/.gitignore\nindex 833ef3b0b7..d4c3914167 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -180,6 +180,7 @@\n /gitweb/static/gitweb.js\n /gitweb/static/gitweb.min.*\n /common-cmds.h\n+/command-list.h\n *.tar.gz\n *.dsc\n *.deb\ndiff --git a/Makefile b/Makefile\nindex f181687250..2a8913ea21 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -757,7 +757,7 @@ LIB_FILE = libgit.a\n XDIFF_LIB = xdiff/lib.a\n VCSSVN_LIB = vcs-svn/lib.a\n \n-GENERATED_H += common-cmds.h\n+GENERATED_H += common-cmds.h command-list.h\n \n LIB_H = $(shell $(FIND) . \\\n \t-name .git -prune -o \\\n@@ -1938,6 +1938,11 @@ $(BUILT_INS): git$X\n common-cmds.h: generate-cmdlist.sh command-list.txt\n \n common-cmds.h: $(wildcard Documentation/git-*.txt)\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt COMMON >$@+ && mv $@+ $@\n+\n+command-list.h: generate-cmdlist.sh command-list.txt\n+\n+command-list.h: $(wildcard Documentation/git-*.txt)\n \t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt >$@+ && mv $@+ $@\n \n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n@@ -2148,7 +2153,7 @@ else\n # Dependencies on header files, for platforms that do not support\n # the gcc -MMD option.\n #\n-# Dependencies on automatically generated headers such as common-cmds.h\n+# Dependencies on automatically generated headers such as common-cmds.h or command-list.h\n # should _not_ be included here, since they are necessary even when\n # building an object for the first time.\n \n@@ -2527,7 +2532,7 @@ sparse: $(SP_OBJ)\n style:\n \tgit clang-format --style file --diff --extensions c,h\n \n-check: common-cmds.h\n+check: common-cmds.h command-list.h\n \t@if sparse; \\\n \tthen \\\n \t\techo >&2 \"Use 'make sparse' instead\"; \\\n@@ -2775,7 +2780,7 @@ clean: profile-clean coverage-clean\n \t$(RM) $(TEST_PROGRAMS) $(NO_INSTALL)\n \t$(RM) -r bin-wrappers $(dep_dirs)\n \t$(RM) -r po/build/\n-\t$(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h $(ETAGS_TARGET) tags cscope*\n+\t$(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h command-list.h $(ETAGS_TARGET) tags cscope*\n \t$(RM) -r $(GIT_TARNAME) .doc-tmp-dir\n \t$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz\n \t$(RM) $(htmldocs).tar.gz $(manpages).tar.gz\ndiff --git a/command-list.txt b/command-list.txt\nindex a1fad28fd8..786536aba0 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -8,8 +8,8 @@ info         examine the history and state (see also: git help revisions)\n history      grow, mark and tweak your common history\n remote       collaborate (see also: git help workflows)\n \n-### command list (do not change this line)\n-# command name                          category [deprecated] [common]\n+### command list (do not change this line, also do not change alignment)\n+# command name                          category [category] [category]\n git-add                                 mainporcelain           worktree\n git-am                                  mainporcelain\n git-annotate                            ancillaryinterrogators\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 17d6809ef5..9ba9911f09 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -1,5 +1,27 @@\n #!/bin/sh\n \n+die () {\n+\techo \"$@\" >&2\n+\texit 1\n+}\n+\n+command_list () {\n+\tsed '1,/^### command list/d;/^#/d' \"$1\"\n+}\n+\n+get_categories() {\n+\ttr ' ' '\\n'|\n+\tgrep -v '^$' |\n+\tsort |\n+\tuniq\n+}\n+\n+category_list () {\n+\tcommand_list \"$1\" |\n+\tcut -c 40- |\n+\tget_categories\n+}\n+\n get_synopsis () {\n \tlocal cmd=\"$1\"\n \n@@ -12,14 +34,51 @@ get_synopsis () {\n \t\t}' \"Documentation/$cmd.txt\"\n }\n \n+define_categories() {\n+\techo\n+\techo \"/* Command categories */\"\n+\tbit=0\n+\tcategory_list \"$1\" |\n+\twhile read cat\n+\tdo\n+\t\techo \"#define CAT_$cat (1UL << $bit)\"\n+\t\tbit=$(($bit+1))\n+\tdone\n+\ttest \"$bit\" -gt 32 && die \"Urgh.. too many categories?\"\n+}\n+\n+print_command_list() {\n+\techo \"static struct cmdname_help command_list[] = {\"\n+\n+\tcommand_list \"$1\" |\n+\twhile read cmd rest\n+\tdo\n+\t\tprintf \"\t{ \\\"$cmd\\\", $(get_synopsis $cmd), 0\"\n+\t\tfor cat in $(echo \"$rest\" | get_categories)\n+\t\tdo\n+\t\t\tprintf \" | CAT_$cat\"\n+\t\tdone\n+\t\techo \" },\"\n+\tdone\n+\techo \"};\"\n+}\n+\n echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n-\tchar name[16];\n-\tchar help[80];\n-\tunsigned char group;\n+\tconst char *name;\n+\tconst char *help;\n+\tuint32_t group;\n };\n+\"\n+if [ -z \"$2\" ]\n+then\n+\tdefine_categories \"$1\"\n+\techo\n+\tprint_command_list \"$1\"\n+\texit 0\n+fi\n \n-static const char *common_cmd_groups[] = {\"\n+echo \"static const char *common_cmd_groups[] = {\"\n \n grps=grps$$.tmp\n match=match$$.tmp\n-- \n2.17.0.519.gb89679a4aa\n\n"},{"id":"345814","messageId":"20180425163107.10399-4-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-1-pclouds@gmail.com","subject":"[PATCH v4/wip 03/12] help: use command-list.h for common command list","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-25T16:30:58Z","receivedAt":"2018-04-25T16:31:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The previous commit added code generation for all_cmd_desc[] which\nincludes almost everything we need to generate common command list.\nConvert help code to use that array instead and drop common_cmds[] array.\n\nThe description of each common command group is removed from\ncommand-list.txt. This keeps this file format simpler. common-cmds.h\nwill not be generated correctly after this change due to the\ncommand-list.txt format change. But it does not matter and\ncommon-cmds.h will be removed.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Makefile            |   4 +-\n command-list.txt    |  10 ----\n generate-cmdlist.sh |   4 +-\n help.c              | 135 ++++++++++++++++++++++++++++++++------------\n 4 files changed, 103 insertions(+), 50 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 2a8913ea21..5c58b0b692 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1914,9 +1914,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \\\n \t\t$(filter %.o,$^) $(LIBS)\n \n-help.sp help.s help.o: common-cmds.h\n+help.sp help.s help.o: common-cmds.h command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h GIT-PREFIX\n+builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h command-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\ndiff --git a/command-list.txt b/command-list.txt\nindex 786536aba0..3bd23201a6 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -1,13 +1,3 @@\n-# common commands are grouped by themes\n-# these groups are output by 'git help' in the order declared here.\n-# map each common command in the command list to one of these groups.\n-### common groups (do not change this line)\n-init         start a working area (see also: git help tutorial)\n-worktree     work on the current change (see also: git help everyday)\n-info         examine the history and state (see also: git help revisions)\n-history      grow, mark and tweak your common history\n-remote       collaborate (see also: git help workflows)\n-\n ### command list (do not change this line, also do not change alignment)\n # command name                          category [category] [category]\n git-add                                 mainporcelain           worktree\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 9ba9911f09..88968160e3 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -6,7 +6,7 @@ die () {\n }\n \n command_list () {\n-\tsed '1,/^### command list/d;/^#/d' \"$1\"\n+\tgrep -v '^#' \"$1\"\n }\n \n get_categories() {\n@@ -67,7 +67,7 @@ echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n \tconst char *name;\n \tconst char *help;\n-\tuint32_t group;\n+\tuint32_t category;\n };\n \"\n if [ -z \"$2\" ]\ndiff --git a/help.c b/help.c\nindex 60071a9bea..5b4a2f1b4f 100644\n--- a/help.c\n+++ b/help.c\n@@ -5,13 +5,104 @@\n #include \"run-command.h\"\n #include \"levenshtein.h\"\n #include \"help.h\"\n-#include \"common-cmds.h\"\n+#include \"command-list.h\"\n #include \"string-list.h\"\n #include \"column.h\"\n #include \"version.h\"\n #include \"refs.h\"\n #include \"parse-options.h\"\n \n+struct category_description {\n+\tuint32_t category;\n+\tconst char *desc;\n+};\n+static uint32_t common_mask =\n+\tCAT_init | CAT_worktree | CAT_info |\n+\tCAT_history | CAT_remote;\n+static struct category_description common_categories[] = {\n+\t{ CAT_init, N_(\"start a working area (see also: git help tutorial)\") },\n+\t{ CAT_worktree, N_(\"work on the current change (see also: git help everyday)\") },\n+\t{ CAT_info, N_(\"examine the history and state (see also: git help revisions)\") },\n+\t{ CAT_history, N_(\"grow, mark and tweak your common history\") },\n+\t{ CAT_remote, N_(\"collaborate (see also: git help workflows)\") },\n+\t{ 0, NULL }\n+};\n+\n+static void extract_cmds(struct cmdname_help **p_cmds, uint32_t mask)\n+{\n+\tint i, nr = 0;\n+\tstruct cmdname_help *cmds;\n+\n+\tALLOC_ARRAY(cmds, ARRAY_SIZE(command_list) + 1);\n+\n+\tfor (i = 0; i < ARRAY_SIZE(command_list); i++) {\n+\t\tconst struct cmdname_help *cmd = command_list + i;\n+\t\tconst char *name;\n+\n+\t\tif (!(cmd->category & mask))\n+\t\t\tcontinue;\n+\n+\t\tcmds[nr] = *cmd;\n+\n+\t\tif (skip_prefix(cmd->name, \"git-\", &name))\n+\t\t\tcmds[nr].name = name;\n+\n+\t\tnr++;\n+\t}\n+\tcmds[nr].name = NULL;\n+\t*p_cmds = cmds;\n+}\n+\n+static void print_command_list(const struct cmdname_help *cmds,\n+\t\t\t       uint32_t mask, int longest)\n+{\n+\tint i;\n+\n+\tfor (i = 0; cmds[i].name; i++) {\n+\t\tif (cmds[i].category & mask) {\n+\t\t\tprintf(\"   %s   \", cmds[i].name);\n+\t\t\tmput_char(' ', longest - strlen(cmds[i].name));\n+\t\t\tputs(_(cmds[i].help));\n+\t\t}\n+\t}\n+}\n+\n+static int cmd_name_cmp(const void *elem1, const void *elem2)\n+{\n+\tconst struct cmdname_help *e1 = elem1;\n+\tconst struct cmdname_help *e2 = elem2;\n+\n+\treturn strcmp(e1->name, e2->name);\n+}\n+\n+static void print_cmd_by_category(const struct category_description *catdesc)\n+{\n+\tstruct cmdname_help *cmds;\n+\tint longest = 0;\n+\tint i, nr = 0;\n+\tuint32_t mask = 0;\n+\n+\tfor (i = 0; catdesc[i].desc; i++)\n+\t\tmask |= catdesc[i].category;\n+\n+\textract_cmds(&cmds, mask);\n+\n+\tfor (i = 0; cmds[i].name; i++, nr++) {\n+\t\tif (longest < strlen(cmds[i].name))\n+\t\t\tlongest = strlen(cmds[i].name);\n+\t}\n+\tQSORT(cmds, nr, cmd_name_cmp);\n+\n+\tfor (i = 0; catdesc[i].desc; i++) {\n+\t\tuint32_t mask = catdesc[i].category;\n+\t\tconst char *desc = catdesc[i].desc;\n+\n+\t\tprintf(\"\\n%s\\n\", _(desc));\n+\t\tprint_command_list(cmds, mask, longest);\n+\t}\n+\tfree(cmds);\n+}\n+\n void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n {\n \tstruct cmdname *ent;\n@@ -190,42 +281,10 @@ void list_commands(unsigned int colopts,\n \t}\n }\n \n-static int cmd_group_cmp(const void *elem1, const void *elem2)\n-{\n-\tconst struct cmdname_help *e1 = elem1;\n-\tconst struct cmdname_help *e2 = elem2;\n-\n-\tif (e1->group < e2->group)\n-\t\treturn -1;\n-\tif (e1->group > e2->group)\n-\t\treturn 1;\n-\treturn strcmp(e1->name, e2->name);\n-}\n-\n void list_common_cmds_help(void)\n {\n-\tint i, longest = 0;\n-\tint current_grp = -1;\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-\tQSORT(common_cmds, ARRAY_SIZE(common_cmds), cmd_group_cmp);\n-\n \tputs(_(\"These are common Git commands used in various situations:\"));\n-\n-\tfor (i = 0; i < ARRAY_SIZE(common_cmds); i++) {\n-\t\tif (common_cmds[i].group != current_grp) {\n-\t\t\tprintf(\"\\n%s\\n\", _(common_cmd_groups[common_cmds[i].group]));\n-\t\t\tcurrent_grp = common_cmds[i].group;\n-\t\t}\n-\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+\tprint_cmd_by_category(common_categories);\n }\n \n int is_in_cmdlist(struct cmdnames *c, const char *s)\n@@ -285,6 +344,7 @@ const char *help_unknown_cmd(const char *cmd)\n {\n \tint i, n, best_similarity = 0;\n \tstruct cmdnames main_cmds, other_cmds;\n+\tstruct cmdname_help *common_cmds;\n \n \tmemset(&main_cmds, 0, sizeof(main_cmds));\n \tmemset(&other_cmds, 0, sizeof(other_cmds));\n@@ -299,6 +359,8 @@ const char *help_unknown_cmd(const char *cmd)\n \tQSORT(main_cmds.names, main_cmds.cnt, cmdname_compare);\n \tuniq(&main_cmds);\n \n+\textract_cmds(&common_cmds, common_mask);\n+\n \t/* This abuses cmdname->len for levenshtein distance */\n \tfor (i = 0, n = 0; i < main_cmds.cnt; i++) {\n \t\tint cmp = 0; /* avoid compiler stupidity */\n@@ -313,10 +375,10 @@ const char *help_unknown_cmd(const char *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\twhile (common_cmds[n].name &&\n \t\t       (cmp = strcmp(common_cmds[n].name, candidate)) < 0)\n \t\t\tn++;\n-\t\tif ((n < ARRAY_SIZE(common_cmds)) && !cmp) {\n+\t\tif (common_cmds[n].name && !cmp) {\n \t\t\t/* Yes, this is one of the common commands */\n \t\t\tn++; /* use the entry from common_cmds[] */\n \t\t\tif (starts_with(candidate, cmd)) {\n@@ -329,6 +391,7 @@ const char *help_unknown_cmd(const char *cmd)\n \t\tmain_cmds.names[i]->len =\n \t\t\tlevenshtein(cmd, candidate, 0, 2, 1, 3) + 1;\n \t}\n+\tFREE_AND_NULL(common_cmds);\n \n \tQSORT(main_cmds.names, main_cmds.cnt, levenshtein_compare);\n \n-- \n2.17.0.519.gb89679a4aa\n\n"},{"id":"345815","messageId":"20180425163107.10399-9-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-1-pclouds@gmail.com","subject":"[PATCH v4/wip 08/12] git: support --list-cmds=<category>","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-25T16:31:03Z","receivedAt":"2018-04-25T16:31:47Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This allows us to select any group of commands by a category defined\nin command-list.txt. This is an internal/hidden option so we don't\nhave to be picky about the category name or worried about exposing too\nmuch.\n\nThis will be used later by git-completion.bash to retrieve certain\ncommand groups.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n generate-cmdlist.sh | 17 +++++++++++++++++\n git.c               |  2 +-\n help.c              | 19 +++++++++++++++++++\n help.h              |  1 +\n 4 files changed, 38 insertions(+), 1 deletion(-)\n\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 57f9800123..c14c0a7adc 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -47,6 +47,21 @@ define_categories() {\n \ttest \"$bit\" -gt 32 && die \"Urgh.. too many categories?\"\n }\n \n+define_category_names() {\n+\techo\n+\techo \"/* Category names */\"\n+\techo \"static const char *category_names[] = {\"\n+\tbit=0\n+\tcategory_list \"$1\" |\n+\twhile read cat\n+\tdo\n+\t\techo \"\t\\\"$cat\\\", /* (1UL << $bit) */\"\n+\t\tbit=$(($bit+1))\n+\tdone\n+\techo \"\tNULL\"\n+\techo \"};\"\n+}\n+\n print_command_list() {\n \techo \"static struct cmdname_help command_list[] = {\"\n \n@@ -72,4 +87,6 @@ struct cmdname_help {\n \"\n define_categories \"$1\"\n echo\n+define_category_names \"$1\"\n+echo\n print_command_list \"$1\"\ndiff --git a/git.c b/git.c\nindex fa6e542d06..6c071d44f5 100644\n--- a/git.c\n+++ b/git.c\n@@ -232,7 +232,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\telse if (!strcmp(cmd, \"all\"))\n \t\t\t\tlist_all_cmds();\n \t\t\telse\n-\t\t\t\tdie(\"unsupported command listing type '%s'\", cmd);\n+\t\t\t\tlist_cmds_by_category(cmd);\n \t\t\tcommands_listed++;\n \t\t} else {\n \t\t\tfprintf(stderr, _(\"unknown option: %s\\n\"), cmd);\ndiff --git a/help.c b/help.c\nindex 217864999e..affa8e4343 100644\n--- a/help.c\n+++ b/help.c\n@@ -305,6 +305,25 @@ void list_all_cmds(void)\n \tclean_cmdnames(&other_cmds);\n }\n \n+void list_cmds_by_category(const char *cat)\n+{\n+\tint i;\n+\tint cat_id = 0;\n+\n+\tfor (i = 0; category_names[i]; i++) {\n+\t\tif (!strcmp(cat, category_names[i])) {\n+\t\t\tcat_id = 1 << i;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\tif (!cat_id)\n+\t\tdie(\"unsupported command listing type '%s'\", cat);\n+\n+\tfor (i = 0; command_list[i].name; i++)\n+\t\tif (command_list[i].category & cat_id)\n+\t\t\tputs(command_list[i].name);\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex 0bf29f8dc5..3e30542927 100644\n--- a/help.h\n+++ b/help.h\n@@ -18,6 +18,7 @@ static inline void mput_char(char c, unsigned int num)\n \n extern void list_common_cmds_help(void);\n extern void list_all_cmds(void);\n+extern void list_cmds_by_category(const char *category);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\n-- \n2.17.0.519.gb89679a4aa\n\n"},{"id":"345816","messageId":"20180425163107.10399-8-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-1-pclouds@gmail.com","subject":"[PATCH v4/wip 07/12] completion: implement and use --list-cmds=all","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-25T16:31:02Z","receivedAt":"2018-04-25T16:31:48Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Instead of parsing \"git help -a\" output, which is tricky to get right,\nless elegant and also slow, make git provide the list in\nmachine-friendly form.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash |  2 +-\n git.c                                  |  2 ++\n help.c                                 | 18 ++++++++++++++++++\n help.h                                 |  1 +\n 4 files changed, 22 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 3556838759..a5f13ade20 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -839,7 +839,7 @@ __git_commands () {\n \tthen\n \t\tprintf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n \telse\n-\t\tgit help -a|egrep '^  [a-zA-Z0-9]'\n+\t\tgit --list-cmds=all\n \tfi\n }\n \ndiff --git a/git.c b/git.c\nindex a46263306d..fa6e542d06 100644\n--- a/git.c\n+++ b/git.c\n@@ -229,6 +229,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t\tlist_builtins(0, '\\n');\n \t\t\telse if (!strcmp(cmd, \"parseopt\"))\n \t\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n+\t\t\telse if (!strcmp(cmd, \"all\"))\n+\t\t\t\tlist_all_cmds();\n \t\t\telse\n \t\t\t\tdie(\"unsupported command listing type '%s'\", cmd);\n \t\t\tcommands_listed++;\ndiff --git a/help.c b/help.c\nindex 5b4a2f1b4f..217864999e 100644\n--- a/help.c\n+++ b/help.c\n@@ -287,6 +287,24 @@ void list_common_cmds_help(void)\n \tprint_cmd_by_category(common_categories);\n }\n \n+void list_all_cmds(void)\n+{\n+\tstruct cmdnames main_cmds, other_cmds;\n+\tint i;\n+\n+\tmemset(&main_cmds, 0, sizeof(main_cmds));\n+\tmemset(&other_cmds, 0, sizeof(other_cmds));\n+\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n+\n+\tfor (i = 0; i < main_cmds.cnt; i++)\n+\t\tputs(main_cmds.names[i]->name);\n+\tfor (i = 0; i < other_cmds.cnt; i++)\n+\t\tputs(other_cmds.names[i]->name);\n+\n+\tclean_cmdnames(&main_cmds);\n+\tclean_cmdnames(&other_cmds);\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex b21d7c94e8..0bf29f8dc5 100644\n--- a/help.h\n+++ b/help.h\n@@ -17,6 +17,7 @@ static inline void mput_char(char c, unsigned int num)\n }\n \n extern void list_common_cmds_help(void);\n+extern void list_all_cmds(void);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\n-- \n2.17.0.519.gb89679a4aa\n\n"},{"id":"345817","messageId":"20180425163107.10399-7-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-1-pclouds@gmail.com","subject":"[PATCH v4/wip 06/12] git: accept multiple --list-cmds options","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-25T16:31:01Z","receivedAt":"2018-04-25T16:31:49Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Later on we may support non-overlapping command groups to\n--list-cmds. Allow the user to execute just one \"git\" process and get\nmultiple groups. This may matter for git-completion.bash on Windows\nbecause we don't want the user to way for long when TAB-ing and\nWindows is slow on launching new processes.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n git.c | 5 ++++-\n 1 file changed, 4 insertions(+), 1 deletion(-)\n\ndiff --git a/git.c b/git.c\nindex 28bfa96d87..a46263306d 100644\n--- a/git.c\n+++ b/git.c\n@@ -64,6 +64,7 @@ void setup_auto_pager(const char *cmd, int def)\n static int handle_options(const char ***argv, int *argc, int *envchanged)\n {\n \tconst char **orig_argv = *argv;\n+\tint commands_listed = 0;\n \n \twhile (*argc > 0) {\n \t\tconst char *cmd = (*argv)[0];\n@@ -230,7 +231,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n \t\t\telse\n \t\t\t\tdie(\"unsupported command listing type '%s'\", cmd);\n-\t\t\texit(0);\n+\t\t\tcommands_listed++;\n \t\t} else {\n \t\t\tfprintf(stderr, _(\"unknown option: %s\\n\"), cmd);\n \t\t\tusage(git_usage_string);\n@@ -239,6 +240,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t(*argv)++;\n \t\t(*argc)--;\n \t}\n+\tif (commands_listed)\n+\t\texit(0);\n \treturn (*argv) - orig_argv;\n }\n \n-- \n2.17.0.519.gb89679a4aa\n\n"},{"id":"345818","messageId":"20180425163107.10399-12-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-1-pclouds@gmail.com","subject":"[PATCH v4/wip 11/12] command-list.txt: add new category \"complete\"","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-25T16:31:06Z","receivedAt":"2018-04-25T16:31:56Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This category, combined with 'external' and 'mainporcelain', is\nintended to replace the \"porcelain command list\" in git-completion.bash.\nIn other words, these are the commands that will show up by default\nwhen you type \"git <tab>\".\n\nCompared to the current list in git-completion.bash (which is\nbasically \"git help -a\" with a black list), the following commands no\nlonger show up:\n\n- annotate          obsolete, discouraged to use\n- difftool-helper   not an end user command\n- filter-branch     not often used\n- get-tar-commit-id not often used\n- imap-send         not often used\n- instaweb          does anybody still run this interactively?\n- interpreter-trailers not an interactive command\n- lost-found        obsolete\n- mergetool         ???\n- p4                too short to complete?\n- peek-remote       not often used??\n- svn               ???\n- tar-tree          obsolete, use archive instead\n- verify-commit     not often used\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n command-list.txt | 33 +++++++++++++++++----------------\n 1 file changed, 17 insertions(+), 16 deletions(-)\n\ndiff --git a/command-list.txt b/command-list.txt\nindex a57bcb64a1..40b56c57f5 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -3,11 +3,11 @@\n git-add                                 mainporcelain           worktree\n git-am                                  mainporcelain\n git-annotate                            ancillaryinterrogators\n-git-apply                               plumbingmanipulators\n+git-apply                               plumbingmanipulators            complete\n git-archimport                          foreignscminterface\n git-archive                             mainporcelain\n git-bisect                              mainporcelain           info\n-git-blame                               ancillaryinterrogators\n+git-blame                               ancillaryinterrogators          complete\n git-branch                              mainporcelain           history\n git-bundle                              mainporcelain\n git-cat-file                            plumbinginterrogators\n@@ -17,7 +17,7 @@ git-check-mailmap                       purehelpers\n git-checkout                            mainporcelain           history\n git-checkout-index                      plumbingmanipulators\n git-check-ref-format                    purehelpers\n-git-cherry                              ancillaryinterrogators\n+git-cherry                              ancillaryinterrogators          complete\n git-cherry-pick                         mainporcelain\n git-citool                              mainporcelain\n git-clean                               mainporcelain\n@@ -25,7 +25,7 @@ git-clone                               mainporcelain           init\n git-column                              purehelpers\n git-commit                              mainporcelain           history\n git-commit-tree                         plumbingmanipulators\n-git-config                              ancillarymanipulators\n+git-config                              ancillarymanipulators           complete\n git-count-objects                       ancillaryinterrogators\n git-credential                          purehelpers\n git-credential-cache                    purehelpers\n@@ -39,7 +39,7 @@ git-diff                                mainporcelain           history\n git-diff-files                          plumbinginterrogators\n git-diff-index                          plumbinginterrogators\n git-diff-tree                           plumbinginterrogators\n-git-difftool                            ancillaryinterrogators\n+git-difftool                            ancillaryinterrogators          complete\n git-fast-export                         ancillarymanipulators\n git-fast-import                         ancillarymanipulators\n git-fetch                               mainporcelain           remote\n@@ -48,13 +48,13 @@ git-filter-branch                       ancillarymanipulators\n git-fmt-merge-msg                       purehelpers\n git-for-each-ref                        plumbinginterrogators\n git-format-patch                        mainporcelain\n-git-fsck                                ancillaryinterrogators\n+git-fsck                                ancillaryinterrogators          complete\n git-gc                                  mainporcelain\n git-get-tar-commit-id                   ancillaryinterrogators\n git-grep                                mainporcelain           info\n git-gui                                 mainporcelain\n git-hash-object                         plumbingmanipulators\n-git-help                                ancillaryinterrogators\n+git-help                                ancillaryinterrogators          complete\n git-http-backend                        synchingrepositories\n git-http-fetch                          synchelpers\n git-http-push                           synchelpers\n@@ -80,7 +80,7 @@ git-merge-tree                          ancillaryinterrogators\n git-mktag                               plumbingmanipulators\n git-mktree                              plumbingmanipulators\n git-mv                                  mainporcelain           worktree\n-git-name-rev                            plumbinginterrogators\n+git-name-rev                            plumbinginterrogators           complete\n git-notes                               mainporcelain\n git-p4                                  foreignscminterface\n git-pack-objects                        plumbingmanipulators\n@@ -96,28 +96,29 @@ git-quiltimport                         foreignscminterface\n git-read-tree                           plumbingmanipulators\n git-rebase                              mainporcelain           history\n git-receive-pack                        synchelpers\n-git-reflog                              ancillarymanipulators\n-git-remote                              ancillarymanipulators\n-git-repack                              ancillarymanipulators\n-git-replace                             ancillarymanipulators\n-git-request-pull                        foreignscminterface\n+git-reflog                              ancillarymanipulators           complete\n+git-remote                              ancillarymanipulators           complete\n+git-repack                              ancillarymanipulators           complete\n+git-replace                             ancillarymanipulators           complete\n+git-request-pull                        foreignscminterface             complete\n git-rerere                              ancillaryinterrogators\n git-reset                               mainporcelain           worktree\n git-revert                              mainporcelain\n git-rev-list                            plumbinginterrogators\n git-rev-parse                           ancillaryinterrogators\n git-rm                                  mainporcelain           worktree\n-git-send-email                          foreignscminterface\n+git-send-email                          foreignscminterface             complete\n git-send-pack                           synchingrepositories\n git-shell                               synchelpers\n git-shortlog                            mainporcelain\n git-show                                mainporcelain           info\n-git-show-branch                         ancillaryinterrogators\n+git-show-branch                         ancillaryinterrogators          complete\n git-show-index                          plumbinginterrogators\n git-show-ref                            plumbinginterrogators\n git-sh-i18n                             purehelpers\n git-sh-setup                            purehelpers\n git-stash                               mainporcelain\n+git-stage                                                               complete\n git-status                              mainporcelain           info\n git-stripspace                          purehelpers\n git-submodule                           mainporcelain\n@@ -136,7 +137,7 @@ git-verify-commit                       ancillaryinterrogators\n git-verify-pack                         plumbinginterrogators\n git-verify-tag                          ancillaryinterrogators\n gitweb                                  ancillaryinterrogators\n-git-whatchanged                         ancillaryinterrogators\n+git-whatchanged                         ancillaryinterrogators          complete\n git-worktree                            mainporcelain\n git-write-tree                          plumbingmanipulators\n gitattributes                           guide\n-- \n2.17.0.519.gb89679a4aa\n\n"},{"id":"345819","messageId":"20180425163107.10399-10-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-1-pclouds@gmail.com","subject":"[PATCH v4/wip 09/12] help: add \"-a --verbose\" to list all commands with synopsis","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-25T16:31:04Z","receivedAt":"2018-04-25T16:32:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This lists all recognized commands [1] by category. The group order\nfollows closely git.txt.\n\n[1] We may actually show commands that are not built (e.g. if you set\nNO_PERL you don't have git-instaweb but it's still listed here). I\nignore the problem because on Linux a git package could be split\nanyway. The \"git-core\" package may not contain git-instaweb even if\nit's built because it may end up in a separate package. We can't know\nanyway.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-help.txt |  4 +++-\n builtin/help.c             |  7 +++++++\n help.c                     | 16 ++++++++++++++++\n help.h                     |  1 +\n t/t0012-help.sh            |  9 +++++++++\n 5 files changed, 36 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-help.txt b/Documentation/git-help.txt\nindex 40d328a4b3..a40fc38d8b 100644\n--- a/Documentation/git-help.txt\n+++ b/Documentation/git-help.txt\n@@ -8,7 +8,7 @@ git-help - Display help information about Git\n SYNOPSIS\n --------\n [verse]\n-'git help' [-a|--all] [-g|--guide]\n+'git help' [-a|--all [--verbose]] [-g|--guide]\n \t   [-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE]\n \n DESCRIPTION\n@@ -42,6 +42,8 @@ OPTIONS\n --all::\n \tPrints all the available commands on the standard output. This\n \toption overrides any given command or guide name.\n+\tWhen used with `--verbose` print description for all recognized\n+\tcommands.\n \n -g::\n --guides::\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 598867cfea..0e0af8426a 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -36,6 +36,7 @@ static const char *html_path;\n \n static int show_all = 0;\n static int show_guides = 0;\n+static int verbose;\n static unsigned int colopts;\n static enum help_format help_format = HELP_FORMAT_NONE;\n static int exclude_guides;\n@@ -48,6 +49,7 @@ static struct option builtin_help_options[] = {\n \t\t\tHELP_FORMAT_WEB),\n \tOPT_SET_INT('i', \"info\", &help_format, N_(\"show info page\"),\n \t\t\tHELP_FORMAT_INFO),\n+\tOPT__VERBOSE(&verbose, N_(\"print command description\")),\n \tOPT_END(),\n };\n \n@@ -463,6 +465,11 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \tif (show_all) {\n \t\tgit_config(git_help_config, NULL);\n+\t\tif (verbose) {\n+\t\t\tsetup_pager();\n+\t\t\tlist_all_cmds_help();\n+\t\t\treturn 0;\n+\t\t}\n \t\tprintf(_(\"usage: %s%s\"), _(git_usage_string), \"\\n\\n\");\n \t\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n \t\tlist_commands(colopts, &main_cmds, &other_cmds);\ndiff --git a/help.c b/help.c\nindex affa8e4343..1f27d94661 100644\n--- a/help.c\n+++ b/help.c\n@@ -27,6 +27,17 @@ static struct category_description common_categories[] = {\n \t{ CAT_remote, N_(\"collaborate (see also: git help workflows)\") },\n \t{ 0, NULL }\n };\n+static struct category_description main_categories[] = {\n+\t{ CAT_mainporcelain, N_(\"Main Porcelain Commands\") },\n+\t{ CAT_ancillarymanipulators, N_(\"Ancillary Commands / Manipulators\") },\n+\t{ CAT_ancillaryinterrogators, N_(\"Ancillary Commands / Interrogators\") },\n+\t{ CAT_foreignscminterface, N_(\"Interacting with Others\") },\n+\t{ CAT_plumbingmanipulators, N_(\"Low-level Commands / Manipulators\") },\n+\t{ CAT_plumbinginterrogators, N_(\"Low-level Commands / Interrogators\") },\n+\t{ CAT_synchingrepositories, N_(\"Low-level Commands / Synching Repositories\") },\n+\t{ CAT_purehelpers, N_(\"Low-level Commands / Internal Helpers\") },\n+\t{ 0, NULL }\n+};\n \n static void extract_cmds(struct cmdname_help **p_cmds, uint32_t mask)\n {\n@@ -324,6 +335,11 @@ void list_cmds_by_category(const char *cat)\n \t\t\tputs(command_list[i].name);\n }\n \n+void list_all_cmds_help(void)\n+{\n+\tprint_cmd_by_category(main_categories);\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex 3e30542927..118b7d9947 100644\n--- a/help.h\n+++ b/help.h\n@@ -17,6 +17,7 @@ static inline void mput_char(char c, unsigned int num)\n }\n \n extern void list_common_cmds_help(void);\n+extern void list_all_cmds_help(void);\n extern void list_all_cmds(void);\n extern void list_cmds_by_category(const char *category);\n extern const char *help_unknown_cmd(const char *cmd);\ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex fd2a7f27dc..53208ab20e 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -25,6 +25,15 @@ test_expect_success \"setup\" '\n \tEOF\n '\n \n+# make sure to exercise these code paths, the output is a bit tricky\n+# to verify\n+test_expect_success 'basic help commands' '\n+\tgit help >/dev/null &&\n+\tgit help -a >/dev/null &&\n+\tgit help -g >/dev/null &&\n+\tgit help -av >/dev/null\n+'\n+\n test_expect_success \"works for commands and guides by default\" '\n \tconfigure_help &&\n \tgit help status &&\n-- \n2.17.0.519.gb89679a4aa\n\n"},{"id":"345820","messageId":"20180425163107.10399-11-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-1-pclouds@gmail.com","subject":"[PATCH v4/wip 10/12] help: use command-list.txt for the source of guides","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-25T16:31:05Z","receivedAt":"2018-04-25T16:32:03Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The help command currently hard codes the list of guides and their\nsummary in C. Let's move this list to command-list.txt. This lets us\nextract summary lines from Documentation/git*.txt. This also\npotentially lets us lists guides in git.txt, but I'll leave that for\nnow.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/gitattributes.txt |  2 +-\n Documentation/gitmodules.txt    |  2 +-\n Documentation/gitrevisions.txt  |  2 +-\n Makefile                        |  2 +-\n builtin/help.c                  | 32 --------------------------------\n command-list.txt                |  8 ++++++++\n help.c                          | 14 +++++++++++++-\n help.h                          |  1 +\n 8 files changed, 26 insertions(+), 37 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex 1094fe2b5b..083c2f380d 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -3,7 +3,7 @@ gitattributes(5)\n \n NAME\n ----\n-gitattributes - defining attributes per path\n+gitattributes - Defining attributes per path\n \n SYNOPSIS\n --------\ndiff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt\nindex db5d47eb19..4d63def206 100644\n--- a/Documentation/gitmodules.txt\n+++ b/Documentation/gitmodules.txt\n@@ -3,7 +3,7 @@ gitmodules(5)\n \n NAME\n ----\n-gitmodules - defining submodule properties\n+gitmodules - Defining submodule properties\n \n SYNOPSIS\n --------\ndiff --git a/Documentation/gitrevisions.txt b/Documentation/gitrevisions.txt\nindex 27dec5b91d..1f6cceaefb 100644\n--- a/Documentation/gitrevisions.txt\n+++ b/Documentation/gitrevisions.txt\n@@ -3,7 +3,7 @@ gitrevisions(7)\n \n NAME\n ----\n-gitrevisions - specifying revisions and ranges for Git\n+gitrevisions - Specifying revisions and ranges for Git\n \n SYNOPSIS\n --------\ndiff --git a/Makefile b/Makefile\nindex a60a78ee67..1efb751e46 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1937,7 +1937,7 @@ $(BUILT_INS): git$X\n \n command-list.h: generate-cmdlist.sh command-list.txt\n \n-command-list.h: $(wildcard Documentation/git-*.txt)\n+command-list.h: $(wildcard Documentation/git*.txt)\n \t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt >$@+ && mv $@+ $@\n \n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 0e0af8426a..5727fb5e51 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -402,38 +402,6 @@ static void show_html_page(const char *git_cmd)\n \topen_html(page_path.buf);\n }\n \n-static struct {\n-\tconst char *name;\n-\tconst char *help;\n-} common_guides[] = {\n-\t{ \"attributes\", N_(\"Defining attributes per path\") },\n-\t{ \"everyday\", N_(\"Everyday Git With 20 Commands Or So\") },\n-\t{ \"glossary\", N_(\"A Git glossary\") },\n-\t{ \"ignore\", N_(\"Specifies intentionally untracked files to ignore\") },\n-\t{ \"modules\", N_(\"Defining submodule properties\") },\n-\t{ \"revisions\", N_(\"Specifying revisions and ranges for Git\") },\n-\t{ \"tutorial\", N_(\"A tutorial introduction to Git (for version 1.5.1 or newer)\") },\n-\t{ \"workflows\", N_(\"An overview of recommended workflows with Git\") },\n-};\n-\n-static void list_common_guides_help(void)\n-{\n-\tint i, longest = 0;\n-\n-\tfor (i = 0; i < ARRAY_SIZE(common_guides); i++) {\n-\t\tif (longest < strlen(common_guides[i].name))\n-\t\t\tlongest = strlen(common_guides[i].name);\n-\t}\n-\n-\tputs(_(\"The common Git guides are:\\n\"));\n-\tfor (i = 0; i < ARRAY_SIZE(common_guides); i++) {\n-\t\tprintf(\"   %s   \", common_guides[i].name);\n-\t\tmput_char(' ', longest - strlen(common_guides[i].name));\n-\t\tputs(_(common_guides[i].help));\n-\t}\n-\tputchar('\\n');\n-}\n-\n static const char *check_git_cmd(const char* cmd)\n {\n \tchar *alias;\ndiff --git a/command-list.txt b/command-list.txt\nindex 3bd23201a6..a57bcb64a1 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -139,3 +139,11 @@ gitweb                                  ancillaryinterrogators\n git-whatchanged                         ancillaryinterrogators\n git-worktree                            mainporcelain\n git-write-tree                          plumbingmanipulators\n+gitattributes                           guide\n+giteveryday                             guide\n+gitglossary                             guide\n+gitignore                               guide\n+gitmodules                              guide\n+gitrevisions                            guide\n+gittutorial                             guide\n+gitworkflows                            guide\ndiff --git a/help.c b/help.c\nindex 1f27d94661..d5a2aff4cb 100644\n--- a/help.c\n+++ b/help.c\n@@ -55,7 +55,9 @@ static void extract_cmds(struct cmdname_help **p_cmds, uint32_t mask)\n \n \t\tcmds[nr] = *cmd;\n \n-\t\tif (skip_prefix(cmd->name, \"git-\", &name))\n+\t\tif (skip_prefix(cmd->name, \"git-\", &name) ||\n+\t\t    (mask == CAT_guide &&\n+\t\t     skip_prefix(cmd->name, \"git\", &name)))\n \t\t\tcmds[nr].name = name;\n \n \t\tnr++;\n@@ -335,6 +337,16 @@ void list_cmds_by_category(const char *cat)\n \t\t\tputs(command_list[i].name);\n }\n \n+void list_common_guides_help(void)\n+{\n+\tstruct category_description catdesc[] = {\n+\t\t{ CAT_guide, N_(\"The common Git guides are:\") },\n+\t\t{ 0, NULL }\n+\t};\n+\tprint_cmd_by_category(catdesc);\n+\tputchar('\\n');\n+}\n+\n void list_all_cmds_help(void)\n {\n \tprint_cmd_by_category(main_categories);\ndiff --git a/help.h b/help.h\nindex 118b7d9947..71b1542896 100644\n--- a/help.h\n+++ b/help.h\n@@ -18,6 +18,7 @@ static inline void mput_char(char c, unsigned int num)\n \n extern void list_common_cmds_help(void);\n extern void list_all_cmds_help(void);\n+extern void list_common_guides_help(void);\n extern void list_all_cmds(void);\n extern void list_cmds_by_category(const char *category);\n extern const char *help_unknown_cmd(const char *cmd);\n-- \n2.17.0.519.gb89679a4aa\n\n"},{"id":"345821","messageId":"20180425163107.10399-6-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-1-pclouds@gmail.com","subject":"[PATCH v4/wip 05/12] git.c: convert --list-*builtins to --list-cmds=*","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-25T16:31:00Z","receivedAt":"2018-04-25T16:32:04Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Even if these are hidden options, let's make them a bit more generic\nsince we're introducing more listing types shortly.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash |  2 +-\n git.c                                  | 12 +++++++-----\n t/t0012-help.sh                        |  2 +-\n 3 files changed, 9 insertions(+), 7 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex a757073945..3556838759 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -3049,7 +3049,7 @@ __git_complete_common () {\n __git_cmds_with_parseopt_helper=\n __git_support_parseopt_helper () {\n \ttest -n \"$__git_cmds_with_parseopt_helper\" ||\n-\t\t__git_cmds_with_parseopt_helper=\"$(__git --list-parseopt-builtins)\"\n+\t\t__git_cmds_with_parseopt_helper=\"$(__git --list-cmds=parseopt)\"\n \n \tcase \" $__git_cmds_with_parseopt_helper \" in\n \t*\" $1 \"*)\ndiff --git a/git.c b/git.c\nindex 3a89893712..28bfa96d87 100644\n--- a/git.c\n+++ b/git.c\n@@ -223,11 +223,13 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t}\n \t\t\t(*argv)++;\n \t\t\t(*argc)--;\n-\t\t} else if (!strcmp(cmd, \"--list-builtins\")) {\n-\t\t\tlist_builtins(0, '\\n');\n-\t\t\texit(0);\n-\t\t} else if (!strcmp(cmd, \"--list-parseopt-builtins\")) {\n-\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n+\t\t} else if (skip_prefix(cmd, \"--list-cmds=\", &cmd)) {\n+\t\t\tif (!strcmp(cmd, \"builtins\"))\n+\t\t\t\tlist_builtins(0, '\\n');\n+\t\t\telse if (!strcmp(cmd, \"parseopt\"))\n+\t\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n+\t\t\telse\n+\t\t\t\tdie(\"unsupported command listing type '%s'\", cmd);\n \t\t\texit(0);\n \t\t} else {\n \t\t\tfprintf(stderr, _(\"unknown option: %s\\n\"), cmd);\ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex 487b92a5de..fd2a7f27dc 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -50,7 +50,7 @@ test_expect_success \"--help does not work for guides\" \"\n \"\n \n test_expect_success 'generate builtin list' '\n-\tgit --list-builtins >builtins\n+\tgit --list-cmds=builtins >builtins\n '\n \n while read builtin\n-- \n2.17.0.519.gb89679a4aa\n\n"},{"id":"345822","messageId":"20180425163107.10399-5-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-1-pclouds@gmail.com","subject":"[PATCH v4/wip 04/12] Remove common-cmds.h","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-25T16:30:59Z","receivedAt":"2018-04-25T16:32:07Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"After the last patch, common-cmds.h is no longer used (and it was\nactually broken). Remove all related code. command-list.h will take\nits place from now on.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n .gitignore          |  1 -\n Makefile            | 17 ++++++-----------\n generate-cmdlist.sh | 46 +++------------------------------------------\n 3 files changed, 9 insertions(+), 55 deletions(-)\n\ndiff --git a/.gitignore b/.gitignore\nindex d4c3914167..0836083992 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -179,7 +179,6 @@\n /gitweb/gitweb.cgi\n /gitweb/static/gitweb.js\n /gitweb/static/gitweb.min.*\n-/common-cmds.h\n /command-list.h\n *.tar.gz\n *.dsc\ndiff --git a/Makefile b/Makefile\nindex 5c58b0b692..a60a78ee67 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -757,7 +757,7 @@ LIB_FILE = libgit.a\n XDIFF_LIB = xdiff/lib.a\n VCSSVN_LIB = vcs-svn/lib.a\n \n-GENERATED_H += common-cmds.h command-list.h\n+GENERATED_H += command-list.h\n \n LIB_H = $(shell $(FIND) . \\\n \t-name .git -prune -o \\\n@@ -1914,9 +1914,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \\\n \t\t$(filter %.o,$^) $(LIBS)\n \n-help.sp help.s help.o: common-cmds.h command-list.h\n+help.sp help.s help.o: command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h command-list.h GIT-PREFIX\n+builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n@@ -1935,11 +1935,6 @@ $(BUILT_INS): git$X\n \tln -s $< $@ 2>/dev/null || \\\n \tcp $< $@\n \n-common-cmds.h: generate-cmdlist.sh command-list.txt\n-\n-common-cmds.h: $(wildcard Documentation/git-*.txt)\n-\t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt COMMON >$@+ && mv $@+ $@\n-\n command-list.h: generate-cmdlist.sh command-list.txt\n \n command-list.h: $(wildcard Documentation/git-*.txt)\n@@ -2153,7 +2148,7 @@ else\n # Dependencies on header files, for platforms that do not support\n # the gcc -MMD option.\n #\n-# Dependencies on automatically generated headers such as common-cmds.h or command-list.h\n+# Dependencies on automatically generated headers such as command-list.h\n # should _not_ be included here, since they are necessary even when\n # building an object for the first time.\n \n@@ -2532,7 +2527,7 @@ sparse: $(SP_OBJ)\n style:\n \tgit clang-format --style file --diff --extensions c,h\n \n-check: common-cmds.h command-list.h\n+check: command-list.h\n \t@if sparse; \\\n \tthen \\\n \t\techo >&2 \"Use 'make sparse' instead\"; \\\n@@ -2780,7 +2775,7 @@ clean: profile-clean coverage-clean\n \t$(RM) $(TEST_PROGRAMS) $(NO_INSTALL)\n \t$(RM) -r bin-wrappers $(dep_dirs)\n \t$(RM) -r po/build/\n-\t$(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h command-list.h $(ETAGS_TARGET) tags cscope*\n+\t$(RM) *.pyc *.pyo */*.pyc */*.pyo command-list.h $(ETAGS_TARGET) tags cscope*\n \t$(RM) -r $(GIT_TARNAME) .doc-tmp-dir\n \t$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz\n \t$(RM) $(htmldocs).tar.gz $(manpages).tar.gz\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 88968160e3..57f9800123 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -70,46 +70,6 @@ struct cmdname_help {\n \tuint32_t category;\n };\n \"\n-if [ -z \"$2\" ]\n-then\n-\tdefine_categories \"$1\"\n-\techo\n-\tprint_command_list \"$1\"\n-\texit 0\n-fi\n-\n-echo \"static const char *common_cmd_groups[] = {\"\n-\n-grps=grps$$.tmp\n-match=match$$.tmp\n-trap \"rm -f '$grps' '$match'\" 0 1 2 3 15\n-\n-sed -n '\n-\t1,/^### common groups/b\n-\t/^### command list/q\n-\t/^#/b\n-\t/^[ \t]*$/b\n-\th;s/^[^ \t][^ \t]*[ \t][ \t]*\\(.*\\)/\tN_(\"\\1\"),/p\n-\tg;s/^\\([^ \t][^ \t]*\\)[ \t].*/\\1/w '$grps'\n-\t' \"$1\"\n-printf '};\\n\\n'\n-\n-n=0\n-substnum=\n-while read grp\n-do\n-\techo \"^git-..*[ \t]$grp\"\n-\tsubstnum=\"$substnum${substnum:+;}s/[ \t]$grp/$n/\"\n-\tn=$(($n+1))\n-done <\"$grps\" >\"$match\"\n-\n-printf 'static struct cmdname_help common_cmds[] = {\\n'\n-grep -f \"$match\" \"$1\" |\n-sed 's/^git-//' |\n-sort |\n-while read cmd tags\n-do\n-\ttag=$(echo \"$tags\" | sed \"$substnum; s/[^0-9]//g\")\n-\techo \"\t{\\\"$cmd\\\", $(get_synopsis git-$cmd), $tag},\"\n-done\n-echo \"};\"\n+define_categories \"$1\"\n+echo\n+print_command_list \"$1\"\n-- \n2.17.0.519.gb89679a4aa\n\n"},{"id":"345823","messageId":"20180425163107.10399-13-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-1-pclouds@gmail.com","subject":"[PATCH v4/wip 12/12] completion: let git provide the completable command list","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-25T16:31:07Z","receivedAt":"2018-04-25T16:32:09Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Instead of maintaining a separate list of command classification,\nwhich often could go out of date, let's centralize the information\nback in git.\n\nNote that the current completion script incorrectly classifies\nfilter-branch as porcelain and t9902 tests this behavior. We keep it\nthis way in t9902 because this test does not really care which\nparticular command is porcelain or plubmbing, they're just names.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash | 119 +++++--------------------\n t/t9902-completion.sh                  |   5 +-\n 2 files changed, 25 insertions(+), 99 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex a5f13ade20..c74d1d7684 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -835,18 +835,30 @@ __git_complete_strategy ()\n }\n \n __git_commands () {\n-\tif test -n \"${GIT_TESTING_COMMAND_COMPLETION:-}\"\n-\tthen\n-\t\tprintf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n-\telse\n-\t\tgit --list-cmds=all\n-\tfi\n+\tcase \"$1\" in\n+\tporcelain)\n+\t\tif test -n \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\"\n+\t\tthen\n+\t\t\tprintf \"%s\" \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\"\n+\t\telse\n+\t\t\tgit --list-cmds=mainporcelain --list-cmds=complete\n+\t\tfi\n+\t\t;;\n+\tall)\n+\t\tif test -n \"$GIT_TESTING_ALL_COMMAND_LIST\"\n+\t\tthen\n+\t\t\tprintf \"%s\" \"$GIT_TESTING_ALL_COMMAND_LIST\";;\n+\t\telse\n+\t\t\tgit --list-cmds=all\n+\t\tfi\n+\t\t;;\n+\tesac\n }\n \n-__git_list_all_commands ()\n+__git_list_commands ()\n {\n \tlocal i IFS=\" \"$'\\n'\n-\tfor i in $(__git_commands)\n+\tfor i in $(__git_commands $1)\n \tdo\n \t\tcase $i in\n \t\t*--*)             : helper pattern;;\n@@ -859,101 +871,14 @@ __git_all_commands=\n __git_compute_all_commands ()\n {\n \ttest -n \"$__git_all_commands\" ||\n-\t__git_all_commands=$(__git_list_all_commands)\n-}\n-\n-__git_list_porcelain_commands ()\n-{\n-\tlocal i IFS=\" \"$'\\n'\n-\t__git_compute_all_commands\n-\tfor i in $__git_all_commands\n-\tdo\n-\t\tcase $i in\n-\t\t*--*)             : helper pattern;;\n-\t\tapplymbox)        : ask gittus;;\n-\t\tapplypatch)       : ask gittus;;\n-\t\tarchimport)       : import;;\n-\t\tcat-file)         : plumbing;;\n-\t\tcheck-attr)       : plumbing;;\n-\t\tcheck-ignore)     : plumbing;;\n-\t\tcheck-mailmap)    : plumbing;;\n-\t\tcheck-ref-format) : plumbing;;\n-\t\tcheckout-index)   : plumbing;;\n-\t\tcolumn)           : internal helper;;\n-\t\tcommit-tree)      : plumbing;;\n-\t\tcount-objects)    : infrequent;;\n-\t\tcredential)       : credentials;;\n-\t\tcredential-*)     : credentials helper;;\n-\t\tcvsexportcommit)  : export;;\n-\t\tcvsimport)        : import;;\n-\t\tcvsserver)        : daemon;;\n-\t\tdaemon)           : daemon;;\n-\t\tdiff-files)       : plumbing;;\n-\t\tdiff-index)       : plumbing;;\n-\t\tdiff-tree)        : plumbing;;\n-\t\tfast-import)      : import;;\n-\t\tfast-export)      : export;;\n-\t\tfsck-objects)     : plumbing;;\n-\t\tfetch-pack)       : plumbing;;\n-\t\tfmt-merge-msg)    : plumbing;;\n-\t\tfor-each-ref)     : plumbing;;\n-\t\thash-object)      : plumbing;;\n-\t\thttp-*)           : transport;;\n-\t\tindex-pack)       : plumbing;;\n-\t\tinit-db)          : deprecated;;\n-\t\tlocal-fetch)      : plumbing;;\n-\t\tls-files)         : plumbing;;\n-\t\tls-remote)        : plumbing;;\n-\t\tls-tree)          : plumbing;;\n-\t\tmailinfo)         : plumbing;;\n-\t\tmailsplit)        : plumbing;;\n-\t\tmerge-*)          : plumbing;;\n-\t\tmktree)           : plumbing;;\n-\t\tmktag)            : plumbing;;\n-\t\tpack-objects)     : plumbing;;\n-\t\tpack-redundant)   : plumbing;;\n-\t\tpack-refs)        : plumbing;;\n-\t\tparse-remote)     : plumbing;;\n-\t\tpatch-id)         : plumbing;;\n-\t\tprune)            : plumbing;;\n-\t\tprune-packed)     : plumbing;;\n-\t\tquiltimport)      : import;;\n-\t\tread-tree)        : plumbing;;\n-\t\treceive-pack)     : plumbing;;\n-\t\tremote-*)         : transport;;\n-\t\trerere)           : plumbing;;\n-\t\trev-list)         : plumbing;;\n-\t\trev-parse)        : plumbing;;\n-\t\trunstatus)        : plumbing;;\n-\t\tsh-setup)         : internal;;\n-\t\tshell)            : daemon;;\n-\t\tshow-ref)         : plumbing;;\n-\t\tsend-pack)        : plumbing;;\n-\t\tshow-index)       : plumbing;;\n-\t\tssh-*)            : transport;;\n-\t\tstripspace)       : plumbing;;\n-\t\tsymbolic-ref)     : plumbing;;\n-\t\tunpack-file)      : plumbing;;\n-\t\tunpack-objects)   : plumbing;;\n-\t\tupdate-index)     : plumbing;;\n-\t\tupdate-ref)       : plumbing;;\n-\t\tupdate-server-info) : daemon;;\n-\t\tupload-archive)   : plumbing;;\n-\t\tupload-pack)      : plumbing;;\n-\t\twrite-tree)       : plumbing;;\n-\t\tvar)              : infrequent;;\n-\t\tverify-pack)      : infrequent;;\n-\t\tverify-tag)       : plumbing;;\n-\t\t*) echo $i;;\n-\t\tesac\n-\tdone\n+\t__git_all_commands=$(__git_list_commands all)\n }\n \n __git_porcelain_commands=\n __git_compute_porcelain_commands ()\n {\n \ttest -n \"$__git_porcelain_commands\" ||\n-\t__git_porcelain_commands=$(__git_list_porcelain_commands)\n+\t__git_porcelain_commands=$(__git_list_commands porcelain)\n }\n \n # Lists all set config variables starting with the given section prefix,\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 1b34caa1e1..2f16679380 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -13,7 +13,7 @@ complete ()\n \treturn 0\n }\n \n-# Be careful when updating this list:\n+# Be careful when updating these lists:\n #\n # (1) The build tree may have build artifact from different branch, or\n #     the user's $PATH may have a random executable that may begin\n@@ -30,7 +30,8 @@ complete ()\n #     completion for \"git <TAB>\", and a plumbing is excluded.  \"add\",\n #     \"filter-branch\" and \"ls-files\" are listed for this.\n \n-GIT_TESTING_COMMAND_COMPLETION='add checkout check-attr filter-branch ls-files'\n+GIT_TESTING_ALL_COMMAND_LIST='add checkout check-attr filter-branch ls-files'\n+GIT_TESTING_PORCELAIN_COMMAND_LIST='add checkout filter-branch'\n \n . \"$GIT_BUILD_DIR/contrib/completion/git-completion.bash\"\n \n-- \n2.17.0.519.gb89679a4aa\n\n"},{"id":"345827","messageId":"CAPig+cTQrbHq9bgge5Ftj+Fi8kMkuL2VtQzs7McuqU-ueVK4vw@mail.gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-2-pclouds@gmail.com","subject":"Re: [PATCH v4/wip 01/12] generate-cmds.sh: factor out synopsis extract code","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-25T17:59:06Z","receivedAt":"2018-04-25T17:59:10Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Apr 25, 2018 at 12:30 PM, Nguyễn Thái Ngọc Duy\n<pclouds@gmail.com> wrote:\n> This makes it easier to reuse the same code in another place (very\n> soon).\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\n> @@ -1,5 +1,17 @@\n> +get_synopsis () {\n> +       local cmd=\"$1\"\n\n'local' is a Bash-ism, isn't it?\n\n> +       sed -n '\n> +               /^NAME/,/'\"$cmd\"'/H\n> +               ${\n> +                       x\n> +                       s/.*'\"$cmd\"' - \\(.*\\)/N_(\"\\1\")/\n> +                       p\n> +               }' \"Documentation/$cmd.txt\"\n> +}\n> +\n>  echo \"/* Automatically generated by generate-cmdlist.sh */\n>  struct cmdname_help {\n>         char name[16];\n> @@ -39,12 +51,6 @@ sort |\n>  while read cmd tags\n>  do\n>         tag=$(echo \"$tags\" | sed \"$substnum; s/[^0-9]//g\")\n> -       sed -n '\n> -               /^NAME/,/git-'\"$cmd\"'/H\n> -               ${\n> -                       x\n> -                       s/.*git-'\"$cmd\"' - \\(.*\\)/      {\"'\"$cmd\"'\", N_(\"\\1\"), '$tag'},/\n> -                       p\n> -               }' \"Documentation/git-$cmd.txt\"\n> +       echo \"  {\\\"$cmd\\\", $(get_synopsis git-$cmd), $tag},\"\n>  done\n>  echo \"};\"\n"},{"id":"345828","messageId":"CAPig+cQ-ZfvHD6B-mK6tOBMdKiVzwz15M4rsOdBMBcgu0OmuxA@mail.gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-3-pclouds@gmail.com","subject":"Re: [PATCH v4/wip 02/12] generate-cmds.sh: export all commands to command-list.h","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-25T18:07:03Z","receivedAt":"2018-04-25T18:07:12Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Apr 25, 2018 at 12:30 PM, Nguyễn Thái Ngọc Duy\n<pclouds@gmail.com> wrote:\n> The current generate-cmds.sh generates just enough to print \"git help\"\n> output. That is, it only extracts help text for common commands.\n>\n> The script is now updated to extract help text for all commands and\n> keep command classification a new file, command-list.h. This will be\n> useful later:\n> [...]\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\n> @@ -12,14 +34,51 @@ get_synopsis () {\n> +define_categories() {\n> +       echo\n> +       echo \"/* Command categories */\"\n> +       bit=0\n> +       category_list \"$1\" |\n> +       while read cat\n> +       do\n> +               echo \"#define CAT_$cat (1UL << $bit)\"\n> +               bit=$(($bit+1))\n> +       done\n> +       test \"$bit\" -gt 32 && die \"Urgh.. too many categories?\"\n\nShould this be '-ge' rather than '-gt'?\n\n> +}\n"},{"id":"345829","messageId":"CAM0VKjkbqmWRhuBQEg6+7AKE4YWX3gONCsyf2wnJuLSho2D+ow@mail.gmail.com","threadId":"48155","inReplyTo":"CAPig+cTQrbHq9bgge5Ftj+Fi8kMkuL2VtQzs7McuqU-ueVK4vw@mail.gmail.com","subject":"Re: [PATCH v4/wip 01/12] generate-cmds.sh: factor out synopsis extract code","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-04-25T18:13:04Z","receivedAt":"2018-04-25T18:16:03Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Wed, Apr 25, 2018 at 7:59 PM Eric Sunshine <sunshine@sunshineco.com>\nwrote:\n\n> On Wed, Apr 25, 2018 at 12:30 PM, Nguyễn Thái Ngọc Duy\n> <pclouds@gmail.com> wrote:\n> > This makes it easier to reuse the same code in another place (very\n> > soon).\n> >\n> > Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> > ---\n> > diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\n> > @@ -1,5 +1,17 @@\n> > +get_synopsis () {\n> > +       local cmd=\"$1\"\n\n> 'local' is a Bash-ism, isn't it?\n\nWell, strictly speaking it isn't, because many shells support it\nbesides Bash.\n\nI don't remember seeing any complaints about 01d3a526ad (t0000: check\nwhether the shell supports the \"local\" keyword, 2017-10-26), but we\nonly have that commit for a couple or months / two releases, so it's\nstill too early to start using 'local' in build scripts.\n"},{"id":"345830","messageId":"CAPig+cT2FJodBeVO8RO9CqSAFvmcMQbEwyTEsxPBYovA6ivXGQ@mail.gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-9-pclouds@gmail.com","subject":"Re: [PATCH v4/wip 08/12] git: support --list-cmds=<category>","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-25T18:16:04Z","receivedAt":"2018-04-25T18:16:11Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Apr 25, 2018 at 12:31 PM, Nguyễn Thái Ngọc Duy\n<pclouds@gmail.com> wrote:\n> This allows us to select any group of commands by a category defined\n> in command-list.txt. This is an internal/hidden option so we don't\n> have to be picky about the category name or worried about exposing too\n> much.\n>\n> This will be used later by git-completion.bash to retrieve certain\n> command groups.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/help.c b/help.c\n> @@ -305,6 +305,25 @@ void list_all_cmds(void)\n> +void list_cmds_by_category(const char *cat)\n> +{\n> +       int i;\n> +       int cat_id = 0;\n\nShould 'cat_id' be unsigned...\n\n> +\n> +       for (i = 0; category_names[i]; i++) {\n> +               if (!strcmp(cat, category_names[i])) {\n> +                       cat_id = 1 << i;\n\n...since you're shifting it here?\n\n> +                       break;\n> +               }\n> +       }\n> +       if (!cat_id)\n> +               die(\"unsupported command listing type '%s'\", cat);\n> +\n> +       for (i = 0; command_list[i].name; i++)\n> +               if (command_list[i].category & cat_id)\n> +                       puts(command_list[i].name);\n> +}\n"},{"id":"345837","messageId":"CAPig+cQEOxFz-0UAKHFYSzVqnxKdgVAmvV3FoJ8fT2SnWvRwLg@mail.gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-11-pclouds@gmail.com","subject":"Re: [PATCH v4/wip 10/12] help: use command-list.txt for the source of guides","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-25T18:22:10Z","receivedAt":"2018-04-25T18:22:31Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Apr 25, 2018 at 12:31 PM, Nguyễn Thái Ngọc Duy\n<pclouds@gmail.com> wrote:\n> The help command currently hard codes the list of guides and their\n> summary in C. Let's move this list to command-list.txt. This lets us\n> extract summary lines from Documentation/git*.txt. This also\n> potentially lets us lists guides in git.txt, but I'll leave that for\n\ns/lists/list/\n\n> now.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n"},{"id":"345842","messageId":"CAPig+cQCy_ZSUit83YcVBSCzpvXAX1kNWjpG0nh+76ESXRD8Mg@mail.gmail.com","threadId":"48155","inReplyTo":"20180425163107.10399-7-pclouds@gmail.com","subject":"Re: [PATCH v4/wip 06/12] git: accept multiple --list-cmds options","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-25T18:12:43Z","receivedAt":"2018-04-25T18:24:53Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Apr 25, 2018 at 12:31 PM, Nguyễn Thái Ngọc Duy\n<pclouds@gmail.com> wrote:\n> Later on we may support non-overlapping command groups to\n> --list-cmds. Allow the user to execute just one \"git\" process and get\n> multiple groups. This may matter for git-completion.bash on Windows\n> because we don't want the user to way for long when TAB-ing and\n\ns/way/wait/\n\n> Windows is slow on launching new processes.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n"},{"id":"346078","messageId":"CACsJy8AzAFVhQw-K_juFg2iF0tVHo0_fF-CRYwMR=xPcTUC-8Q@mail.gmail.com","threadId":"48155","inReplyTo":"CAPig+cQ-ZfvHD6B-mK6tOBMdKiVzwz15M4rsOdBMBcgu0OmuxA@mail.gmail.com","subject":"Re: [PATCH v4/wip 02/12] generate-cmds.sh: export all commands to command-list.h","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-29T16:11:56Z","receivedAt":"2018-04-29T16:12:31Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Apr 25, 2018 at 8:07 PM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Wed, Apr 25, 2018 at 12:30 PM, Nguyễn Thái Ngọc Duy\n> <pclouds@gmail.com> wrote:\n>> The current generate-cmds.sh generates just enough to print \"git help\"\n>> output. That is, it only extracts help text for common commands.\n>>\n>> The script is now updated to extract help text for all commands and\n>> keep command classification a new file, command-list.h. This will be\n>> useful later:\n>> [...]\n>> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n>> ---\n>> diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\n>> @@ -12,14 +34,51 @@ get_synopsis () {\n>> +define_categories() {\n>> +       echo\n>> +       echo \"/* Command categories */\"\n>> +       bit=0\n>> +       category_list \"$1\" |\n>> +       while read cat\n>> +       do\n>> +               echo \"#define CAT_$cat (1UL << $bit)\"\n>> +               bit=$(($bit+1))\n>> +       done\n>> +       test \"$bit\" -gt 32 && die \"Urgh.. too many categories?\"\n>\n> Should this be '-ge' rather than '-gt'?\n\nAfter we print \"1UL << 31\" we increment it to 32 and exit the loop,\nthen it's still within limits, -ge would incorrectly complain\n-- \nDuy\n"},{"id":"346082","messageId":"20180429181844.21325-1-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180421165414.30051-1-pclouds@gmail.com","subject":"[PATCH v5 00/10] Keep all info in command-list.txt in git binary","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-29T18:18:34Z","receivedAt":"2018-04-29T18:19:06Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"I think v5 is getting close to what I wanted to achieve from the RFC\nversion (I skip v4 since I sent out v4/wip and another v4 may confuse\npeople).\n\nInterdiff is too large to be helpful, but the summary of changes\ncompared to v3 is:\n\n- common-cmds.h is renamed to command-list.h\n- the common group description is moved from command-list.txt to\n  help.c to simplify command-list.txt format\n- generate-cmds.sh supports multiple categories per command, a new one\n  \"complete\" is added to aid git-completion.bash\n- multiple --list-cmds options is replaced with\n  --list-cmds=<type>[,<type>...]. This allows easier group\n  customization in git-completion.bash (not happens yet)\n- __git_list_all_commands() and __git_list_porcelain_commands() for\n  backward compatibility\n- \"git help <tab>\" completion also makes use of guide list in\n  command-list.txt\n- better tests from Ramsay\n\nThere is one sticky point yet about the guides. I'll pull Phillip in\nand explain more in the relevant patch.\n\nNguyễn Thái Ngọc Duy (10):\n  generate-cmds.sh: factor out synopsis extract code\n  generate-cmds.sh: export all commands to command-list.h\n  help: use command-list.h for common command list\n  Remove common-cmds.h\n  git.c: convert --list-*builtins to --list-cmds=*\n  completion: implement and use --list-cmds=main,others\n  git: support --list-cmds=list-<category>\n  help: add \"-a --verbose\" to list all commands with synopsis\n  help: use command-list.txt for the source of guides\n  completion: let git provide the completable command list\n\n .gitignore                             |   2 +-\n Documentation/git-help.txt             |   4 +-\n Documentation/gitattributes.txt        |   2 +-\n Documentation/gitmodules.txt           |   2 +-\n Documentation/gitrevisions.txt         |   2 +-\n Makefile                               |  16 +-\n builtin/help.c                         |  39 +----\n command-list.txt                       |  67 ++++----\n contrib/completion/git-completion.bash | 134 +++++-----------\n generate-cmdlist.sh                    | 126 ++++++++++-----\n git.c                                  |  38 ++++-\n help.c                                 | 209 +++++++++++++++++++++----\n help.h                                 |   5 +\n t/t0012-help.sh                        |  26 ++-\n t/t9902-completion.sh                  |   5 +-\n 15 files changed, 426 insertions(+), 251 deletions(-)\n\n-- \n2.17.0.664.g8924eee37a\n\n"},{"id":"346083","messageId":"20180429181844.21325-2-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180429181844.21325-1-pclouds@gmail.com","subject":"[PATCH v5 01/10] generate-cmds.sh: factor out synopsis extract code","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-29T18:18:35Z","receivedAt":"2018-04-29T18:19:11Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This makes it easier to reuse the same code in another place (very\nsoon).\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n generate-cmdlist.sh | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex eeea4b67ea..31b6d886cb 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -1,5 +1,15 @@\n #!/bin/sh\n \n+get_synopsis () {\n+\tsed -n '\n+\t\t/^NAME/,/'\"$1\"'/H\n+\t\t${\n+\t\t\tx\n+\t\t\ts/.*'\"$1\"' - \\(.*\\)/N_(\"\\1\")/\n+\t\t\tp\n+\t\t}' \"Documentation/$1.txt\"\n+}\n+\n echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n \tchar name[16];\n@@ -39,12 +49,6 @@ sort |\n while read cmd tags\n do\n \ttag=$(echo \"$tags\" | sed \"$substnum; s/[^0-9]//g\")\n-\tsed -n '\n-\t\t/^NAME/,/git-'\"$cmd\"'/H\n-\t\t${\n-\t\t\tx\n-\t\t\ts/.*git-'\"$cmd\"' - \\(.*\\)/\t{\"'\"$cmd\"'\", N_(\"\\1\"), '$tag'},/\n-\t\t\tp\n-\t\t}' \"Documentation/git-$cmd.txt\"\n+\techo \"\t{\\\"$cmd\\\", $(get_synopsis git-$cmd), $tag},\"\n done\n echo \"};\"\n-- \n2.17.0.664.g8924eee37a\n\n"},{"id":"346084","messageId":"20180429181844.21325-3-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180429181844.21325-1-pclouds@gmail.com","subject":"[PATCH v5 02/10] generate-cmds.sh: export all commands to command-list.h","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-29T18:18:36Z","receivedAt":"2018-04-29T18:19:12Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The current generate-cmds.sh generates just enough to print \"git help\"\noutput. That is, it only extracts help text for common commands.\n\nThe script is now updated to extract help text for all commands and\nkeep command classification a new file, command-list.h. This will be\nuseful later:\n\n- \"git help -a\" could print a short summary of all commands instead of\n  just the common ones.\n\n- \"git\" could produce a list of commands of one or more category. One\n  of its use is to reduce another command classification embedded in\n  git-completion.bash.\n\nThe new file can be generated but is not used anywhere yet. The plan\nis we migrate away from common-cmds.h. Then we can kill off\ncommon-cmds.h build rules and generation code (and also delete\nduplicate content in command-list.h which we keep for now to not mess\ngenerate-cmds.sh up too much).\n\nPS. The new fixed column requirement on command-list.txt is\ntechnically not needed. But it helps simplify the code a bit at this\nstage. We could lift this restriction later if we want to.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n .gitignore          |  1 +\n Makefile            | 13 ++++++---\n command-list.txt    |  4 +--\n generate-cmdlist.sh | 67 ++++++++++++++++++++++++++++++++++++++++++---\n 4 files changed, 75 insertions(+), 10 deletions(-)\n\ndiff --git a/.gitignore b/.gitignore\nindex 833ef3b0b7..d4c3914167 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -180,6 +180,7 @@\n /gitweb/static/gitweb.js\n /gitweb/static/gitweb.min.*\n /common-cmds.h\n+/command-list.h\n *.tar.gz\n *.dsc\n *.deb\ndiff --git a/Makefile b/Makefile\nindex 50da82b016..bb29470f88 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -757,7 +757,7 @@ LIB_FILE = libgit.a\n XDIFF_LIB = xdiff/lib.a\n VCSSVN_LIB = vcs-svn/lib.a\n \n-GENERATED_H += common-cmds.h\n+GENERATED_H += common-cmds.h command-list.h\n \n LIB_H = $(shell $(FIND) . \\\n \t-name .git -prune -o \\\n@@ -1940,6 +1940,11 @@ $(BUILT_INS): git$X\n common-cmds.h: generate-cmdlist.sh command-list.txt\n \n common-cmds.h: $(wildcard Documentation/git-*.txt)\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt COMMON >$@+ && mv $@+ $@\n+\n+command-list.h: generate-cmdlist.sh command-list.txt\n+\n+command-list.h: $(wildcard Documentation/git-*.txt)\n \t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt >$@+ && mv $@+ $@\n \n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n@@ -2150,7 +2155,7 @@ else\n # Dependencies on header files, for platforms that do not support\n # the gcc -MMD option.\n #\n-# Dependencies on automatically generated headers such as common-cmds.h\n+# Dependencies on automatically generated headers such as common-cmds.h or command-list.h\n # should _not_ be included here, since they are necessary even when\n # building an object for the first time.\n \n@@ -2529,7 +2534,7 @@ sparse: $(SP_OBJ)\n style:\n \tgit clang-format --style file --diff --extensions c,h\n \n-check: common-cmds.h\n+check: common-cmds.h command-list.h\n \t@if sparse; \\\n \tthen \\\n \t\techo >&2 \"Use 'make sparse' instead\"; \\\n@@ -2777,7 +2782,7 @@ clean: profile-clean coverage-clean\n \t$(RM) $(TEST_PROGRAMS) $(NO_INSTALL)\n \t$(RM) -r bin-wrappers $(dep_dirs)\n \t$(RM) -r po/build/\n-\t$(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h $(ETAGS_TARGET) tags cscope*\n+\t$(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h command-list.h $(ETAGS_TARGET) tags cscope*\n \t$(RM) -r $(GIT_TARNAME) .doc-tmp-dir\n \t$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz\n \t$(RM) $(htmldocs).tar.gz $(manpages).tar.gz\ndiff --git a/command-list.txt b/command-list.txt\nindex a1fad28fd8..786536aba0 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -8,8 +8,8 @@ info         examine the history and state (see also: git help revisions)\n history      grow, mark and tweak your common history\n remote       collaborate (see also: git help workflows)\n \n-### command list (do not change this line)\n-# command name                          category [deprecated] [common]\n+### command list (do not change this line, also do not change alignment)\n+# command name                          category [category] [category]\n git-add                                 mainporcelain           worktree\n git-am                                  mainporcelain\n git-annotate                            ancillaryinterrogators\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 31b6d886cb..c9fd524760 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -1,5 +1,27 @@\n #!/bin/sh\n \n+die () {\n+\techo \"$@\" >&2\n+\texit 1\n+}\n+\n+command_list () {\n+\tsed '1,/^### command list/d;/^#/d' \"$1\"\n+}\n+\n+get_categories() {\n+\ttr ' ' '\\n'|\n+\tgrep -v '^$' |\n+\tsort |\n+\tuniq\n+}\n+\n+category_list () {\n+\tcommand_list \"$1\" |\n+\tcut -c 40- |\n+\tget_categories\n+}\n+\n get_synopsis () {\n \tsed -n '\n \t\t/^NAME/,/'\"$1\"'/H\n@@ -10,14 +32,51 @@ get_synopsis () {\n \t\t}' \"Documentation/$1.txt\"\n }\n \n+define_categories() {\n+\techo\n+\techo \"/* Command categories */\"\n+\tbit=0\n+\tcategory_list \"$1\" |\n+\twhile read cat\n+\tdo\n+\t\techo \"#define CAT_$cat (1UL << $bit)\"\n+\t\tbit=$(($bit+1))\n+\tdone\n+\ttest \"$bit\" -gt 32 && die \"Urgh.. too many categories?\"\n+}\n+\n+print_command_list() {\n+\techo \"static struct cmdname_help command_list[] = {\"\n+\n+\tcommand_list \"$1\" |\n+\twhile read cmd rest\n+\tdo\n+\t\tprintf \"\t{ \\\"$cmd\\\", $(get_synopsis $cmd), 0\"\n+\t\tfor cat in $(echo \"$rest\" | get_categories)\n+\t\tdo\n+\t\t\tprintf \" | CAT_$cat\"\n+\t\tdone\n+\t\techo \" },\"\n+\tdone\n+\techo \"};\"\n+}\n+\n echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n-\tchar name[16];\n-\tchar help[80];\n-\tunsigned char group;\n+\tconst char *name;\n+\tconst char *help;\n+\tuint32_t group;\n };\n+\"\n+if [ -z \"$2\" ]\n+then\n+\tdefine_categories \"$1\"\n+\techo\n+\tprint_command_list \"$1\"\n+\texit 0\n+fi\n \n-static const char *common_cmd_groups[] = {\"\n+echo \"static const char *common_cmd_groups[] = {\"\n \n grps=grps$$.tmp\n match=match$$.tmp\n-- \n2.17.0.664.g8924eee37a\n\n"},{"id":"346085","messageId":"20180429181844.21325-4-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180429181844.21325-1-pclouds@gmail.com","subject":"[PATCH v5 03/10] help: use command-list.h for common command list","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-29T18:18:37Z","receivedAt":"2018-04-29T18:19:14Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The previous commit added code generation for all_cmd_desc[] which\nincludes almost everything we need to generate common command list.\nConvert help code to use that array instead and drop common_cmds[] array.\n\nThe description of each common command group is removed from\ncommand-list.txt. This keeps this file format simpler. common-cmds.h\nwill not be generated correctly after this change due to the\ncommand-list.txt format change. But it does not matter and\ncommon-cmds.h will be removed.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Makefile            |   4 +-\n command-list.txt    |  10 ---\n generate-cmdlist.sh |   4 +-\n help.c              | 145 +++++++++++++++++++++++++++++++++-----------\n t/t0012-help.sh     |   9 +++\n 5 files changed, 122 insertions(+), 50 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex bb29470f88..ab67150e68 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1916,9 +1916,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \\\n \t\t$(filter %.o,$^) $(LIBS)\n \n-help.sp help.s help.o: common-cmds.h\n+help.sp help.s help.o: common-cmds.h command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h GIT-PREFIX\n+builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h command-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\ndiff --git a/command-list.txt b/command-list.txt\nindex 786536aba0..3bd23201a6 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -1,13 +1,3 @@\n-# common commands are grouped by themes\n-# these groups are output by 'git help' in the order declared here.\n-# map each common command in the command list to one of these groups.\n-### common groups (do not change this line)\n-init         start a working area (see also: git help tutorial)\n-worktree     work on the current change (see also: git help everyday)\n-info         examine the history and state (see also: git help revisions)\n-history      grow, mark and tweak your common history\n-remote       collaborate (see also: git help workflows)\n-\n ### command list (do not change this line, also do not change alignment)\n # command name                          category [category] [category]\n git-add                                 mainporcelain           worktree\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex c9fd524760..93de8e8f59 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -6,7 +6,7 @@ die () {\n }\n \n command_list () {\n-\tsed '1,/^### command list/d;/^#/d' \"$1\"\n+\tgrep -v '^#' \"$1\"\n }\n \n get_categories() {\n@@ -65,7 +65,7 @@ echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n \tconst char *name;\n \tconst char *help;\n-\tuint32_t group;\n+\tuint32_t category;\n };\n \"\n if [ -z \"$2\" ]\ndiff --git a/help.c b/help.c\nindex a4feef2ffe..bf2738e9ef 100644\n--- a/help.c\n+++ b/help.c\n@@ -5,13 +5,114 @@\n #include \"run-command.h\"\n #include \"levenshtein.h\"\n #include \"help.h\"\n-#include \"common-cmds.h\"\n+#include \"command-list.h\"\n #include \"string-list.h\"\n #include \"column.h\"\n #include \"version.h\"\n #include \"refs.h\"\n #include \"parse-options.h\"\n \n+struct category_description {\n+\tuint32_t category;\n+\tconst char *desc;\n+};\n+static uint32_t common_mask =\n+\tCAT_init | CAT_worktree | CAT_info |\n+\tCAT_history | CAT_remote;\n+static struct category_description common_categories[] = {\n+\t{ CAT_init, N_(\"start a working area (see also: git help tutorial)\") },\n+\t{ CAT_worktree, N_(\"work on the current change (see also: git help everyday)\") },\n+\t{ CAT_info, N_(\"examine the history and state (see also: git help revisions)\") },\n+\t{ CAT_history, N_(\"grow, mark and tweak your common history\") },\n+\t{ CAT_remote, N_(\"collaborate (see also: git help workflows)\") },\n+\t{ 0, NULL }\n+};\n+\n+static const char *drop_prefix(const char *name)\n+{\n+\tconst char *new_name;\n+\n+\tif (skip_prefix(name, \"git-\", &new_name))\n+\t\treturn new_name;\n+\treturn name;\n+\n+}\n+\n+static void extract_cmds(struct cmdname_help **p_cmds, uint32_t mask)\n+{\n+\tint i, nr = 0;\n+\tstruct cmdname_help *cmds;\n+\n+\tif (ARRAY_SIZE(command_list) == 0)\n+\t\tBUG(\"empty command_list[] is a sign of broken generate-cmdlist.sh\");\n+\n+\tALLOC_ARRAY(cmds, ARRAY_SIZE(command_list) + 1);\n+\n+\tfor (i = 0; i < ARRAY_SIZE(command_list); i++) {\n+\t\tconst struct cmdname_help *cmd = command_list + i;\n+\n+\t\tif (!(cmd->category & mask))\n+\t\t\tcontinue;\n+\n+\t\tcmds[nr] = *cmd;\n+\t\tcmds[nr].name = drop_prefix(cmd->name);\n+\n+\t\tnr++;\n+\t}\n+\tcmds[nr].name = NULL;\n+\t*p_cmds = cmds;\n+}\n+\n+static void print_command_list(const struct cmdname_help *cmds,\n+\t\t\t       uint32_t mask, int longest)\n+{\n+\tint i;\n+\n+\tfor (i = 0; cmds[i].name; i++) {\n+\t\tif (cmds[i].category & mask) {\n+\t\t\tprintf(\"   %s   \", cmds[i].name);\n+\t\t\tmput_char(' ', longest - strlen(cmds[i].name));\n+\t\t\tputs(_(cmds[i].help));\n+\t\t}\n+\t}\n+}\n+\n+static int cmd_name_cmp(const void *elem1, const void *elem2)\n+{\n+\tconst struct cmdname_help *e1 = elem1;\n+\tconst struct cmdname_help *e2 = elem2;\n+\n+\treturn strcmp(e1->name, e2->name);\n+}\n+\n+static void print_cmd_by_category(const struct category_description *catdesc)\n+{\n+\tstruct cmdname_help *cmds;\n+\tint longest = 0;\n+\tint i, nr = 0;\n+\tuint32_t mask = 0;\n+\n+\tfor (i = 0; catdesc[i].desc; i++)\n+\t\tmask |= catdesc[i].category;\n+\n+\textract_cmds(&cmds, mask);\n+\n+\tfor (i = 0; cmds[i].name; i++, nr++) {\n+\t\tif (longest < strlen(cmds[i].name))\n+\t\t\tlongest = strlen(cmds[i].name);\n+\t}\n+\tQSORT(cmds, nr, cmd_name_cmp);\n+\n+\tfor (i = 0; catdesc[i].desc; i++) {\n+\t\tuint32_t mask = catdesc[i].category;\n+\t\tconst char *desc = catdesc[i].desc;\n+\n+\t\tprintf(\"\\n%s\\n\", _(desc));\n+\t\tprint_command_list(cmds, mask, longest);\n+\t}\n+\tfree(cmds);\n+}\n+\n void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n {\n \tstruct cmdname *ent;\n@@ -190,42 +291,10 @@ void list_commands(unsigned int colopts,\n \t}\n }\n \n-static int cmd_group_cmp(const void *elem1, const void *elem2)\n-{\n-\tconst struct cmdname_help *e1 = elem1;\n-\tconst struct cmdname_help *e2 = elem2;\n-\n-\tif (e1->group < e2->group)\n-\t\treturn -1;\n-\tif (e1->group > e2->group)\n-\t\treturn 1;\n-\treturn strcmp(e1->name, e2->name);\n-}\n-\n void list_common_cmds_help(void)\n {\n-\tint i, longest = 0;\n-\tint current_grp = -1;\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-\tQSORT(common_cmds, ARRAY_SIZE(common_cmds), cmd_group_cmp);\n-\n \tputs(_(\"These are common Git commands used in various situations:\"));\n-\n-\tfor (i = 0; i < ARRAY_SIZE(common_cmds); i++) {\n-\t\tif (common_cmds[i].group != current_grp) {\n-\t\t\tprintf(\"\\n%s\\n\", _(common_cmd_groups[common_cmds[i].group]));\n-\t\t\tcurrent_grp = common_cmds[i].group;\n-\t\t}\n-\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+\tprint_cmd_by_category(common_categories);\n }\n \n int is_in_cmdlist(struct cmdnames *c, const char *s)\n@@ -285,6 +354,7 @@ const char *help_unknown_cmd(const char *cmd)\n {\n \tint i, n, best_similarity = 0;\n \tstruct cmdnames main_cmds, other_cmds;\n+\tstruct cmdname_help *common_cmds;\n \n \tmemset(&main_cmds, 0, sizeof(main_cmds));\n \tmemset(&other_cmds, 0, sizeof(other_cmds));\n@@ -299,6 +369,8 @@ const char *help_unknown_cmd(const char *cmd)\n \tQSORT(main_cmds.names, main_cmds.cnt, cmdname_compare);\n \tuniq(&main_cmds);\n \n+\textract_cmds(&common_cmds, common_mask);\n+\n \t/* This abuses cmdname->len for levenshtein distance */\n \tfor (i = 0, n = 0; i < main_cmds.cnt; i++) {\n \t\tint cmp = 0; /* avoid compiler stupidity */\n@@ -313,10 +385,10 @@ const char *help_unknown_cmd(const char *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\twhile (common_cmds[n].name &&\n \t\t       (cmp = strcmp(common_cmds[n].name, candidate)) < 0)\n \t\t\tn++;\n-\t\tif ((n < ARRAY_SIZE(common_cmds)) && !cmp) {\n+\t\tif (common_cmds[n].name && !cmp) {\n \t\t\t/* Yes, this is one of the common commands */\n \t\t\tn++; /* use the entry from common_cmds[] */\n \t\t\tif (starts_with(candidate, cmd)) {\n@@ -329,6 +401,7 @@ const char *help_unknown_cmd(const char *cmd)\n \t\tmain_cmds.names[i]->len =\n \t\t\tlevenshtein(cmd, candidate, 0, 2, 1, 3) + 1;\n \t}\n+\tFREE_AND_NULL(common_cmds);\n \n \tQSORT(main_cmds.names, main_cmds.cnt, levenshtein_compare);\n \ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex 487b92a5de..c096f33505 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -49,6 +49,15 @@ test_expect_success \"--help does not work for guides\" \"\n \ttest_i18ncmp expect actual\n \"\n \n+test_expect_success 'git help' '\n+\tgit help >help.output &&\n+\ttest_i18ngrep \"^   clone  \" help.output &&\n+\ttest_i18ngrep \"^   add    \" help.output &&\n+\ttest_i18ngrep \"^   log    \" help.output &&\n+\ttest_i18ngrep \"^   commit \" help.output &&\n+\ttest_i18ngrep \"^   fetch  \" help.output\n+'\n+\n test_expect_success 'generate builtin list' '\n \tgit --list-builtins >builtins\n '\n-- \n2.17.0.664.g8924eee37a\n\n"},{"id":"346086","messageId":"20180429181844.21325-7-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180429181844.21325-1-pclouds@gmail.com","subject":"[PATCH v5 06/10] completion: implement and use --list-cmds=main,others","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-29T18:18:40Z","receivedAt":"2018-04-29T18:19:18Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Instead of parsing \"git help -a\" output, which is tricky to get right,\nless elegant and also slow, make git provide the list in a\nmachine-friendly form. This adds two separate listing types, main and\nothers, instead of just \"all\" for more flexibility.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash |  2 +-\n git.c                                  |  4 ++++\n help.c                                 | 32 ++++++++++++++++++++++++++\n help.h                                 |  2 ++\n 4 files changed, 39 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex d7b448fd94..77cfb8a20b 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -834,7 +834,7 @@ __git_commands () {\n \tthen\n \t\tprintf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n \telse\n-\t\tgit help -a|egrep '^  [a-zA-Z0-9]'\n+\t\tgit --list-cmds=main,others\n \tfi\n }\n \ndiff --git a/git.c b/git.c\nindex ea9bbfb6a3..da161a74ae 100644\n--- a/git.c\n+++ b/git.c\n@@ -48,6 +48,10 @@ static int list_cmds(const char *spec)\n \t\t\tlist_builtins(0, '\\n');\n \t\telse if (len == 8 && !strncmp(spec, \"parseopt\", 8))\n \t\t\tlist_builtins(NO_PARSEOPT, ' ');\n+\t\telse if (len == 4 && !strncmp(spec, \"main\", 4))\n+\t\t\tlist_all_main_cmds();\n+\t\telse if (len == 6 && !strncmp(spec, \"others\", 6))\n+\t\t\tlist_all_other_cmds();\n \t\telse\n \t\t\tdie(_(\"unsupported command listing type '%s'\"), spec);\n \t\tspec += len;\ndiff --git a/help.c b/help.c\nindex bf2738e9ef..71bc001570 100644\n--- a/help.c\n+++ b/help.c\n@@ -297,6 +297,38 @@ void list_common_cmds_help(void)\n \tprint_cmd_by_category(common_categories);\n }\n \n+void list_all_main_cmds(void)\n+{\n+\tstruct cmdnames main_cmds, other_cmds;\n+\tint i;\n+\n+\tmemset(&main_cmds, 0, sizeof(main_cmds));\n+\tmemset(&other_cmds, 0, sizeof(other_cmds));\n+\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n+\n+\tfor (i = 0; i < main_cmds.cnt; i++)\n+\t\tputs(main_cmds.names[i]->name);\n+\n+\tclean_cmdnames(&main_cmds);\n+\tclean_cmdnames(&other_cmds);\n+}\n+\n+void list_all_other_cmds(void)\n+{\n+\tstruct cmdnames main_cmds, other_cmds;\n+\tint i;\n+\n+\tmemset(&main_cmds, 0, sizeof(main_cmds));\n+\tmemset(&other_cmds, 0, sizeof(other_cmds));\n+\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n+\n+\tfor (i = 0; i < other_cmds.cnt; i++)\n+\t\tputs(other_cmds.names[i]->name);\n+\n+\tclean_cmdnames(&main_cmds);\n+\tclean_cmdnames(&other_cmds);\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex b21d7c94e8..30e165773e 100644\n--- a/help.h\n+++ b/help.h\n@@ -17,6 +17,8 @@ static inline void mput_char(char c, unsigned int num)\n }\n \n extern void list_common_cmds_help(void);\n+extern void list_all_main_cmds(void);\n+extern void list_all_other_cmds(void);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\n-- \n2.17.0.664.g8924eee37a\n\n"},{"id":"346087","messageId":"20180429181844.21325-6-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180429181844.21325-1-pclouds@gmail.com","subject":"[PATCH v5 05/10] git.c: convert --list-*builtins to --list-cmds=*","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-29T18:18:39Z","receivedAt":"2018-04-29T18:19:20Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Even if these are hidden options, let's make them a bit more generic\nsince we're introducing more listing types shortly.\n\nThis also allows combining multiple listing types, which is usually\nnow (for combining parseopt and builtins) but future types will\nbenefit from this.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash |  2 +-\n git.c                                  | 27 ++++++++++++++++++++------\n t/t0012-help.sh                        |  2 +-\n 3 files changed, 23 insertions(+), 8 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 01dd9ff07a..d7b448fd94 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -3044,7 +3044,7 @@ __git_complete_common () {\n __git_cmds_with_parseopt_helper=\n __git_support_parseopt_helper () {\n \ttest -n \"$__git_cmds_with_parseopt_helper\" ||\n-\t\t__git_cmds_with_parseopt_helper=\"$(__git --list-parseopt-builtins)\"\n+\t\t__git_cmds_with_parseopt_helper=\"$(__git --list-cmds=parseopt)\"\n \n \tcase \" $__git_cmds_with_parseopt_helper \" in\n \t*\" $1 \"*)\ndiff --git a/git.c b/git.c\nindex f598fae7b7..ea9bbfb6a3 100644\n--- a/git.c\n+++ b/git.c\n@@ -38,6 +38,25 @@ static int use_pager = -1;\n \n static void list_builtins(unsigned int exclude_option, char sep);\n \n+static int list_cmds(const char *spec)\n+{\n+\twhile (*spec) {\n+\t\tconst char *sep = strchrnul(spec, ',');\n+\t\tint len = sep - spec;\n+\n+\t\tif (len == 8 && !strncmp(spec, \"builtins\", 8))\n+\t\t\tlist_builtins(0, '\\n');\n+\t\telse if (len == 8 && !strncmp(spec, \"parseopt\", 8))\n+\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n+\t\telse\n+\t\t\tdie(_(\"unsupported command listing type '%s'\"), spec);\n+\t\tspec += len;\n+\t\tif (*spec == ',')\n+\t\t\tspec++;\n+\t}\n+\treturn 0;\n+}\n+\n static void commit_pager_choice(void) {\n \tswitch (use_pager) {\n \tcase 0:\n@@ -223,12 +242,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t}\n \t\t\t(*argv)++;\n \t\t\t(*argc)--;\n-\t\t} else if (!strcmp(cmd, \"--list-builtins\")) {\n-\t\t\tlist_builtins(0, '\\n');\n-\t\t\texit(0);\n-\t\t} else if (!strcmp(cmd, \"--list-parseopt-builtins\")) {\n-\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n-\t\t\texit(0);\n+\t\t} else if (skip_prefix(cmd, \"--list-cmds=\", &cmd)) {\n+\t\t\texit(list_cmds(cmd));\n \t\t} else {\n \t\t\tfprintf(stderr, _(\"unknown option: %s\\n\"), cmd);\n \t\t\tusage(git_usage_string);\ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex c096f33505..3c91a9024a 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -59,7 +59,7 @@ test_expect_success 'git help' '\n '\n \n test_expect_success 'generate builtin list' '\n-\tgit --list-builtins >builtins\n+\tgit --list-cmds=builtins >builtins\n '\n \n while read builtin\n-- \n2.17.0.664.g8924eee37a\n\n"},{"id":"346088","messageId":"20180429181844.21325-11-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180429181844.21325-1-pclouds@gmail.com","subject":"[PATCH v5 10/10] completion: let git provide the completable command list","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-29T18:18:44Z","receivedAt":"2018-04-29T18:19:23Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Instead of maintaining a separate list of command classification,\nwhich often could go out of date, let's centralize the information\nback in git.\n\nWhile the function in git-completion.bash implies \"list porcelain\ncommands\", that's not exactly what it does. It gets all commands (aka\n--list-cmds=main,others) then exclude certain non-porcelain ones. We\ncould almost recreate this list two lists list-mainporcelain and\nothers. The non-porcelain-but-included-anyway is added by the third\ncategory list-complete.\n\nlist-complete does not recreate exactly the command list before this\npatch though. The following commands are not part of neither\nlist-mainporcelain nor list-complete and as a result no longer\ncompletes:\n\n- annotate             obsolete, discouraged to use\n- difftool-helper      not an end user command\n- filter-branch        not often used\n- get-tar-commit-id    not often used\n- imap-send            not often used\n- interpreter-trailers not for interactive use\n- lost-found           obsolete\n- p4                   too short and probably not often used (*)\n- peek-remote          deprecated\n- svn                  same category as p4 (*)\n- tar-tree             obsolete\n- verify-commit        not often used\n\nNote that the current completion script incorrectly classifies\nfilter-branch as porcelain and t9902 tests this behavior. We keep it\nthis way in t9902 because this test does not really care which\nparticular command is porcelain or plubmbing, they're just names.\n\n(*) to be fair, send-email command which is in the same\nforeignscminterface group as svn and p4 does get completion, just\nbecause it's used by git and kernel development. So maybe should\ninclude them.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n command-list.txt                       |  37 ++++----\n contrib/completion/git-completion.bash | 117 ++++++-------------------\n t/t9902-completion.sh                  |   5 +-\n 3 files changed, 48 insertions(+), 111 deletions(-)\n\ndiff --git a/command-list.txt b/command-list.txt\nindex 99ddc231c1..40776b9587 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -3,11 +3,11 @@\n git-add                                 mainporcelain           worktree\n git-am                                  mainporcelain\n git-annotate                            ancillaryinterrogators\n-git-apply                               plumbingmanipulators\n+git-apply                               plumbingmanipulators            complete\n git-archimport                          foreignscminterface\n git-archive                             mainporcelain\n git-bisect                              mainporcelain           info\n-git-blame                               ancillaryinterrogators\n+git-blame                               ancillaryinterrogators          complete\n git-branch                              mainporcelain           history\n git-bundle                              mainporcelain\n git-cat-file                            plumbinginterrogators\n@@ -17,7 +17,7 @@ git-check-mailmap                       purehelpers\n git-checkout                            mainporcelain           history\n git-checkout-index                      plumbingmanipulators\n git-check-ref-format                    purehelpers\n-git-cherry                              ancillaryinterrogators\n+git-cherry                              ancillaryinterrogators          complete\n git-cherry-pick                         mainporcelain\n git-citool                              mainporcelain\n git-clean                               mainporcelain\n@@ -25,7 +25,7 @@ git-clone                               mainporcelain           init\n git-column                              purehelpers\n git-commit                              mainporcelain           history\n git-commit-tree                         plumbingmanipulators\n-git-config                              ancillarymanipulators\n+git-config                              ancillarymanipulators           complete\n git-count-objects                       ancillaryinterrogators\n git-credential                          purehelpers\n git-credential-cache                    purehelpers\n@@ -39,7 +39,7 @@ git-diff                                mainporcelain           history\n git-diff-files                          plumbinginterrogators\n git-diff-index                          plumbinginterrogators\n git-diff-tree                           plumbinginterrogators\n-git-difftool                            ancillaryinterrogators\n+git-difftool                            ancillaryinterrogators          complete\n git-fast-export                         ancillarymanipulators\n git-fast-import                         ancillarymanipulators\n git-fetch                               mainporcelain           remote\n@@ -48,20 +48,20 @@ git-filter-branch                       ancillarymanipulators\n git-fmt-merge-msg                       purehelpers\n git-for-each-ref                        plumbinginterrogators\n git-format-patch                        mainporcelain\n-git-fsck                                ancillaryinterrogators\n+git-fsck                                ancillaryinterrogators          complete\n git-gc                                  mainporcelain\n git-get-tar-commit-id                   ancillaryinterrogators\n git-grep                                mainporcelain           info\n git-gui                                 mainporcelain\n git-hash-object                         plumbingmanipulators\n-git-help                                ancillaryinterrogators\n+git-help                                ancillaryinterrogators          complete\n git-http-backend                        synchingrepositories\n git-http-fetch                          synchelpers\n git-http-push                           synchelpers\n git-imap-send                           foreignscminterface\n git-index-pack                          plumbingmanipulators\n git-init                                mainporcelain           init\n-git-instaweb                            ancillaryinterrogators\n+git-instaweb                            ancillaryinterrogators          complete\n git-interpret-trailers                  purehelpers\n gitk                                    mainporcelain\n git-log                                 mainporcelain           info\n@@ -75,12 +75,12 @@ git-merge-base                          plumbinginterrogators\n git-merge-file                          plumbingmanipulators\n git-merge-index                         plumbingmanipulators\n git-merge-one-file                      purehelpers\n-git-mergetool                           ancillarymanipulators\n+git-mergetool                           ancillarymanipulators           complete\n git-merge-tree                          ancillaryinterrogators\n git-mktag                               plumbingmanipulators\n git-mktree                              plumbingmanipulators\n git-mv                                  mainporcelain           worktree\n-git-name-rev                            plumbinginterrogators\n+git-name-rev                            plumbinginterrogators           complete\n git-notes                               mainporcelain\n git-p4                                  foreignscminterface\n git-pack-objects                        plumbingmanipulators\n@@ -96,28 +96,29 @@ git-quiltimport                         foreignscminterface\n git-read-tree                           plumbingmanipulators\n git-rebase                              mainporcelain           history\n git-receive-pack                        synchelpers\n-git-reflog                              ancillarymanipulators\n-git-remote                              ancillarymanipulators\n-git-repack                              ancillarymanipulators\n-git-replace                             ancillarymanipulators\n-git-request-pull                        foreignscminterface\n+git-reflog                              ancillarymanipulators           complete\n+git-remote                              ancillarymanipulators           complete\n+git-repack                              ancillarymanipulators           complete\n+git-replace                             ancillarymanipulators           complete\n+git-request-pull                        foreignscminterface             complete\n git-rerere                              ancillaryinterrogators\n git-reset                               mainporcelain           worktree\n git-revert                              mainporcelain\n git-rev-list                            plumbinginterrogators\n git-rev-parse                           ancillaryinterrogators\n git-rm                                  mainporcelain           worktree\n-git-send-email                          foreignscminterface\n+git-send-email                          foreignscminterface             complete\n git-send-pack                           synchingrepositories\n git-shell                               synchelpers\n git-shortlog                            mainporcelain\n git-show                                mainporcelain           info\n-git-show-branch                         ancillaryinterrogators\n+git-show-branch                         ancillaryinterrogators          complete\n git-show-index                          plumbinginterrogators\n git-show-ref                            plumbinginterrogators\n git-sh-i18n                             purehelpers\n git-sh-setup                            purehelpers\n git-stash                               mainporcelain\n+git-stage                                                               complete\n git-status                              mainporcelain           info\n git-stripspace                          purehelpers\n git-submodule                           mainporcelain\n@@ -136,7 +137,7 @@ git-verify-commit                       ancillaryinterrogators\n git-verify-pack                         plumbinginterrogators\n git-verify-tag                          ancillaryinterrogators\n gitweb                                  ancillaryinterrogators\n-git-whatchanged                         ancillaryinterrogators\n+git-whatchanged                         ancillaryinterrogators          complete\n git-worktree                            mainporcelain\n git-write-tree                          plumbingmanipulators\n gitattributes                           guide\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 50d14a93dc..b27008b2f0 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -830,18 +830,30 @@ __git_complete_strategy ()\n }\n \n __git_commands () {\n-\tif test -n \"${GIT_TESTING_COMMAND_COMPLETION:-}\"\n-\tthen\n-\t\tprintf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n-\telse\n-\t\tgit --list-cmds=main,others\n-\tfi\n+\tcase \"$1\" in\n+\tporcelain)\n+\t\tif test -n \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\"\n+\t\tthen\n+\t\t\tprintf \"%s\" \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\"\n+\t\telse\n+\t\t\tgit --list-cmds=list-mainporcelain,others,list-complete\n+\t\tfi\n+\t\t;;\n+\tall)\n+\t\tif test -n \"$GIT_TESTING_ALL_COMMAND_LIST\"\n+\t\tthen\n+\t\t\tprintf \"%s\" \"$GIT_TESTING_ALL_COMMAND_LIST\"\n+\t\telse\n+\t\t\tgit --list-cmds=main,others\n+\t\tfi\n+\t\t;;\n+\tesac\n }\n \n-__git_list_all_commands ()\n+__git_list_commands ()\n {\n \tlocal i IFS=\" \"$'\\n'\n-\tfor i in $(__git_commands)\n+\tfor i in $(__git_commands $1)\n \tdo\n \t\tcase $i in\n \t\t*--*)             : helper pattern;;\n@@ -850,6 +862,11 @@ __git_list_all_commands ()\n \tdone\n }\n \n+__git_list_all_commands ()\n+{\n+\t__git_list_commands all\n+}\n+\n __git_all_commands=\n __git_compute_all_commands ()\n {\n@@ -859,89 +876,7 @@ __git_compute_all_commands ()\n \n __git_list_porcelain_commands ()\n {\n-\tlocal i IFS=\" \"$'\\n'\n-\t__git_compute_all_commands\n-\tfor i in $__git_all_commands\n-\tdo\n-\t\tcase $i in\n-\t\t*--*)             : helper pattern;;\n-\t\tapplymbox)        : ask gittus;;\n-\t\tapplypatch)       : ask gittus;;\n-\t\tarchimport)       : import;;\n-\t\tcat-file)         : plumbing;;\n-\t\tcheck-attr)       : plumbing;;\n-\t\tcheck-ignore)     : plumbing;;\n-\t\tcheck-mailmap)    : plumbing;;\n-\t\tcheck-ref-format) : plumbing;;\n-\t\tcheckout-index)   : plumbing;;\n-\t\tcolumn)           : internal helper;;\n-\t\tcommit-tree)      : plumbing;;\n-\t\tcount-objects)    : infrequent;;\n-\t\tcredential)       : credentials;;\n-\t\tcredential-*)     : credentials helper;;\n-\t\tcvsexportcommit)  : export;;\n-\t\tcvsimport)        : import;;\n-\t\tcvsserver)        : daemon;;\n-\t\tdaemon)           : daemon;;\n-\t\tdiff-files)       : plumbing;;\n-\t\tdiff-index)       : plumbing;;\n-\t\tdiff-tree)        : plumbing;;\n-\t\tfast-import)      : import;;\n-\t\tfast-export)      : export;;\n-\t\tfsck-objects)     : plumbing;;\n-\t\tfetch-pack)       : plumbing;;\n-\t\tfmt-merge-msg)    : plumbing;;\n-\t\tfor-each-ref)     : plumbing;;\n-\t\thash-object)      : plumbing;;\n-\t\thttp-*)           : transport;;\n-\t\tindex-pack)       : plumbing;;\n-\t\tinit-db)          : deprecated;;\n-\t\tlocal-fetch)      : plumbing;;\n-\t\tls-files)         : plumbing;;\n-\t\tls-remote)        : plumbing;;\n-\t\tls-tree)          : plumbing;;\n-\t\tmailinfo)         : plumbing;;\n-\t\tmailsplit)        : plumbing;;\n-\t\tmerge-*)          : plumbing;;\n-\t\tmktree)           : plumbing;;\n-\t\tmktag)            : plumbing;;\n-\t\tpack-objects)     : plumbing;;\n-\t\tpack-redundant)   : plumbing;;\n-\t\tpack-refs)        : plumbing;;\n-\t\tparse-remote)     : plumbing;;\n-\t\tpatch-id)         : plumbing;;\n-\t\tprune)            : plumbing;;\n-\t\tprune-packed)     : plumbing;;\n-\t\tquiltimport)      : import;;\n-\t\tread-tree)        : plumbing;;\n-\t\treceive-pack)     : plumbing;;\n-\t\tremote-*)         : transport;;\n-\t\trerere)           : plumbing;;\n-\t\trev-list)         : plumbing;;\n-\t\trev-parse)        : plumbing;;\n-\t\trunstatus)        : plumbing;;\n-\t\tsh-setup)         : internal;;\n-\t\tshell)            : daemon;;\n-\t\tshow-ref)         : plumbing;;\n-\t\tsend-pack)        : plumbing;;\n-\t\tshow-index)       : plumbing;;\n-\t\tssh-*)            : transport;;\n-\t\tstripspace)       : plumbing;;\n-\t\tsymbolic-ref)     : plumbing;;\n-\t\tunpack-file)      : plumbing;;\n-\t\tunpack-objects)   : plumbing;;\n-\t\tupdate-index)     : plumbing;;\n-\t\tupdate-ref)       : plumbing;;\n-\t\tupdate-server-info) : daemon;;\n-\t\tupload-archive)   : plumbing;;\n-\t\tupload-pack)      : plumbing;;\n-\t\twrite-tree)       : plumbing;;\n-\t\tvar)              : infrequent;;\n-\t\tverify-pack)      : infrequent;;\n-\t\tverify-tag)       : plumbing;;\n-\t\t*) echo $i;;\n-\t\tesac\n-\tdone\n+\t__git_list_commands porcelain\n }\n \n __git_porcelain_commands=\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 1b34caa1e1..2f16679380 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -13,7 +13,7 @@ complete ()\n \treturn 0\n }\n \n-# Be careful when updating this list:\n+# Be careful when updating these lists:\n #\n # (1) The build tree may have build artifact from different branch, or\n #     the user's $PATH may have a random executable that may begin\n@@ -30,7 +30,8 @@ complete ()\n #     completion for \"git <TAB>\", and a plumbing is excluded.  \"add\",\n #     \"filter-branch\" and \"ls-files\" are listed for this.\n \n-GIT_TESTING_COMMAND_COMPLETION='add checkout check-attr filter-branch ls-files'\n+GIT_TESTING_ALL_COMMAND_LIST='add checkout check-attr filter-branch ls-files'\n+GIT_TESTING_PORCELAIN_COMMAND_LIST='add checkout filter-branch'\n \n . \"$GIT_BUILD_DIR/contrib/completion/git-completion.bash\"\n \n-- \n2.17.0.664.g8924eee37a\n\n"},{"id":"346089","messageId":"20180429181844.21325-5-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180429181844.21325-1-pclouds@gmail.com","subject":"[PATCH v5 04/10] Remove common-cmds.h","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-29T18:18:38Z","receivedAt":"2018-04-29T18:19:30Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"After the last patch, common-cmds.h is no longer used (and it was\nactually broken). Remove all related code. command-list.h will take\nits place from now on.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n .gitignore          |  1 -\n Makefile            | 17 ++++++-----------\n generate-cmdlist.sh | 46 +++------------------------------------------\n 3 files changed, 9 insertions(+), 55 deletions(-)\n\ndiff --git a/.gitignore b/.gitignore\nindex d4c3914167..0836083992 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -179,7 +179,6 @@\n /gitweb/gitweb.cgi\n /gitweb/static/gitweb.js\n /gitweb/static/gitweb.min.*\n-/common-cmds.h\n /command-list.h\n *.tar.gz\n *.dsc\ndiff --git a/Makefile b/Makefile\nindex ab67150e68..71b5b594cd 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -757,7 +757,7 @@ LIB_FILE = libgit.a\n XDIFF_LIB = xdiff/lib.a\n VCSSVN_LIB = vcs-svn/lib.a\n \n-GENERATED_H += common-cmds.h command-list.h\n+GENERATED_H += command-list.h\n \n LIB_H = $(shell $(FIND) . \\\n \t-name .git -prune -o \\\n@@ -1916,9 +1916,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \\\n \t\t$(filter %.o,$^) $(LIBS)\n \n-help.sp help.s help.o: common-cmds.h command-list.h\n+help.sp help.s help.o: command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h command-list.h GIT-PREFIX\n+builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n@@ -1937,11 +1937,6 @@ $(BUILT_INS): git$X\n \tln -s $< $@ 2>/dev/null || \\\n \tcp $< $@\n \n-common-cmds.h: generate-cmdlist.sh command-list.txt\n-\n-common-cmds.h: $(wildcard Documentation/git-*.txt)\n-\t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt COMMON >$@+ && mv $@+ $@\n-\n command-list.h: generate-cmdlist.sh command-list.txt\n \n command-list.h: $(wildcard Documentation/git-*.txt)\n@@ -2155,7 +2150,7 @@ else\n # Dependencies on header files, for platforms that do not support\n # the gcc -MMD option.\n #\n-# Dependencies on automatically generated headers such as common-cmds.h or command-list.h\n+# Dependencies on automatically generated headers such as command-list.h\n # should _not_ be included here, since they are necessary even when\n # building an object for the first time.\n \n@@ -2534,7 +2529,7 @@ sparse: $(SP_OBJ)\n style:\n \tgit clang-format --style file --diff --extensions c,h\n \n-check: common-cmds.h command-list.h\n+check: command-list.h\n \t@if sparse; \\\n \tthen \\\n \t\techo >&2 \"Use 'make sparse' instead\"; \\\n@@ -2782,7 +2777,7 @@ clean: profile-clean coverage-clean\n \t$(RM) $(TEST_PROGRAMS) $(NO_INSTALL)\n \t$(RM) -r bin-wrappers $(dep_dirs)\n \t$(RM) -r po/build/\n-\t$(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h command-list.h $(ETAGS_TARGET) tags cscope*\n+\t$(RM) *.pyc *.pyo */*.pyc */*.pyo command-list.h $(ETAGS_TARGET) tags cscope*\n \t$(RM) -r $(GIT_TARNAME) .doc-tmp-dir\n \t$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz\n \t$(RM) $(htmldocs).tar.gz $(manpages).tar.gz\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 93de8e8f59..015eef2804 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -68,46 +68,6 @@ struct cmdname_help {\n \tuint32_t category;\n };\n \"\n-if [ -z \"$2\" ]\n-then\n-\tdefine_categories \"$1\"\n-\techo\n-\tprint_command_list \"$1\"\n-\texit 0\n-fi\n-\n-echo \"static const char *common_cmd_groups[] = {\"\n-\n-grps=grps$$.tmp\n-match=match$$.tmp\n-trap \"rm -f '$grps' '$match'\" 0 1 2 3 15\n-\n-sed -n '\n-\t1,/^### common groups/b\n-\t/^### command list/q\n-\t/^#/b\n-\t/^[ \t]*$/b\n-\th;s/^[^ \t][^ \t]*[ \t][ \t]*\\(.*\\)/\tN_(\"\\1\"),/p\n-\tg;s/^\\([^ \t][^ \t]*\\)[ \t].*/\\1/w '$grps'\n-\t' \"$1\"\n-printf '};\\n\\n'\n-\n-n=0\n-substnum=\n-while read grp\n-do\n-\techo \"^git-..*[ \t]$grp\"\n-\tsubstnum=\"$substnum${substnum:+;}s/[ \t]$grp/$n/\"\n-\tn=$(($n+1))\n-done <\"$grps\" >\"$match\"\n-\n-printf 'static struct cmdname_help common_cmds[] = {\\n'\n-grep -f \"$match\" \"$1\" |\n-sed 's/^git-//' |\n-sort |\n-while read cmd tags\n-do\n-\ttag=$(echo \"$tags\" | sed \"$substnum; s/[^0-9]//g\")\n-\techo \"\t{\\\"$cmd\\\", $(get_synopsis git-$cmd), $tag},\"\n-done\n-echo \"};\"\n+define_categories \"$1\"\n+echo\n+print_command_list \"$1\"\n-- \n2.17.0.664.g8924eee37a\n\n"},{"id":"346090","messageId":"20180429181844.21325-8-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180429181844.21325-1-pclouds@gmail.com","subject":"[PATCH v5 07/10] git: support --list-cmds=list-<category>","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-29T18:18:41Z","receivedAt":"2018-04-29T18:19:33Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This allows us to select any group of commands by a category defined\nin command-list.txt. This is an internal/hidden option so we don't\nhave to be picky about the category name or worried about exposing too\nmuch.\n\nThis will be used later by git-completion.bash to retrieve certain\ncommand groups.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n generate-cmdlist.sh | 17 +++++++++++++++++\n git.c               |  7 +++++++\n help.c              | 22 ++++++++++++++++++++++\n help.h              |  1 +\n 4 files changed, 47 insertions(+)\n\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 015eef2804..bfd8ef0671 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -45,6 +45,21 @@ define_categories() {\n \ttest \"$bit\" -gt 32 && die \"Urgh.. too many categories?\"\n }\n \n+define_category_names() {\n+\techo\n+\techo \"/* Category names */\"\n+\techo \"static const char *category_names[] = {\"\n+\tbit=0\n+\tcategory_list \"$1\" |\n+\twhile read cat\n+\tdo\n+\t\techo \"\t\\\"$cat\\\", /* (1UL << $bit) */\"\n+\t\tbit=$(($bit+1))\n+\tdone\n+\techo \"\tNULL\"\n+\techo \"};\"\n+}\n+\n print_command_list() {\n \techo \"static struct cmdname_help command_list[] = {\"\n \n@@ -70,4 +85,6 @@ struct cmdname_help {\n \"\n define_categories \"$1\"\n echo\n+define_category_names \"$1\"\n+echo\n print_command_list \"$1\"\ndiff --git a/git.c b/git.c\nindex da161a74ae..93927e34c4 100644\n--- a/git.c\n+++ b/git.c\n@@ -52,6 +52,13 @@ static int list_cmds(const char *spec)\n \t\t\tlist_all_main_cmds();\n \t\telse if (len == 6 && !strncmp(spec, \"others\", 6))\n \t\t\tlist_all_other_cmds();\n+\t\telse if (len > 5 && !strncmp(spec, \"list-\", 5)) {\n+\t\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\t\tstrbuf_add(&sb, spec + 5, len - 5);\n+\t\t\tlist_cmds_by_category(sb.buf);\n+\t\t\tstrbuf_release(&sb);\n+\t\t}\n \t\telse\n \t\t\tdie(_(\"unsupported command listing type '%s'\"), spec);\n \t\tspec += len;\ndiff --git a/help.c b/help.c\nindex 71bc001570..156dde1bea 100644\n--- a/help.c\n+++ b/help.c\n@@ -329,6 +329,28 @@ void list_all_other_cmds(void)\n \tclean_cmdnames(&other_cmds);\n }\n \n+void list_cmds_by_category(const char *cat)\n+{\n+\tint i, n = ARRAY_SIZE(command_list);\n+\tuint32_t cat_id = 0;\n+\n+\tfor (i = 0; category_names[i]; i++) {\n+\t\tif (!strcmp(cat, category_names[i])) {\n+\t\t\tcat_id = 1UL << i;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\tif (!cat_id)\n+\t\tdie(_(\"unsupported command listing type '%s'\"), cat);\n+\n+\tfor (i = 0; i < n; i++) {\n+\t\tstruct cmdname_help *cmd = command_list + i;\n+\n+\t\tif (cmd->category & cat_id)\n+\t\t\tputs(drop_prefix(cmd->name));\n+\t}\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex 30e165773e..752368840a 100644\n--- a/help.h\n+++ b/help.h\n@@ -19,6 +19,7 @@ static inline void mput_char(char c, unsigned int num)\n extern void list_common_cmds_help(void);\n extern void list_all_main_cmds(void);\n extern void list_all_other_cmds(void);\n+extern void list_cmds_by_category(const char *category);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\n-- \n2.17.0.664.g8924eee37a\n\n"},{"id":"346091","messageId":"20180429181844.21325-9-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180429181844.21325-1-pclouds@gmail.com","subject":"[PATCH v5 08/10] help: add \"-a --verbose\" to list all commands with synopsis","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-29T18:18:42Z","receivedAt":"2018-04-29T18:19:35Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This lists all recognized commands [1] by category. The group order\nfollows closely git.txt.\n\n[1] We may actually show commands that are not built (e.g. if you set\nNO_PERL you don't have git-instaweb but it's still listed here). I\nignore the problem because on Linux a git package could be split\nanyway. The \"git-core\" package may not contain git-instaweb even if\nit's built because it may end up in a separate package. We can't know\nanyway.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-help.txt |  4 +++-\n builtin/help.c             |  7 +++++++\n help.c                     | 16 ++++++++++++++++\n help.h                     |  1 +\n t/t0012-help.sh            |  9 +++++++++\n 5 files changed, 36 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-help.txt b/Documentation/git-help.txt\nindex 40d328a4b3..a40fc38d8b 100644\n--- a/Documentation/git-help.txt\n+++ b/Documentation/git-help.txt\n@@ -8,7 +8,7 @@ git-help - Display help information about Git\n SYNOPSIS\n --------\n [verse]\n-'git help' [-a|--all] [-g|--guide]\n+'git help' [-a|--all [--verbose]] [-g|--guide]\n \t   [-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE]\n \n DESCRIPTION\n@@ -42,6 +42,8 @@ OPTIONS\n --all::\n \tPrints all the available commands on the standard output. This\n \toption overrides any given command or guide name.\n+\tWhen used with `--verbose` print description for all recognized\n+\tcommands.\n \n -g::\n --guides::\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 2d51071429..83a7d73afe 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -36,6 +36,7 @@ static const char *html_path;\n \n static int show_all = 0;\n static int show_guides = 0;\n+static int verbose;\n static unsigned int colopts;\n static enum help_format help_format = HELP_FORMAT_NONE;\n static int exclude_guides;\n@@ -48,6 +49,7 @@ static struct option builtin_help_options[] = {\n \t\t\tHELP_FORMAT_WEB),\n \tOPT_SET_INT('i', \"info\", &help_format, N_(\"show info page\"),\n \t\t\tHELP_FORMAT_INFO),\n+\tOPT__VERBOSE(&verbose, N_(\"print command description\")),\n \tOPT_END(),\n };\n \n@@ -463,6 +465,11 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \tif (show_all) {\n \t\tgit_config(git_help_config, NULL);\n+\t\tif (verbose) {\n+\t\t\tsetup_pager();\n+\t\t\tlist_all_cmds_help();\n+\t\t\treturn 0;\n+\t\t}\n \t\tprintf(_(\"usage: %s%s\"), _(git_usage_string), \"\\n\\n\");\n \t\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n \t\tlist_commands(colopts, &main_cmds, &other_cmds);\ndiff --git a/help.c b/help.c\nindex 156dde1bea..f9da0214f1 100644\n--- a/help.c\n+++ b/help.c\n@@ -27,6 +27,17 @@ static struct category_description common_categories[] = {\n \t{ CAT_remote, N_(\"collaborate (see also: git help workflows)\") },\n \t{ 0, NULL }\n };\n+static struct category_description main_categories[] = {\n+\t{ CAT_mainporcelain, N_(\"Main Porcelain Commands\") },\n+\t{ CAT_ancillarymanipulators, N_(\"Ancillary Commands / Manipulators\") },\n+\t{ CAT_ancillaryinterrogators, N_(\"Ancillary Commands / Interrogators\") },\n+\t{ CAT_foreignscminterface, N_(\"Interacting with Others\") },\n+\t{ CAT_plumbingmanipulators, N_(\"Low-level Commands / Manipulators\") },\n+\t{ CAT_plumbinginterrogators, N_(\"Low-level Commands / Interrogators\") },\n+\t{ CAT_synchingrepositories, N_(\"Low-level Commands / Synching Repositories\") },\n+\t{ CAT_purehelpers, N_(\"Low-level Commands / Internal Helpers\") },\n+\t{ 0, NULL }\n+};\n \n static const char *drop_prefix(const char *name)\n {\n@@ -351,6 +362,11 @@ void list_cmds_by_category(const char *cat)\n \t}\n }\n \n+void list_all_cmds_help(void)\n+{\n+\tprint_cmd_by_category(main_categories);\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex 752368840a..090d46ba01 100644\n--- a/help.h\n+++ b/help.h\n@@ -17,6 +17,7 @@ static inline void mput_char(char c, unsigned int num)\n }\n \n extern void list_common_cmds_help(void);\n+extern void list_all_cmds_help(void);\n extern void list_all_main_cmds(void);\n extern void list_all_other_cmds(void);\n extern void list_cmds_by_category(const char *category);\ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex 3c91a9024a..060df24c2d 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -25,6 +25,15 @@ test_expect_success \"setup\" '\n \tEOF\n '\n \n+# make sure to exercise these code paths, the output is a bit tricky\n+# to verify\n+test_expect_success 'basic help commands' '\n+\tgit help >/dev/null &&\n+\tgit help -a >/dev/null &&\n+\tgit help -g >/dev/null &&\n+\tgit help -av >/dev/null\n+'\n+\n test_expect_success \"works for commands and guides by default\" '\n \tconfigure_help &&\n \tgit help status &&\n-- \n2.17.0.664.g8924eee37a\n\n"},{"id":"346092","messageId":"20180429181844.21325-10-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180429181844.21325-1-pclouds@gmail.com","subject":"[PATCH v5 09/10] help: use command-list.txt for the source of guides","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-29T18:18:43Z","receivedAt":"2018-04-29T18:19:38Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The help command currently hard codes the list of guides and their\nsummary in C. Let's move this list to command-list.txt. This lets us\nextract summary lines from Documentation/git*.txt. This also\npotentially lets us list guides in git.txt, but I'll leave that for\nnow.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/gitattributes.txt        |  2 +-\n Documentation/gitmodules.txt           |  2 +-\n Documentation/gitrevisions.txt         |  2 +-\n Makefile                               |  2 +-\n builtin/help.c                         | 32 --------------------------\n command-list.txt                       | 16 +++++++++++++\n contrib/completion/git-completion.bash | 15 ++++++++----\n help.c                                 | 18 ++++++++++++---\n help.h                                 |  1 +\n t/t0012-help.sh                        |  6 +++++\n 10 files changed, 52 insertions(+), 44 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex 1094fe2b5b..083c2f380d 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -3,7 +3,7 @@ gitattributes(5)\n \n NAME\n ----\n-gitattributes - defining attributes per path\n+gitattributes - Defining attributes per path\n \n SYNOPSIS\n --------\ndiff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt\nindex db5d47eb19..4d63def206 100644\n--- a/Documentation/gitmodules.txt\n+++ b/Documentation/gitmodules.txt\n@@ -3,7 +3,7 @@ gitmodules(5)\n \n NAME\n ----\n-gitmodules - defining submodule properties\n+gitmodules - Defining submodule properties\n \n SYNOPSIS\n --------\ndiff --git a/Documentation/gitrevisions.txt b/Documentation/gitrevisions.txt\nindex 27dec5b91d..1f6cceaefb 100644\n--- a/Documentation/gitrevisions.txt\n+++ b/Documentation/gitrevisions.txt\n@@ -3,7 +3,7 @@ gitrevisions(7)\n \n NAME\n ----\n-gitrevisions - specifying revisions and ranges for Git\n+gitrevisions - Specifying revisions and ranges for Git\n \n SYNOPSIS\n --------\ndiff --git a/Makefile b/Makefile\nindex 71b5b594cd..18696e35b0 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1939,7 +1939,7 @@ $(BUILT_INS): git$X\n \n command-list.h: generate-cmdlist.sh command-list.txt\n \n-command-list.h: $(wildcard Documentation/git-*.txt)\n+command-list.h: $(wildcard Documentation/git*.txt)\n \t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt >$@+ && mv $@+ $@\n \n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 83a7d73afe..b58e8d5f6a 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -402,38 +402,6 @@ static void show_html_page(const char *git_cmd)\n \topen_html(page_path.buf);\n }\n \n-static struct {\n-\tconst char *name;\n-\tconst char *help;\n-} common_guides[] = {\n-\t{ \"attributes\", N_(\"Defining attributes per path\") },\n-\t{ \"everyday\", N_(\"Everyday Git With 20 Commands Or So\") },\n-\t{ \"glossary\", N_(\"A Git glossary\") },\n-\t{ \"ignore\", N_(\"Specifies intentionally untracked files to ignore\") },\n-\t{ \"modules\", N_(\"Defining submodule properties\") },\n-\t{ \"revisions\", N_(\"Specifying revisions and ranges for Git\") },\n-\t{ \"tutorial\", N_(\"A tutorial introduction to Git (for version 1.5.1 or newer)\") },\n-\t{ \"workflows\", N_(\"An overview of recommended workflows with Git\") },\n-};\n-\n-static void list_common_guides_help(void)\n-{\n-\tint i, longest = 0;\n-\n-\tfor (i = 0; i < ARRAY_SIZE(common_guides); i++) {\n-\t\tif (longest < strlen(common_guides[i].name))\n-\t\t\tlongest = strlen(common_guides[i].name);\n-\t}\n-\n-\tputs(_(\"The common Git guides are:\\n\"));\n-\tfor (i = 0; i < ARRAY_SIZE(common_guides); i++) {\n-\t\tprintf(\"   %s   \", common_guides[i].name);\n-\t\tmput_char(' ', longest - strlen(common_guides[i].name));\n-\t\tputs(_(common_guides[i].help));\n-\t}\n-\tputchar('\\n');\n-}\n-\n static const char *check_git_cmd(const char* cmd)\n {\n \tchar *alias;\ndiff --git a/command-list.txt b/command-list.txt\nindex 3bd23201a6..99ddc231c1 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -139,3 +139,19 @@ gitweb                                  ancillaryinterrogators\n git-whatchanged                         ancillaryinterrogators\n git-worktree                            mainporcelain\n git-write-tree                          plumbingmanipulators\n+gitattributes                           guide\n+gitcli                                  guide\n+gitcore-tutorial                        guide\n+gitcvs-migration                        guide\n+gitdiffcore                             guide\n+giteveryday                             guide\n+gitglossary                             guide\n+githooks                                guide\n+gitignore                               guide\n+gitmodules                              guide\n+gitnamespaces                           guide\n+gitrepository-layout                    guide\n+gitrevisions                            guide\n+gittutorial-2                           guide\n+gittutorial                             guide\n+gitworkflows                            guide\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 77cfb8a20b..50d14a93dc 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1570,6 +1570,13 @@ _git_grep ()\n \t__git_complete_refs\n }\n \n+__git_all_guides=\n+__git_compute_all_guides ()\n+{\n+\ttest -n \"$__git_all_guides\" ||\n+\t__git_all_guides=$(git --list-cmds=list-guide)\n+}\n+\n _git_help ()\n {\n \tcase \"$cur\" in\n@@ -1579,11 +1586,9 @@ _git_help ()\n \t\t;;\n \tesac\n \t__git_compute_all_commands\n-\t__gitcomp \"$__git_all_commands $(__git_aliases)\n-\t\tattributes cli core-tutorial cvs-migration\n-\t\tdiffcore everyday gitk glossary hooks ignore modules\n-\t\tnamespaces repository-layout revisions tutorial tutorial-2\n-\t\tworkflows\n+\t__git_compute_all_guides\n+\t__gitcomp \"$__git_all_commands $(__git_aliases) $__git_all_guides\n+\t\tgitk\n \t\t\"\n }\n \ndiff --git a/help.c b/help.c\nindex f9da0214f1..f4629d0ee1 100644\n--- a/help.c\n+++ b/help.c\n@@ -39,12 +39,14 @@ static struct category_description main_categories[] = {\n \t{ 0, NULL }\n };\n \n-static const char *drop_prefix(const char *name)\n+static const char *drop_prefix(const char *name, uint32_t category)\n {\n \tconst char *new_name;\n \n \tif (skip_prefix(name, \"git-\", &new_name))\n \t\treturn new_name;\n+\tif (category == CAT_guide && skip_prefix(name, \"git\", &new_name))\n+\t\treturn new_name;\n \treturn name;\n \n }\n@@ -66,7 +68,7 @@ static void extract_cmds(struct cmdname_help **p_cmds, uint32_t mask)\n \t\t\tcontinue;\n \n \t\tcmds[nr] = *cmd;\n-\t\tcmds[nr].name = drop_prefix(cmd->name);\n+\t\tcmds[nr].name = drop_prefix(cmd->name, cmd->category);\n \n \t\tnr++;\n \t}\n@@ -358,10 +360,20 @@ void list_cmds_by_category(const char *cat)\n \t\tstruct cmdname_help *cmd = command_list + i;\n \n \t\tif (cmd->category & cat_id)\n-\t\t\tputs(drop_prefix(cmd->name));\n+\t\t\tputs(drop_prefix(cmd->name, cmd->category));\n \t}\n }\n \n+void list_common_guides_help(void)\n+{\n+\tstruct category_description catdesc[] = {\n+\t\t{ CAT_guide, N_(\"The common Git guides are:\") },\n+\t\t{ 0, NULL }\n+\t};\n+\tprint_cmd_by_category(catdesc);\n+\tputchar('\\n');\n+}\n+\n void list_all_cmds_help(void)\n {\n \tprint_cmd_by_category(main_categories);\ndiff --git a/help.h b/help.h\nindex 090d46ba01..5d27368fe4 100644\n--- a/help.h\n+++ b/help.h\n@@ -18,6 +18,7 @@ static inline void mput_char(char c, unsigned int num)\n \n extern void list_common_cmds_help(void);\n extern void list_all_cmds_help(void);\n+extern void list_common_guides_help(void);\n extern void list_all_main_cmds(void);\n extern void list_all_other_cmds(void);\n extern void list_cmds_by_category(const char *category);\ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex 060df24c2d..bc27df7f38 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -66,6 +66,12 @@ test_expect_success 'git help' '\n \ttest_i18ngrep \"^   commit \" help.output &&\n \ttest_i18ngrep \"^   fetch  \" help.output\n '\n+test_expect_success 'git help -g' '\n+\tgit help -g >help.output &&\n+\ttest_i18ngrep \"^   attributes \" help.output &&\n+\ttest_i18ngrep \"^   everyday   \" help.output &&\n+\ttest_i18ngrep \"^   tutorial   \" help.output\n+'\n \n test_expect_success 'generate builtin list' '\n \tgit --list-cmds=builtins >builtins\n-- \n2.17.0.664.g8924eee37a\n\n"},{"id":"346093","messageId":"CACsJy8ADj-bTMYDHxRNLOMppOEdPbVwL49u3XCfNBCmoLLZo+A@mail.gmail.com","threadId":"48155","inReplyTo":"20180429181844.21325-10-pclouds@gmail.com","subject":"Re: [PATCH v5 09/10] help: use command-list.txt for the source of guides","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-29T18:23:24Z","receivedAt":"2018-04-29T18:23:58Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Phillip (and others) the changes in this patch make \"git help -g\" now\nlists a lot more guides than just the \"common\" one as advertised (see\nbelow for the exact list). The man page for \"git help -g\" also\nmentions that it would list \"useful\" guides, not all guides. But we\nhave no way to list all guides as far as I can tell.\n\nI guess we have two options forward:\n\n- keep \"help -g\" to common guide (we can tag common guides in\ncommand-list.txt) and add a new option to list all guides (\"help\n-ag\"?)\n- reword the man page to make \"help -g\" list all guides\n\nI'm ok with either direction. What's your preference?\n\nFor comparison, this is the new output\n\nThe common Git guides are:\n   attributes          Defining attributes per path\n   cli                 Git command-line interface and conventions\n   core-tutorial       A Git core tutorial for developers\n   cvs-migration       Git for CVS users\n   diffcore            Tweaking diff output\n   everyday            A useful minimum set of commands for Everyday\nGit\n   glossary            A Git Glossary\n   hooks               Hooks used by Git\n   ignore              Specifies intentionally untracked files to\nignore\n   modules             Defining submodule properties\n   namespaces          Git namespaces\n   repository-layout   Git Repository Layout\n   revisions           Specifying revisions and ranges for Git\n   tutorial            A tutorial introduction to Git\n   tutorial-2          A tutorial introduction to Git: part two\n   workflows           An overview of recommended workflows with Git\n\ncompared to the old version\n\nThe common Git guides are:\n\n   attributes   Defining attributes per path\n   everyday     Everyday Git With 20 Commands Or So\n   glossary     A Git glossary\n   ignore       Specifies intentionally untracked files to ignore\n   modules      Defining submodule properties\n   revisions    Specifying revisions and ranges for Git\n   tutorial     A tutorial introduction to Git (for version 1.5.1 or\nnewer)\n   workflows    An overview of recommended workflows with Git\n\n\n\n\nOn Sun, Apr 29, 2018 at 8:18 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> The help command currently hard codes the list of guides and their\n> summary in C. Let's move this list to command-list.txt. This lets us\n> extract summary lines from Documentation/git*.txt. This also\n> potentially lets us list guides in git.txt, but I'll leave that for\n> now.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  Documentation/gitattributes.txt        |  2 +-\n>  Documentation/gitmodules.txt           |  2 +-\n>  Documentation/gitrevisions.txt         |  2 +-\n>  Makefile                               |  2 +-\n>  builtin/help.c                         | 32 --------------------------\n>  command-list.txt                       | 16 +++++++++++++\n>  contrib/completion/git-completion.bash | 15 ++++++++----\n>  help.c                                 | 18 ++++++++++++---\n>  help.h                                 |  1 +\n>  t/t0012-help.sh                        |  6 +++++\n>  10 files changed, 52 insertions(+), 44 deletions(-)\n>\n> diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\n> index 1094fe2b5b..083c2f380d 100644\n> --- a/Documentation/gitattributes.txt\n> +++ b/Documentation/gitattributes.txt\n> @@ -3,7 +3,7 @@ gitattributes(5)\n>\n>  NAME\n>  ----\n> -gitattributes - defining attributes per path\n> +gitattributes - Defining attributes per path\n>\n>  SYNOPSIS\n>  --------\n> diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt\n> index db5d47eb19..4d63def206 100644\n> --- a/Documentation/gitmodules.txt\n> +++ b/Documentation/gitmodules.txt\n> @@ -3,7 +3,7 @@ gitmodules(5)\n>\n>  NAME\n>  ----\n> -gitmodules - defining submodule properties\n> +gitmodules - Defining submodule properties\n>\n>  SYNOPSIS\n>  --------\n> diff --git a/Documentation/gitrevisions.txt b/Documentation/gitrevisions.txt\n> index 27dec5b91d..1f6cceaefb 100644\n> --- a/Documentation/gitrevisions.txt\n> +++ b/Documentation/gitrevisions.txt\n> @@ -3,7 +3,7 @@ gitrevisions(7)\n>\n>  NAME\n>  ----\n> -gitrevisions - specifying revisions and ranges for Git\n> +gitrevisions - Specifying revisions and ranges for Git\n>\n>  SYNOPSIS\n>  --------\n> diff --git a/Makefile b/Makefile\n> index 71b5b594cd..18696e35b0 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -1939,7 +1939,7 @@ $(BUILT_INS): git$X\n>\n>  command-list.h: generate-cmdlist.sh command-list.txt\n>\n> -command-list.h: $(wildcard Documentation/git-*.txt)\n> +command-list.h: $(wildcard Documentation/git*.txt)\n>         $(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt >$@+ && mv $@+ $@\n>\n>  SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n> diff --git a/builtin/help.c b/builtin/help.c\n> index 83a7d73afe..b58e8d5f6a 100644\n> --- a/builtin/help.c\n> +++ b/builtin/help.c\n> @@ -402,38 +402,6 @@ static void show_html_page(const char *git_cmd)\n>         open_html(page_path.buf);\n>  }\n>\n> -static struct {\n> -       const char *name;\n> -       const char *help;\n> -} common_guides[] = {\n> -       { \"attributes\", N_(\"Defining attributes per path\") },\n> -       { \"everyday\", N_(\"Everyday Git With 20 Commands Or So\") },\n> -       { \"glossary\", N_(\"A Git glossary\") },\n> -       { \"ignore\", N_(\"Specifies intentionally untracked files to ignore\") },\n> -       { \"modules\", N_(\"Defining submodule properties\") },\n> -       { \"revisions\", N_(\"Specifying revisions and ranges for Git\") },\n> -       { \"tutorial\", N_(\"A tutorial introduction to Git (for version 1.5.1 or newer)\") },\n> -       { \"workflows\", N_(\"An overview of recommended workflows with Git\") },\n> -};\n> -\n> -static void list_common_guides_help(void)\n> -{\n> -       int i, longest = 0;\n> -\n> -       for (i = 0; i < ARRAY_SIZE(common_guides); i++) {\n> -               if (longest < strlen(common_guides[i].name))\n> -                       longest = strlen(common_guides[i].name);\n> -       }\n> -\n> -       puts(_(\"The common Git guides are:\\n\"));\n> -       for (i = 0; i < ARRAY_SIZE(common_guides); i++) {\n> -               printf(\"   %s   \", common_guides[i].name);\n> -               mput_char(' ', longest - strlen(common_guides[i].name));\n> -               puts(_(common_guides[i].help));\n> -       }\n> -       putchar('\\n');\n> -}\n> -\n>  static const char *check_git_cmd(const char* cmd)\n>  {\n>         char *alias;\n> diff --git a/command-list.txt b/command-list.txt\n> index 3bd23201a6..99ddc231c1 100644\n> --- a/command-list.txt\n> +++ b/command-list.txt\n> @@ -139,3 +139,19 @@ gitweb                                  ancillaryinterrogators\n>  git-whatchanged                         ancillaryinterrogators\n>  git-worktree                            mainporcelain\n>  git-write-tree                          plumbingmanipulators\n> +gitattributes                           guide\n> +gitcli                                  guide\n> +gitcore-tutorial                        guide\n> +gitcvs-migration                        guide\n> +gitdiffcore                             guide\n> +giteveryday                             guide\n> +gitglossary                             guide\n> +githooks                                guide\n> +gitignore                               guide\n> +gitmodules                              guide\n> +gitnamespaces                           guide\n> +gitrepository-layout                    guide\n> +gitrevisions                            guide\n> +gittutorial-2                           guide\n> +gittutorial                             guide\n> +gitworkflows                            guide\n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> index 77cfb8a20b..50d14a93dc 100644\n> --- a/contrib/completion/git-completion.bash\n> +++ b/contrib/completion/git-completion.bash\n> @@ -1570,6 +1570,13 @@ _git_grep ()\n>         __git_complete_refs\n>  }\n>\n> +__git_all_guides=\n> +__git_compute_all_guides ()\n> +{\n> +       test -n \"$__git_all_guides\" ||\n> +       __git_all_guides=$(git --list-cmds=list-guide)\n> +}\n> +\n>  _git_help ()\n>  {\n>         case \"$cur\" in\n> @@ -1579,11 +1586,9 @@ _git_help ()\n>                 ;;\n>         esac\n>         __git_compute_all_commands\n> -       __gitcomp \"$__git_all_commands $(__git_aliases)\n> -               attributes cli core-tutorial cvs-migration\n> -               diffcore everyday gitk glossary hooks ignore modules\n> -               namespaces repository-layout revisions tutorial tutorial-2\n> -               workflows\n> +       __git_compute_all_guides\n> +       __gitcomp \"$__git_all_commands $(__git_aliases) $__git_all_guides\n> +               gitk\n>                 \"\n>  }\n>\n> diff --git a/help.c b/help.c\n> index f9da0214f1..f4629d0ee1 100644\n> --- a/help.c\n> +++ b/help.c\n> @@ -39,12 +39,14 @@ static struct category_description main_categories[] = {\n>         { 0, NULL }\n>  };\n>\n> -static const char *drop_prefix(const char *name)\n> +static const char *drop_prefix(const char *name, uint32_t category)\n>  {\n>         const char *new_name;\n>\n>         if (skip_prefix(name, \"git-\", &new_name))\n>                 return new_name;\n> +       if (category == CAT_guide && skip_prefix(name, \"git\", &new_name))\n> +               return new_name;\n>         return name;\n>\n>  }\n> @@ -66,7 +68,7 @@ static void extract_cmds(struct cmdname_help **p_cmds, uint32_t mask)\n>                         continue;\n>\n>                 cmds[nr] = *cmd;\n> -               cmds[nr].name = drop_prefix(cmd->name);\n> +               cmds[nr].name = drop_prefix(cmd->name, cmd->category);\n>\n>                 nr++;\n>         }\n> @@ -358,10 +360,20 @@ void list_cmds_by_category(const char *cat)\n>                 struct cmdname_help *cmd = command_list + i;\n>\n>                 if (cmd->category & cat_id)\n> -                       puts(drop_prefix(cmd->name));\n> +                       puts(drop_prefix(cmd->name, cmd->category));\n>         }\n>  }\n>\n> +void list_common_guides_help(void)\n> +{\n> +       struct category_description catdesc[] = {\n> +               { CAT_guide, N_(\"The common Git guides are:\") },\n> +               { 0, NULL }\n> +       };\n> +       print_cmd_by_category(catdesc);\n> +       putchar('\\n');\n> +}\n> +\n>  void list_all_cmds_help(void)\n>  {\n>         print_cmd_by_category(main_categories);\n> diff --git a/help.h b/help.h\n> index 090d46ba01..5d27368fe4 100644\n> --- a/help.h\n> +++ b/help.h\n> @@ -18,6 +18,7 @@ static inline void mput_char(char c, unsigned int num)\n>\n>  extern void list_common_cmds_help(void);\n>  extern void list_all_cmds_help(void);\n> +extern void list_common_guides_help(void);\n>  extern void list_all_main_cmds(void);\n>  extern void list_all_other_cmds(void);\n>  extern void list_cmds_by_category(const char *category);\n> diff --git a/t/t0012-help.sh b/t/t0012-help.sh\n> index 060df24c2d..bc27df7f38 100755\n> --- a/t/t0012-help.sh\n> +++ b/t/t0012-help.sh\n> @@ -66,6 +66,12 @@ test_expect_success 'git help' '\n>         test_i18ngrep \"^   commit \" help.output &&\n>         test_i18ngrep \"^   fetch  \" help.output\n>  '\n> +test_expect_success 'git help -g' '\n> +       git help -g >help.output &&\n> +       test_i18ngrep \"^   attributes \" help.output &&\n> +       test_i18ngrep \"^   everyday   \" help.output &&\n> +       test_i18ngrep \"^   tutorial   \" help.output\n> +'\n>\n>  test_expect_success 'generate builtin list' '\n>         git --list-cmds=builtins >builtins\n> --\n> 2.17.0.664.g8924eee37a\n>\n\n\n\n-- \nDuy\n"},{"id":"346167","messageId":"CACsJy8A5O2qPHPNTCWWcFb6FJx3XAwfmaSWSdg7658JtDNV4rA@mail.gmail.com","threadId":"48155","inReplyTo":"20180429181844.21325-1-pclouds@gmail.com","subject":"Re: [PATCH v5 00/10] Keep all info in command-list.txt in git binary","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-04-30T15:53:34Z","receivedAt":"2018-04-30T15:54:28Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is probably scope creep for this series, but do you guys think we\nshould do the same for config variables completion? We currently\nmaintain a giant list at the end of _git_config(). Extracting the list\nfrom Documentation/config.txt to keep it in a C array does not look\nsuper hard. There will be some special handling for advice.* or\ncolor.<slot>... but overall I still think it's a net gain.\n\nListing all recognizable config variables from \"git config\" (or \"git\nhelp\") would be lovely, but I don't think it helps unless we could\nprint a short summary line each variable, but this info is not\navailable anywhere.\n--\nDuy\n"},{"id":"346886","messageId":"20180507175222.12114-1-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180429181844.21325-1-pclouds@gmail.com","subject":"[PATCH v6 00/13] Keep all info in command-list.txt in git binary","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-07T17:52:09Z","receivedAt":"2018-05-07T17:53:05Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"v6 is now \"feature complete\". v6 adds\n\n- documentation in command-list.txt so people know how to update it\n- support for config key completion.commands, which consists\n  of extra commands. It could also be used for excluding some\n  commands.\n\nInterdiff\n\ndiff --git a/command-list.txt b/command-list.txt\nindex 40776b9587..3e21ddfcfb 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -1,3 +1,47 @@\n+# Command classification list\n+# ---------------------------\n+# All supported commands, builtin or external, must be described in\n+# here. This info is used to list commands in various places. Each\n+# command is on one line followed by one or more attributes.\n+#\n+# The first attribute group is mandatory and indicates the command\n+# type. This group includes:\n+#\n+#   mainporcelain\n+#   ancillarymanipulators\n+#   ancillaryinterrogators\n+#   foreignscminterface\n+#   plumbingmanipulators\n+#   plumbinginterrogators\n+#   synchingrepositories\n+#   synchelpers\n+#   purehelpers\n+#\n+# The type names are self explanatory. But if you want to see what\n+# command belongs to what group to get a better picture, have a look\n+# at \"git\" man page, \"GIT COMMANDS\" section.\n+#\n+# Commands of type mainporcelain can also optionally have one of these\n+# attributes:\n+#\n+#   init\n+#   worktree\n+#   info\n+#   history\n+#   remote\n+#\n+# These commands are considered \"common\" and will show up in \"git\n+# help\" output in groups. Uncommon porcelain commands must not\n+# specify any of these attributes.\n+#\n+# \"complete\" attribute is used to mark that the command should be\n+# completable by git-completion.bash. Note that by default,\n+# mainporcelain commands are completable so you don't need this\n+# attribute.\n+#\n+# While not true commands, guides are also specified here, which can\n+# only have \"guide\" attribute and nothing else.\n+#\n ### command list (do not change this line, also do not change alignment)\n # command name                          category [category] [category]\n git-add                                 mainporcelain           worktree\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 908692ea52..0fd29803d5 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -38,6 +38,38 @@\n #\n #     When set to \"1\", do not include \"DWIM\" suggestions in git-checkout\n #     completion (e.g., completing \"foo\" when \"origin/foo\" exists).\n+#\n+#   GIT_COMPLETION_CMD_GROUPS\n+#\n+#     When set, \"git --list-cmds=$GIT_COMPLETION_CMD_GROUPS\" will be\n+#     used to get the list of completable commands. The default is\n+#     \"mainporcelain,others,list-complete\" (in English: all porcelain\n+#     commands and external ones are included. Certain non-porcelain\n+#     commands are also marked for completion in command-list.txt).\n+#     You could for example complete all commands with\n+#\n+#         GIT_COMPLETION_CMD_GROUPS=main,others\n+#\n+#     Or you could go with defaults add some extra commands specified\n+#     in the configuration variable completion.commands [1] with\n+#\n+#         GIT_COMPLETION_CMD_GROUPS=mainporcelain,others,list-complete,config\n+#\n+#     Or go completely custom group with\n+#\n+#         GIT_COMPLETION_CMD_GROUPS=config\n+#\n+#     Or you could even play with other command categories found in\n+#     command-list.txt.\n+#\n+#     [1] Note that completion.commands should not be per-repository\n+#         since the command list is generated once and cached.\n+#\n+#         completion.commands could be used to exclude commands as\n+#         well.  If a command in this list begins with '-', then it\n+#         will be excluded from the list of commands gathered by the\n+#         groups specified before \"config\" in\n+#         $GIT_COMPLETION_CMD_GROUPS.\n \n case \"$COMP_WORDBREAKS\" in\n *:*) : great ;;\n@@ -840,6 +872,9 @@ __git_commands () {\n \t\tif test -n \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\"\n \t\tthen\n \t\t\tprintf \"%s\" \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\"\n+\t\telif test -n \"$GIT_COMPLETION_CMD_GROUPS\"\n+\t\tthen\n+\t\t\tgit --list-cmds=\"$GIT_COMPLETION_CMD_GROUPS\"\n \t\telse\n \t\t\tgit --list-cmds=list-mainporcelain,others,list-complete\n \t\tfi\ndiff --git a/git.c b/git.c\nindex 1c8b0c93e1..fd08911e11 100644\n--- a/git.c\n+++ b/git.c\n@@ -36,27 +36,30 @@ const char git_more_info_string[] =\n \n static int use_pager = -1;\n \n-static void list_builtins(unsigned int exclude_option, char sep);\n+static void list_builtins(struct string_list *list, unsigned int exclude_option);\n \n static int list_cmds(const char *spec)\n {\n+\tstruct string_list list = STRING_LIST_INIT_DUP;\n+\tint i;\n+\n \twhile (*spec) {\n \t\tconst char *sep = strchrnul(spec, ',');\n \t\tint len = sep - spec;\n \n \t\tif (len == 8 && !strncmp(spec, \"builtins\", 8))\n-\t\t\tlist_builtins(0, '\\n');\n-\t\telse if (len == 8 && !strncmp(spec, \"parseopt\", 8))\n-\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n+\t\t\tlist_builtins(&list, 0);\n \t\telse if (len == 4 && !strncmp(spec, \"main\", 4))\n-\t\t\tlist_all_main_cmds();\n+\t\t\tlist_all_main_cmds(&list);\n \t\telse if (len == 6 && !strncmp(spec, \"others\", 6))\n-\t\t\tlist_all_other_cmds();\n+\t\t\tlist_all_other_cmds(&list);\n+\t\telse if (len == 6 && !strncmp(spec, \"config\", 6))\n+\t\t\tlist_cmds_by_config(&list);\n \t\telse if (len > 5 && !strncmp(spec, \"list-\", 5)) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n \n \t\t\tstrbuf_add(&sb, spec + 5, len - 5);\n-\t\t\tlist_cmds_by_category(sb.buf);\n+\t\t\tlist_cmds_by_category(&list, sb.buf);\n \t\t\tstrbuf_release(&sb);\n \t\t}\n \t\telse\n@@ -65,6 +68,9 @@ static int list_cmds(const char *spec)\n \t\tif (*spec == ',')\n \t\t\tspec++;\n \t}\n+\tfor (i = 0; i < list.nr; i++)\n+\t\tputs(list.items[i].string);\n+\tstring_list_clear(&list, 0);\n \treturn 0;\n }\n \n@@ -254,7 +260,18 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t(*argv)++;\n \t\t\t(*argc)--;\n \t\t} else if (skip_prefix(cmd, \"--list-cmds=\", &cmd)) {\n-\t\t\texit(list_cmds(cmd));\n+\t\t\tif (!strcmp(cmd, \"parseopt\")) {\n+\t\t\t\tstruct string_list list = STRING_LIST_INIT_DUP;\n+\t\t\t\tint i;\n+\n+\t\t\t\tlist_builtins(&list, NO_PARSEOPT);\n+\t\t\t\tfor (i = 0; i < list.nr; i++)\n+\t\t\t\t\tprintf(\"%s \", list.items[i].string);\n+\t\t\t\tstring_list_clear(&list, 0);\n+\t\t\t\texit(0);\n+\t\t\t} else {\n+\t\t\t\texit(list_cmds(cmd));\n+\t\t\t}\n \t\t} else {\n \t\t\tfprintf(stderr, _(\"unknown option: %s\\n\"), cmd);\n \t\t\tusage(git_usage_string);\n@@ -534,14 +551,14 @@ int is_builtin(const char *s)\n \treturn !!get_builtin(s);\n }\n \n-static void list_builtins(unsigned int exclude_option, char sep)\n+static void list_builtins(struct string_list *out, unsigned int exclude_option)\n {\n \tint i;\n \tfor (i = 0; i < ARRAY_SIZE(commands); i++) {\n \t\tif (exclude_option &&\n \t\t    (commands[i].option & exclude_option))\n \t\t\tcontinue;\n-\t\tprintf(\"%s%c\", commands[i].cmd, sep);\n+\t\tstring_list_append(out, commands[i].cmd);\n \t}\n }\n \ndiff --git a/help.c b/help.c\nindex 78ab40a0eb..abf87205b2 100644\n--- a/help.c\n+++ b/help.c\n@@ -310,7 +310,7 @@ void list_common_cmds_help(void)\n \tprint_cmd_by_category(common_categories);\n }\n \n-void list_all_main_cmds(void)\n+void list_all_main_cmds(struct string_list *list)\n {\n \tstruct cmdnames main_cmds, other_cmds;\n \tint i;\n@@ -320,13 +320,13 @@ void list_all_main_cmds(void)\n \tload_command_list(\"git-\", &main_cmds, &other_cmds);\n \n \tfor (i = 0; i < main_cmds.cnt; i++)\n-\t\tputs(main_cmds.names[i]->name);\n+\t\tstring_list_append(list, main_cmds.names[i]->name);\n \n \tclean_cmdnames(&main_cmds);\n \tclean_cmdnames(&other_cmds);\n }\n \n-void list_all_other_cmds(void)\n+void list_all_other_cmds(struct string_list *list)\n {\n \tstruct cmdnames main_cmds, other_cmds;\n \tint i;\n@@ -336,13 +336,14 @@ void list_all_other_cmds(void)\n \tload_command_list(\"git-\", &main_cmds, &other_cmds);\n \n \tfor (i = 0; i < other_cmds.cnt; i++)\n-\t\tputs(other_cmds.names[i]->name);\n+\t\tstring_list_append(list, other_cmds.names[i]->name);\n \n \tclean_cmdnames(&main_cmds);\n \tclean_cmdnames(&other_cmds);\n }\n \n-void list_cmds_by_category(const char *cat)\n+void list_cmds_by_category(struct string_list *list,\n+\t\t\t   const char *cat)\n {\n \tint i, n = ARRAY_SIZE(command_list);\n \tuint32_t cat_id = 0;\n@@ -359,8 +360,42 @@ void list_cmds_by_category(const char *cat)\n \tfor (i = 0; i < n; i++) {\n \t\tstruct cmdname_help *cmd = command_list + i;\n \n-\t\tif (cmd->category & cat_id)\n-\t\t\tputs(drop_prefix(cmd->name, cmd->category));\n+\t\tif (!(cmd->category & cat_id))\n+\t\t\tcontinue;\n+\t\tstring_list_append(list, drop_prefix(cmd->name, cmd->category));\n+\t}\n+}\n+\n+void list_cmds_by_config(struct string_list *list)\n+{\n+\tconst char *cmd_list;\n+\n+\t/*\n+\t * There's no actual repository setup at this point (and even\n+\t * if there is, we don't really care; only global config\n+\t * matters). If we accidentally set up a repository, it's ok\n+\t * too since the caller (git --list-cmds=) should exit shortly\n+\t * anyway.\n+\t */\n+\tif (git_config_get_string_const(\"completion.commands\", &cmd_list))\n+\t\treturn;\n+\n+\tstring_list_sort(list);\n+\tstring_list_remove_duplicates(list, 0);\n+\n+\twhile (*cmd_list) {\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\t\tconst char *p = strchrnul(cmd_list, ' ');\n+\n+\t\tstrbuf_add(&sb, cmd_list, p - cmd_list);\n+\t\tif (*cmd_list == '-')\n+\t\t\tstring_list_remove(list, cmd_list + 1, 0);\n+\t\telse\n+\t\t\tstring_list_insert(list, sb.buf);\n+\t\tstrbuf_release(&sb);\n+\t\twhile (*p == ' ')\n+\t\t\tp++;\n+\t\tcmd_list = p;\n \t}\n }\n \ndiff --git a/help.h b/help.h\nindex 5d27368fe4..3b38292a1b 100644\n--- a/help.h\n+++ b/help.h\n@@ -1,6 +1,8 @@\n #ifndef HELP_H\n #define HELP_H\n \n+struct string_list;\n+\n struct cmdnames {\n \tint alloc;\n \tint cnt;\n@@ -19,9 +21,12 @@ static inline void mput_char(char c, unsigned int num)\n extern void list_common_cmds_help(void);\n extern void list_all_cmds_help(void);\n extern void list_common_guides_help(void);\n-extern void list_all_main_cmds(void);\n-extern void list_all_other_cmds(void);\n-extern void list_cmds_by_category(const char *category);\n+\n+extern void list_all_main_cmds(struct string_list *list);\n+extern void list_all_other_cmds(struct string_list *list);\n+extern void list_cmds_by_category(struct string_list *list,\n+\t\t\t\t  const char *category);\n+extern void list_cmds_by_config(struct string_list *list);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\n\nNguyễn Thái Ngọc Duy (13):\n  generate-cmds.sh: factor out synopsis extract code\n  generate-cmds.sh: export all commands to command-list.h\n  help: use command-list.h for common command list\n  Remove common-cmds.h\n  git.c: convert --list-* to --list-cmds=*\n  git --list-cmds: collect command list in a string_list\n  completion: implement and use --list-cmds=main,others\n  git: support --list-cmds=list-<category>\n  help: add \"-a --verbose\" to list all commands with synopsis\n  help: use command-list.txt for the source of guides\n  command-list.txt: documentation and guide line\n  completion: let git provide the completable command list\n  completion: allow to customize the completable command list\n\n .gitignore                             |   2 +-\n Documentation/git-help.txt             |   4 +-\n Documentation/gitattributes.txt        |   2 +-\n Documentation/gitmodules.txt           |   2 +-\n Documentation/gitrevisions.txt         |   2 +-\n Makefile                               |  16 +-\n builtin/help.c                         |  39 +---\n command-list.txt                       | 111 ++++++++---\n contrib/completion/git-completion.bash | 169 ++++++++---------\n generate-cmdlist.sh                    | 126 ++++++++-----\n git.c                                  |  61 ++++++-\n help.c                                 | 244 ++++++++++++++++++++++---\n help.h                                 |  10 +\n t/t0012-help.sh                        |  26 ++-\n t/t9902-completion.sh                  |   5 +-\n 15 files changed, 565 insertions(+), 254 deletions(-)\n\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"346887","messageId":"20180507175222.12114-2-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180507175222.12114-1-pclouds@gmail.com","subject":"[PATCH v6 01/13] generate-cmds.sh: factor out synopsis extract code","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-07T17:52:10Z","receivedAt":"2018-05-07T17:53:07Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This makes it easier to reuse the same code in another place (very\nsoon).\n---\n generate-cmdlist.sh | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex eeea4b67ea..31b6d886cb 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -1,5 +1,15 @@\n #!/bin/sh\n \n+get_synopsis () {\n+\tsed -n '\n+\t\t/^NAME/,/'\"$1\"'/H\n+\t\t${\n+\t\t\tx\n+\t\t\ts/.*'\"$1\"' - \\(.*\\)/N_(\"\\1\")/\n+\t\t\tp\n+\t\t}' \"Documentation/$1.txt\"\n+}\n+\n echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n \tchar name[16];\n@@ -39,12 +49,6 @@ sort |\n while read cmd tags\n do\n \ttag=$(echo \"$tags\" | sed \"$substnum; s/[^0-9]//g\")\n-\tsed -n '\n-\t\t/^NAME/,/git-'\"$cmd\"'/H\n-\t\t${\n-\t\t\tx\n-\t\t\ts/.*git-'\"$cmd\"' - \\(.*\\)/\t{\"'\"$cmd\"'\", N_(\"\\1\"), '$tag'},/\n-\t\t\tp\n-\t\t}' \"Documentation/git-$cmd.txt\"\n+\techo \"\t{\\\"$cmd\\\", $(get_synopsis git-$cmd), $tag},\"\n done\n echo \"};\"\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"346888","messageId":"20180507175222.12114-3-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180507175222.12114-1-pclouds@gmail.com","subject":"[PATCH v6 02/13] generate-cmds.sh: export all commands to command-list.h","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-07T17:52:11Z","receivedAt":"2018-05-07T17:53:08Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The current generate-cmds.sh generates just enough to print \"git help\"\noutput. That is, it only extracts help text for common commands.\n\nThe script is now updated to extract help text for all commands and\nkeep command classification a new file, command-list.h. This will be\nuseful later:\n\n- \"git help -a\" could print a short summary of all commands instead of\n  just the common ones.\n\n- \"git\" could produce a list of commands of one or more category. One\n  of its use is to reduce another command classification embedded in\n  git-completion.bash.\n\nThe new file can be generated but is not used anywhere yet. The plan\nis we migrate away from common-cmds.h. Then we can kill off\ncommon-cmds.h build rules and generation code (and also delete\nduplicate content in command-list.h which we keep for now to not mess\ngenerate-cmds.sh up too much).\n\nPS. The new fixed column requirement on command-list.txt is\ntechnically not needed. But it helps simplify the code a bit at this\nstage. We could lift this restriction later if we want to.\n---\n .gitignore          |  1 +\n Makefile            | 13 ++++++---\n command-list.txt    |  4 +--\n generate-cmdlist.sh | 67 ++++++++++++++++++++++++++++++++++++++++++---\n 4 files changed, 75 insertions(+), 10 deletions(-)\n\ndiff --git a/.gitignore b/.gitignore\nindex 833ef3b0b7..d4c3914167 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -180,6 +180,7 @@\n /gitweb/static/gitweb.js\n /gitweb/static/gitweb.min.*\n /common-cmds.h\n+/command-list.h\n *.tar.gz\n *.dsc\n *.deb\ndiff --git a/Makefile b/Makefile\nindex f181687250..2a8913ea21 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -757,7 +757,7 @@ LIB_FILE = libgit.a\n XDIFF_LIB = xdiff/lib.a\n VCSSVN_LIB = vcs-svn/lib.a\n \n-GENERATED_H += common-cmds.h\n+GENERATED_H += common-cmds.h command-list.h\n \n LIB_H = $(shell $(FIND) . \\\n \t-name .git -prune -o \\\n@@ -1938,6 +1938,11 @@ $(BUILT_INS): git$X\n common-cmds.h: generate-cmdlist.sh command-list.txt\n \n common-cmds.h: $(wildcard Documentation/git-*.txt)\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt COMMON >$@+ && mv $@+ $@\n+\n+command-list.h: generate-cmdlist.sh command-list.txt\n+\n+command-list.h: $(wildcard Documentation/git-*.txt)\n \t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt >$@+ && mv $@+ $@\n \n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n@@ -2148,7 +2153,7 @@ else\n # Dependencies on header files, for platforms that do not support\n # the gcc -MMD option.\n #\n-# Dependencies on automatically generated headers such as common-cmds.h\n+# Dependencies on automatically generated headers such as common-cmds.h or command-list.h\n # should _not_ be included here, since they are necessary even when\n # building an object for the first time.\n \n@@ -2527,7 +2532,7 @@ sparse: $(SP_OBJ)\n style:\n \tgit clang-format --style file --diff --extensions c,h\n \n-check: common-cmds.h\n+check: common-cmds.h command-list.h\n \t@if sparse; \\\n \tthen \\\n \t\techo >&2 \"Use 'make sparse' instead\"; \\\n@@ -2775,7 +2780,7 @@ clean: profile-clean coverage-clean\n \t$(RM) $(TEST_PROGRAMS) $(NO_INSTALL)\n \t$(RM) -r bin-wrappers $(dep_dirs)\n \t$(RM) -r po/build/\n-\t$(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h $(ETAGS_TARGET) tags cscope*\n+\t$(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h command-list.h $(ETAGS_TARGET) tags cscope*\n \t$(RM) -r $(GIT_TARNAME) .doc-tmp-dir\n \t$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz\n \t$(RM) $(htmldocs).tar.gz $(manpages).tar.gz\ndiff --git a/command-list.txt b/command-list.txt\nindex a1fad28fd8..786536aba0 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -8,8 +8,8 @@ info         examine the history and state (see also: git help revisions)\n history      grow, mark and tweak your common history\n remote       collaborate (see also: git help workflows)\n \n-### command list (do not change this line)\n-# command name                          category [deprecated] [common]\n+### command list (do not change this line, also do not change alignment)\n+# command name                          category [category] [category]\n git-add                                 mainporcelain           worktree\n git-am                                  mainporcelain\n git-annotate                            ancillaryinterrogators\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 31b6d886cb..c9fd524760 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -1,5 +1,27 @@\n #!/bin/sh\n \n+die () {\n+\techo \"$@\" >&2\n+\texit 1\n+}\n+\n+command_list () {\n+\tsed '1,/^### command list/d;/^#/d' \"$1\"\n+}\n+\n+get_categories() {\n+\ttr ' ' '\\n'|\n+\tgrep -v '^$' |\n+\tsort |\n+\tuniq\n+}\n+\n+category_list () {\n+\tcommand_list \"$1\" |\n+\tcut -c 40- |\n+\tget_categories\n+}\n+\n get_synopsis () {\n \tsed -n '\n \t\t/^NAME/,/'\"$1\"'/H\n@@ -10,14 +32,51 @@ get_synopsis () {\n \t\t}' \"Documentation/$1.txt\"\n }\n \n+define_categories() {\n+\techo\n+\techo \"/* Command categories */\"\n+\tbit=0\n+\tcategory_list \"$1\" |\n+\twhile read cat\n+\tdo\n+\t\techo \"#define CAT_$cat (1UL << $bit)\"\n+\t\tbit=$(($bit+1))\n+\tdone\n+\ttest \"$bit\" -gt 32 && die \"Urgh.. too many categories?\"\n+}\n+\n+print_command_list() {\n+\techo \"static struct cmdname_help command_list[] = {\"\n+\n+\tcommand_list \"$1\" |\n+\twhile read cmd rest\n+\tdo\n+\t\tprintf \"\t{ \\\"$cmd\\\", $(get_synopsis $cmd), 0\"\n+\t\tfor cat in $(echo \"$rest\" | get_categories)\n+\t\tdo\n+\t\t\tprintf \" | CAT_$cat\"\n+\t\tdone\n+\t\techo \" },\"\n+\tdone\n+\techo \"};\"\n+}\n+\n echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n-\tchar name[16];\n-\tchar help[80];\n-\tunsigned char group;\n+\tconst char *name;\n+\tconst char *help;\n+\tuint32_t group;\n };\n+\"\n+if [ -z \"$2\" ]\n+then\n+\tdefine_categories \"$1\"\n+\techo\n+\tprint_command_list \"$1\"\n+\texit 0\n+fi\n \n-static const char *common_cmd_groups[] = {\"\n+echo \"static const char *common_cmd_groups[] = {\"\n \n grps=grps$$.tmp\n match=match$$.tmp\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"346889","messageId":"20180507175222.12114-5-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180507175222.12114-1-pclouds@gmail.com","subject":"[PATCH v6 04/13] Remove common-cmds.h","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-07T17:52:13Z","receivedAt":"2018-05-07T17:53:11Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"After the last patch, common-cmds.h is no longer used (and it was\nactually broken). Remove all related code. command-list.h will take\nits place from now on.\n---\n .gitignore          |  1 -\n Makefile            | 17 ++++++-----------\n generate-cmdlist.sh | 46 +++------------------------------------------\n 3 files changed, 9 insertions(+), 55 deletions(-)\n\ndiff --git a/.gitignore b/.gitignore\nindex d4c3914167..0836083992 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -179,7 +179,6 @@\n /gitweb/gitweb.cgi\n /gitweb/static/gitweb.js\n /gitweb/static/gitweb.min.*\n-/common-cmds.h\n /command-list.h\n *.tar.gz\n *.dsc\ndiff --git a/Makefile b/Makefile\nindex 5c58b0b692..a60a78ee67 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -757,7 +757,7 @@ LIB_FILE = libgit.a\n XDIFF_LIB = xdiff/lib.a\n VCSSVN_LIB = vcs-svn/lib.a\n \n-GENERATED_H += common-cmds.h command-list.h\n+GENERATED_H += command-list.h\n \n LIB_H = $(shell $(FIND) . \\\n \t-name .git -prune -o \\\n@@ -1914,9 +1914,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \\\n \t\t$(filter %.o,$^) $(LIBS)\n \n-help.sp help.s help.o: common-cmds.h command-list.h\n+help.sp help.s help.o: command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h command-list.h GIT-PREFIX\n+builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n@@ -1935,11 +1935,6 @@ $(BUILT_INS): git$X\n \tln -s $< $@ 2>/dev/null || \\\n \tcp $< $@\n \n-common-cmds.h: generate-cmdlist.sh command-list.txt\n-\n-common-cmds.h: $(wildcard Documentation/git-*.txt)\n-\t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt COMMON >$@+ && mv $@+ $@\n-\n command-list.h: generate-cmdlist.sh command-list.txt\n \n command-list.h: $(wildcard Documentation/git-*.txt)\n@@ -2153,7 +2148,7 @@ else\n # Dependencies on header files, for platforms that do not support\n # the gcc -MMD option.\n #\n-# Dependencies on automatically generated headers such as common-cmds.h or command-list.h\n+# Dependencies on automatically generated headers such as command-list.h\n # should _not_ be included here, since they are necessary even when\n # building an object for the first time.\n \n@@ -2532,7 +2527,7 @@ sparse: $(SP_OBJ)\n style:\n \tgit clang-format --style file --diff --extensions c,h\n \n-check: common-cmds.h command-list.h\n+check: command-list.h\n \t@if sparse; \\\n \tthen \\\n \t\techo >&2 \"Use 'make sparse' instead\"; \\\n@@ -2780,7 +2775,7 @@ clean: profile-clean coverage-clean\n \t$(RM) $(TEST_PROGRAMS) $(NO_INSTALL)\n \t$(RM) -r bin-wrappers $(dep_dirs)\n \t$(RM) -r po/build/\n-\t$(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h command-list.h $(ETAGS_TARGET) tags cscope*\n+\t$(RM) *.pyc *.pyo */*.pyc */*.pyo command-list.h $(ETAGS_TARGET) tags cscope*\n \t$(RM) -r $(GIT_TARNAME) .doc-tmp-dir\n \t$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz\n \t$(RM) $(htmldocs).tar.gz $(manpages).tar.gz\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 93de8e8f59..015eef2804 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -68,46 +68,6 @@ struct cmdname_help {\n \tuint32_t category;\n };\n \"\n-if [ -z \"$2\" ]\n-then\n-\tdefine_categories \"$1\"\n-\techo\n-\tprint_command_list \"$1\"\n-\texit 0\n-fi\n-\n-echo \"static const char *common_cmd_groups[] = {\"\n-\n-grps=grps$$.tmp\n-match=match$$.tmp\n-trap \"rm -f '$grps' '$match'\" 0 1 2 3 15\n-\n-sed -n '\n-\t1,/^### common groups/b\n-\t/^### command list/q\n-\t/^#/b\n-\t/^[ \t]*$/b\n-\th;s/^[^ \t][^ \t]*[ \t][ \t]*\\(.*\\)/\tN_(\"\\1\"),/p\n-\tg;s/^\\([^ \t][^ \t]*\\)[ \t].*/\\1/w '$grps'\n-\t' \"$1\"\n-printf '};\\n\\n'\n-\n-n=0\n-substnum=\n-while read grp\n-do\n-\techo \"^git-..*[ \t]$grp\"\n-\tsubstnum=\"$substnum${substnum:+;}s/[ \t]$grp/$n/\"\n-\tn=$(($n+1))\n-done <\"$grps\" >\"$match\"\n-\n-printf 'static struct cmdname_help common_cmds[] = {\\n'\n-grep -f \"$match\" \"$1\" |\n-sed 's/^git-//' |\n-sort |\n-while read cmd tags\n-do\n-\ttag=$(echo \"$tags\" | sed \"$substnum; s/[^0-9]//g\")\n-\techo \"\t{\\\"$cmd\\\", $(get_synopsis git-$cmd), $tag},\"\n-done\n-echo \"};\"\n+define_categories \"$1\"\n+echo\n+print_command_list \"$1\"\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"346890","messageId":"20180507175222.12114-7-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180507175222.12114-1-pclouds@gmail.com","subject":"[PATCH v6 06/13] git --list-cmds: collect command list in a string_list","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-07T17:52:15Z","receivedAt":"2018-05-07T17:53:14Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Instead of printing the command directly one by one, keep them in a\nlist and print at the end. This allows more modification before we\nprint out (e.g. sorting, removing duplicates or even excluding some\nitems).\n---\n git.c | 22 +++++++++++++++++-----\n 1 file changed, 17 insertions(+), 5 deletions(-)\n\ndiff --git a/git.c b/git.c\nindex b2842a22e2..a0477c459e 100644\n--- a/git.c\n+++ b/git.c\n@@ -36,22 +36,28 @@ const char git_more_info_string[] =\n \n static int use_pager = -1;\n \n-static void list_builtins(unsigned int exclude_option, char sep);\n+static void list_builtins(struct string_list *list, unsigned int exclude_option);\n \n static int list_cmds(const char *spec)\n {\n+\tstruct string_list list = STRING_LIST_INIT_DUP;\n+\tint i;\n+\n \twhile (*spec) {\n \t\tconst char *sep = strchrnul(spec, ',');\n \t\tint len = sep - spec;\n \n \t\tif (len == 8 && !strncmp(spec, \"builtins\", 8))\n-\t\t\tlist_builtins(0, '\\n');\n+\t\t\tlist_builtins(&list, 0);\n \t\telse\n \t\t\tdie(_(\"unsupported command listing type '%s'\"), spec);\n \t\tspec += len;\n \t\tif (*spec == ',')\n \t\t\tspec++;\n \t}\n+\tfor (i = 0; i < list.nr; i++)\n+\t\tputs(list.items[i].string);\n+\tstring_list_clear(&list, 0);\n \treturn 0;\n }\n \n@@ -242,7 +248,13 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t(*argc)--;\n \t\t} else if (skip_prefix(cmd, \"--list-cmds=\", &cmd)) {\n \t\t\tif (!strcmp(cmd, \"parseopt\")) {\n-\t\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n+\t\t\t\tstruct string_list list = STRING_LIST_INIT_DUP;\n+\t\t\t\tint i;\n+\n+\t\t\t\tlist_builtins(&list, NO_PARSEOPT);\n+\t\t\t\tfor (i = 0; i < list.nr; i++)\n+\t\t\t\t\tprintf(\"%s \", list.items[i].string);\n+\t\t\t\tstring_list_clear(&list, 0);\n \t\t\t\texit(0);\n \t\t\t} else {\n \t\t\t\texit(list_cmds(cmd));\n@@ -526,14 +538,14 @@ int is_builtin(const char *s)\n \treturn !!get_builtin(s);\n }\n \n-static void list_builtins(unsigned int exclude_option, char sep)\n+static void list_builtins(struct string_list *out, unsigned int exclude_option)\n {\n \tint i;\n \tfor (i = 0; i < ARRAY_SIZE(commands); i++) {\n \t\tif (exclude_option &&\n \t\t    (commands[i].option & exclude_option))\n \t\t\tcontinue;\n-\t\tprintf(\"%s%c\", commands[i].cmd, sep);\n+\t\tstring_list_append(out, commands[i].cmd);\n \t}\n }\n \n-- \n2.17.0.705.g3525833791\n\n"},{"id":"346891","messageId":"20180507175222.12114-8-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180507175222.12114-1-pclouds@gmail.com","subject":"[PATCH v6 07/13] completion: implement and use --list-cmds=main,others","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-07T17:52:16Z","receivedAt":"2018-05-07T17:53:17Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Instead of parsing \"git help -a\" output, which is tricky to get right,\nless elegant and also slow, make git provide the list in a\nmachine-friendly form. This adds two separate listing types, main and\nothers, instead of just \"all\" for more flexibility.\n---\n contrib/completion/git-completion.bash |  2 +-\n git.c                                  |  4 ++++\n help.c                                 | 32 ++++++++++++++++++++++++++\n help.h                                 |  4 ++++\n 4 files changed, 41 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 3556838759..62ca8641f4 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -839,7 +839,7 @@ __git_commands () {\n \tthen\n \t\tprintf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n \telse\n-\t\tgit help -a|egrep '^  [a-zA-Z0-9]'\n+\t\tgit --list-cmds=main,others\n \tfi\n }\n \ndiff --git a/git.c b/git.c\nindex a0477c459e..3c032d01fc 100644\n--- a/git.c\n+++ b/git.c\n@@ -49,6 +49,10 @@ static int list_cmds(const char *spec)\n \n \t\tif (len == 8 && !strncmp(spec, \"builtins\", 8))\n \t\t\tlist_builtins(&list, 0);\n+\t\telse if (len == 4 && !strncmp(spec, \"main\", 4))\n+\t\t\tlist_all_main_cmds(&list);\n+\t\telse if (len == 6 && !strncmp(spec, \"others\", 6))\n+\t\t\tlist_all_other_cmds(&list);\n \t\telse\n \t\t\tdie(_(\"unsupported command listing type '%s'\"), spec);\n \t\tspec += len;\ndiff --git a/help.c b/help.c\nindex 2d6a3157f8..d5ce9dfcbb 100644\n--- a/help.c\n+++ b/help.c\n@@ -297,6 +297,38 @@ void list_common_cmds_help(void)\n \tprint_cmd_by_category(common_categories);\n }\n \n+void list_all_main_cmds(struct string_list *list)\n+{\n+\tstruct cmdnames main_cmds, other_cmds;\n+\tint i;\n+\n+\tmemset(&main_cmds, 0, sizeof(main_cmds));\n+\tmemset(&other_cmds, 0, sizeof(other_cmds));\n+\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n+\n+\tfor (i = 0; i < main_cmds.cnt; i++)\n+\t\tstring_list_append(list, main_cmds.names[i]->name);\n+\n+\tclean_cmdnames(&main_cmds);\n+\tclean_cmdnames(&other_cmds);\n+}\n+\n+void list_all_other_cmds(struct string_list *list)\n+{\n+\tstruct cmdnames main_cmds, other_cmds;\n+\tint i;\n+\n+\tmemset(&main_cmds, 0, sizeof(main_cmds));\n+\tmemset(&other_cmds, 0, sizeof(other_cmds));\n+\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n+\n+\tfor (i = 0; i < other_cmds.cnt; i++)\n+\t\tstring_list_append(list, other_cmds.names[i]->name);\n+\n+\tclean_cmdnames(&main_cmds);\n+\tclean_cmdnames(&other_cmds);\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex b21d7c94e8..97e6c0965e 100644\n--- a/help.h\n+++ b/help.h\n@@ -1,6 +1,8 @@\n #ifndef HELP_H\n #define HELP_H\n \n+struct string_list;\n+\n struct cmdnames {\n \tint alloc;\n \tint cnt;\n@@ -17,6 +19,8 @@ static inline void mput_char(char c, unsigned int num)\n }\n \n extern void list_common_cmds_help(void);\n+extern void list_all_main_cmds(struct string_list *list);\n+extern void list_all_other_cmds(struct string_list *list);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"346892","messageId":"20180507175222.12114-6-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180507175222.12114-1-pclouds@gmail.com","subject":"[PATCH v6 05/13] git.c: convert --list-* to --list-cmds=*","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-07T17:52:14Z","receivedAt":"2018-05-07T17:53:20Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Even if these are hidden options, let's make them a bit more generic\nsince we're introducing more listing types shortly. The code is\nstructured to allow combining multiple listing types together because\nwe will soon add more types the 'builtins'.\n\n'parseopt' remains separate because it has separate (SPC) to match\ngit-completion.bash needs and will not combine with others.\n---\n contrib/completion/git-completion.bash |  2 +-\n git.c                                  | 30 ++++++++++++++++++++------\n t/t0012-help.sh                        |  2 +-\n 3 files changed, 26 insertions(+), 8 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex a757073945..3556838759 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -3049,7 +3049,7 @@ __git_complete_common () {\n __git_cmds_with_parseopt_helper=\n __git_support_parseopt_helper () {\n \ttest -n \"$__git_cmds_with_parseopt_helper\" ||\n-\t\t__git_cmds_with_parseopt_helper=\"$(__git --list-parseopt-builtins)\"\n+\t\t__git_cmds_with_parseopt_helper=\"$(__git --list-cmds=parseopt)\"\n \n \tcase \" $__git_cmds_with_parseopt_helper \" in\n \t*\" $1 \"*)\ndiff --git a/git.c b/git.c\nindex 3a89893712..b2842a22e2 100644\n--- a/git.c\n+++ b/git.c\n@@ -38,6 +38,23 @@ static int use_pager = -1;\n \n static void list_builtins(unsigned int exclude_option, char sep);\n \n+static int list_cmds(const char *spec)\n+{\n+\twhile (*spec) {\n+\t\tconst char *sep = strchrnul(spec, ',');\n+\t\tint len = sep - spec;\n+\n+\t\tif (len == 8 && !strncmp(spec, \"builtins\", 8))\n+\t\t\tlist_builtins(0, '\\n');\n+\t\telse\n+\t\t\tdie(_(\"unsupported command listing type '%s'\"), spec);\n+\t\tspec += len;\n+\t\tif (*spec == ',')\n+\t\t\tspec++;\n+\t}\n+\treturn 0;\n+}\n+\n static void commit_pager_choice(void) {\n \tswitch (use_pager) {\n \tcase 0:\n@@ -223,12 +240,13 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t}\n \t\t\t(*argv)++;\n \t\t\t(*argc)--;\n-\t\t} else if (!strcmp(cmd, \"--list-builtins\")) {\n-\t\t\tlist_builtins(0, '\\n');\n-\t\t\texit(0);\n-\t\t} else if (!strcmp(cmd, \"--list-parseopt-builtins\")) {\n-\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n-\t\t\texit(0);\n+\t\t} else if (skip_prefix(cmd, \"--list-cmds=\", &cmd)) {\n+\t\t\tif (!strcmp(cmd, \"parseopt\")) {\n+\t\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n+\t\t\t\texit(0);\n+\t\t\t} else {\n+\t\t\t\texit(list_cmds(cmd));\n+\t\t\t}\n \t\t} else {\n \t\t\tfprintf(stderr, _(\"unknown option: %s\\n\"), cmd);\n \t\t\tusage(git_usage_string);\ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex c096f33505..3c91a9024a 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -59,7 +59,7 @@ test_expect_success 'git help' '\n '\n \n test_expect_success 'generate builtin list' '\n-\tgit --list-builtins >builtins\n+\tgit --list-cmds=builtins >builtins\n '\n \n while read builtin\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"346893","messageId":"20180507175222.12114-10-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180507175222.12114-1-pclouds@gmail.com","subject":"[PATCH v6 09/13] help: add \"-a --verbose\" to list all commands with synopsis","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-07T17:52:18Z","receivedAt":"2018-05-07T17:53:22Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This lists all recognized commands [1] by category. The group order\nfollows closely git.txt.\n\n[1] We may actually show commands that are not built (e.g. if you set\nNO_PERL you don't have git-instaweb but it's still listed here). I\nignore the problem because on Linux a git package could be split\nanyway. The \"git-core\" package may not contain git-instaweb even if\nit's built because it may end up in a separate package. We can't know\nanyway.\n---\n Documentation/git-help.txt |  4 +++-\n builtin/help.c             |  7 +++++++\n help.c                     | 16 ++++++++++++++++\n help.h                     |  2 ++\n t/t0012-help.sh            |  9 +++++++++\n 5 files changed, 37 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-help.txt b/Documentation/git-help.txt\nindex 40d328a4b3..a40fc38d8b 100644\n--- a/Documentation/git-help.txt\n+++ b/Documentation/git-help.txt\n@@ -8,7 +8,7 @@ git-help - Display help information about Git\n SYNOPSIS\n --------\n [verse]\n-'git help' [-a|--all] [-g|--guide]\n+'git help' [-a|--all [--verbose]] [-g|--guide]\n \t   [-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE]\n \n DESCRIPTION\n@@ -42,6 +42,8 @@ OPTIONS\n --all::\n \tPrints all the available commands on the standard output. This\n \toption overrides any given command or guide name.\n+\tWhen used with `--verbose` print description for all recognized\n+\tcommands.\n \n -g::\n --guides::\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 598867cfea..0e0af8426a 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -36,6 +36,7 @@ static const char *html_path;\n \n static int show_all = 0;\n static int show_guides = 0;\n+static int verbose;\n static unsigned int colopts;\n static enum help_format help_format = HELP_FORMAT_NONE;\n static int exclude_guides;\n@@ -48,6 +49,7 @@ static struct option builtin_help_options[] = {\n \t\t\tHELP_FORMAT_WEB),\n \tOPT_SET_INT('i', \"info\", &help_format, N_(\"show info page\"),\n \t\t\tHELP_FORMAT_INFO),\n+\tOPT__VERBOSE(&verbose, N_(\"print command description\")),\n \tOPT_END(),\n };\n \n@@ -463,6 +465,11 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \tif (show_all) {\n \t\tgit_config(git_help_config, NULL);\n+\t\tif (verbose) {\n+\t\t\tsetup_pager();\n+\t\t\tlist_all_cmds_help();\n+\t\t\treturn 0;\n+\t\t}\n \t\tprintf(_(\"usage: %s%s\"), _(git_usage_string), \"\\n\\n\");\n \t\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n \t\tlist_commands(colopts, &main_cmds, &other_cmds);\ndiff --git a/help.c b/help.c\nindex 1117f7d1d1..c7df1d2338 100644\n--- a/help.c\n+++ b/help.c\n@@ -27,6 +27,17 @@ static struct category_description common_categories[] = {\n \t{ CAT_remote, N_(\"collaborate (see also: git help workflows)\") },\n \t{ 0, NULL }\n };\n+static struct category_description main_categories[] = {\n+\t{ CAT_mainporcelain, N_(\"Main Porcelain Commands\") },\n+\t{ CAT_ancillarymanipulators, N_(\"Ancillary Commands / Manipulators\") },\n+\t{ CAT_ancillaryinterrogators, N_(\"Ancillary Commands / Interrogators\") },\n+\t{ CAT_foreignscminterface, N_(\"Interacting with Others\") },\n+\t{ CAT_plumbingmanipulators, N_(\"Low-level Commands / Manipulators\") },\n+\t{ CAT_plumbinginterrogators, N_(\"Low-level Commands / Interrogators\") },\n+\t{ CAT_synchingrepositories, N_(\"Low-level Commands / Synching Repositories\") },\n+\t{ CAT_purehelpers, N_(\"Low-level Commands / Internal Helpers\") },\n+\t{ 0, NULL }\n+};\n \n static const char *drop_prefix(const char *name)\n {\n@@ -352,6 +363,11 @@ void list_cmds_by_category(struct string_list *list,\n \t}\n }\n \n+void list_all_cmds_help(void)\n+{\n+\tprint_cmd_by_category(main_categories);\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex 734bba32d3..40917fc38c 100644\n--- a/help.h\n+++ b/help.h\n@@ -19,6 +19,8 @@ static inline void mput_char(char c, unsigned int num)\n }\n \n extern void list_common_cmds_help(void);\n+extern void list_all_cmds_help(void);\n+\n extern void list_all_main_cmds(struct string_list *list);\n extern void list_all_other_cmds(struct string_list *list);\n extern void list_cmds_by_category(struct string_list *list,\ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex 3c91a9024a..060df24c2d 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -25,6 +25,15 @@ test_expect_success \"setup\" '\n \tEOF\n '\n \n+# make sure to exercise these code paths, the output is a bit tricky\n+# to verify\n+test_expect_success 'basic help commands' '\n+\tgit help >/dev/null &&\n+\tgit help -a >/dev/null &&\n+\tgit help -g >/dev/null &&\n+\tgit help -av >/dev/null\n+'\n+\n test_expect_success \"works for commands and guides by default\" '\n \tconfigure_help &&\n \tgit help status &&\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"346894","messageId":"20180507175222.12114-13-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180507175222.12114-1-pclouds@gmail.com","subject":"[PATCH v6 12/13] completion: let git provide the completable command list","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-07T17:52:21Z","receivedAt":"2018-05-07T17:53:23Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Instead of maintaining a separate list of command classification,\nwhich often could go out of date, let's centralize the information\nback in git.\n\nWhile the function in git-completion.bash implies \"list porcelain\ncommands\", that's not exactly what it does. It gets all commands (aka\n--list-cmds=main,others) then exclude certain non-porcelain ones. We\ncould almost recreate this list two lists list-mainporcelain and\nothers. The non-porcelain-but-included-anyway is added by the third\ncategory list-complete.\n\nlist-complete does not recreate exactly the command list before this\npatch though. The following commands are not part of neither\nlist-mainporcelain nor list-complete and as a result no longer\ncompletes:\n\n- annotate             obsolete, discouraged to use\n- difftool-helper      not an end user command\n- filter-branch        not often used\n- get-tar-commit-id    not often used\n- imap-send            not often used\n- interpreter-trailers not for interactive use\n- lost-found           obsolete\n- p4                   too short and probably not often used (*)\n- peek-remote          deprecated\n- svn                  same category as p4 (*)\n- tar-tree             obsolete\n- verify-commit        not often used\n\nNote that the current completion script incorrectly classifies\nfilter-branch as porcelain and t9902 tests this behavior. We keep it\nthis way in t9902 because this test does not really care which\nparticular command is porcelain or plubmbing, they're just names.\n\n(*) to be fair, send-email command which is in the same\nforeignscminterface group as svn and p4 does get completion, just\nbecause it's used by git and kernel development. So maybe should\ninclude them.\n---\n command-list.txt                       |  37 ++++----\n contrib/completion/git-completion.bash | 117 ++++++-------------------\n t/t9902-completion.sh                  |   5 +-\n 3 files changed, 48 insertions(+), 111 deletions(-)\n\ndiff --git a/command-list.txt b/command-list.txt\nindex 9c70c69193..3e21ddfcfb 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -47,11 +47,11 @@\n git-add                                 mainporcelain           worktree\n git-am                                  mainporcelain\n git-annotate                            ancillaryinterrogators\n-git-apply                               plumbingmanipulators\n+git-apply                               plumbingmanipulators            complete\n git-archimport                          foreignscminterface\n git-archive                             mainporcelain\n git-bisect                              mainporcelain           info\n-git-blame                               ancillaryinterrogators\n+git-blame                               ancillaryinterrogators          complete\n git-branch                              mainporcelain           history\n git-bundle                              mainporcelain\n git-cat-file                            plumbinginterrogators\n@@ -61,7 +61,7 @@ git-check-mailmap                       purehelpers\n git-checkout                            mainporcelain           history\n git-checkout-index                      plumbingmanipulators\n git-check-ref-format                    purehelpers\n-git-cherry                              ancillaryinterrogators\n+git-cherry                              ancillaryinterrogators          complete\n git-cherry-pick                         mainporcelain\n git-citool                              mainporcelain\n git-clean                               mainporcelain\n@@ -69,7 +69,7 @@ git-clone                               mainporcelain           init\n git-column                              purehelpers\n git-commit                              mainporcelain           history\n git-commit-tree                         plumbingmanipulators\n-git-config                              ancillarymanipulators\n+git-config                              ancillarymanipulators           complete\n git-count-objects                       ancillaryinterrogators\n git-credential                          purehelpers\n git-credential-cache                    purehelpers\n@@ -83,7 +83,7 @@ git-diff                                mainporcelain           history\n git-diff-files                          plumbinginterrogators\n git-diff-index                          plumbinginterrogators\n git-diff-tree                           plumbinginterrogators\n-git-difftool                            ancillaryinterrogators\n+git-difftool                            ancillaryinterrogators          complete\n git-fast-export                         ancillarymanipulators\n git-fast-import                         ancillarymanipulators\n git-fetch                               mainporcelain           remote\n@@ -92,20 +92,20 @@ git-filter-branch                       ancillarymanipulators\n git-fmt-merge-msg                       purehelpers\n git-for-each-ref                        plumbinginterrogators\n git-format-patch                        mainporcelain\n-git-fsck                                ancillaryinterrogators\n+git-fsck                                ancillaryinterrogators          complete\n git-gc                                  mainporcelain\n git-get-tar-commit-id                   ancillaryinterrogators\n git-grep                                mainporcelain           info\n git-gui                                 mainporcelain\n git-hash-object                         plumbingmanipulators\n-git-help                                ancillaryinterrogators\n+git-help                                ancillaryinterrogators          complete\n git-http-backend                        synchingrepositories\n git-http-fetch                          synchelpers\n git-http-push                           synchelpers\n git-imap-send                           foreignscminterface\n git-index-pack                          plumbingmanipulators\n git-init                                mainporcelain           init\n-git-instaweb                            ancillaryinterrogators\n+git-instaweb                            ancillaryinterrogators          complete\n git-interpret-trailers                  purehelpers\n gitk                                    mainporcelain\n git-log                                 mainporcelain           info\n@@ -119,12 +119,12 @@ git-merge-base                          plumbinginterrogators\n git-merge-file                          plumbingmanipulators\n git-merge-index                         plumbingmanipulators\n git-merge-one-file                      purehelpers\n-git-mergetool                           ancillarymanipulators\n+git-mergetool                           ancillarymanipulators           complete\n git-merge-tree                          ancillaryinterrogators\n git-mktag                               plumbingmanipulators\n git-mktree                              plumbingmanipulators\n git-mv                                  mainporcelain           worktree\n-git-name-rev                            plumbinginterrogators\n+git-name-rev                            plumbinginterrogators           complete\n git-notes                               mainporcelain\n git-p4                                  foreignscminterface\n git-pack-objects                        plumbingmanipulators\n@@ -140,28 +140,29 @@ git-quiltimport                         foreignscminterface\n git-read-tree                           plumbingmanipulators\n git-rebase                              mainporcelain           history\n git-receive-pack                        synchelpers\n-git-reflog                              ancillarymanipulators\n-git-remote                              ancillarymanipulators\n-git-repack                              ancillarymanipulators\n-git-replace                             ancillarymanipulators\n-git-request-pull                        foreignscminterface\n+git-reflog                              ancillarymanipulators           complete\n+git-remote                              ancillarymanipulators           complete\n+git-repack                              ancillarymanipulators           complete\n+git-replace                             ancillarymanipulators           complete\n+git-request-pull                        foreignscminterface             complete\n git-rerere                              ancillaryinterrogators\n git-reset                               mainporcelain           worktree\n git-revert                              mainporcelain\n git-rev-list                            plumbinginterrogators\n git-rev-parse                           ancillaryinterrogators\n git-rm                                  mainporcelain           worktree\n-git-send-email                          foreignscminterface\n+git-send-email                          foreignscminterface             complete\n git-send-pack                           synchingrepositories\n git-shell                               synchelpers\n git-shortlog                            mainporcelain\n git-show                                mainporcelain           info\n-git-show-branch                         ancillaryinterrogators\n+git-show-branch                         ancillaryinterrogators          complete\n git-show-index                          plumbinginterrogators\n git-show-ref                            plumbinginterrogators\n git-sh-i18n                             purehelpers\n git-sh-setup                            purehelpers\n git-stash                               mainporcelain\n+git-stage                                                               complete\n git-status                              mainporcelain           info\n git-stripspace                          purehelpers\n git-submodule                           mainporcelain\n@@ -180,7 +181,7 @@ git-verify-commit                       ancillaryinterrogators\n git-verify-pack                         plumbinginterrogators\n git-verify-tag                          ancillaryinterrogators\n gitweb                                  ancillaryinterrogators\n-git-whatchanged                         ancillaryinterrogators\n+git-whatchanged                         ancillaryinterrogators          complete\n git-worktree                            mainporcelain\n git-write-tree                          plumbingmanipulators\n gitattributes                           guide\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 4e724a5b76..908692ea52 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -835,18 +835,30 @@ __git_complete_strategy ()\n }\n \n __git_commands () {\n-\tif test -n \"${GIT_TESTING_COMMAND_COMPLETION:-}\"\n-\tthen\n-\t\tprintf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n-\telse\n-\t\tgit --list-cmds=main,others\n-\tfi\n+\tcase \"$1\" in\n+\tporcelain)\n+\t\tif test -n \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\"\n+\t\tthen\n+\t\t\tprintf \"%s\" \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\"\n+\t\telse\n+\t\t\tgit --list-cmds=list-mainporcelain,others,list-complete\n+\t\tfi\n+\t\t;;\n+\tall)\n+\t\tif test -n \"$GIT_TESTING_ALL_COMMAND_LIST\"\n+\t\tthen\n+\t\t\tprintf \"%s\" \"$GIT_TESTING_ALL_COMMAND_LIST\"\n+\t\telse\n+\t\t\tgit --list-cmds=main,others\n+\t\tfi\n+\t\t;;\n+\tesac\n }\n \n-__git_list_all_commands ()\n+__git_list_commands ()\n {\n \tlocal i IFS=\" \"$'\\n'\n-\tfor i in $(__git_commands)\n+\tfor i in $(__git_commands $1)\n \tdo\n \t\tcase $i in\n \t\t*--*)             : helper pattern;;\n@@ -855,6 +867,11 @@ __git_list_all_commands ()\n \tdone\n }\n \n+__git_list_all_commands ()\n+{\n+\t__git_list_commands all\n+}\n+\n __git_all_commands=\n __git_compute_all_commands ()\n {\n@@ -864,89 +881,7 @@ __git_compute_all_commands ()\n \n __git_list_porcelain_commands ()\n {\n-\tlocal i IFS=\" \"$'\\n'\n-\t__git_compute_all_commands\n-\tfor i in $__git_all_commands\n-\tdo\n-\t\tcase $i in\n-\t\t*--*)             : helper pattern;;\n-\t\tapplymbox)        : ask gittus;;\n-\t\tapplypatch)       : ask gittus;;\n-\t\tarchimport)       : import;;\n-\t\tcat-file)         : plumbing;;\n-\t\tcheck-attr)       : plumbing;;\n-\t\tcheck-ignore)     : plumbing;;\n-\t\tcheck-mailmap)    : plumbing;;\n-\t\tcheck-ref-format) : plumbing;;\n-\t\tcheckout-index)   : plumbing;;\n-\t\tcolumn)           : internal helper;;\n-\t\tcommit-tree)      : plumbing;;\n-\t\tcount-objects)    : infrequent;;\n-\t\tcredential)       : credentials;;\n-\t\tcredential-*)     : credentials helper;;\n-\t\tcvsexportcommit)  : export;;\n-\t\tcvsimport)        : import;;\n-\t\tcvsserver)        : daemon;;\n-\t\tdaemon)           : daemon;;\n-\t\tdiff-files)       : plumbing;;\n-\t\tdiff-index)       : plumbing;;\n-\t\tdiff-tree)        : plumbing;;\n-\t\tfast-import)      : import;;\n-\t\tfast-export)      : export;;\n-\t\tfsck-objects)     : plumbing;;\n-\t\tfetch-pack)       : plumbing;;\n-\t\tfmt-merge-msg)    : plumbing;;\n-\t\tfor-each-ref)     : plumbing;;\n-\t\thash-object)      : plumbing;;\n-\t\thttp-*)           : transport;;\n-\t\tindex-pack)       : plumbing;;\n-\t\tinit-db)          : deprecated;;\n-\t\tlocal-fetch)      : plumbing;;\n-\t\tls-files)         : plumbing;;\n-\t\tls-remote)        : plumbing;;\n-\t\tls-tree)          : plumbing;;\n-\t\tmailinfo)         : plumbing;;\n-\t\tmailsplit)        : plumbing;;\n-\t\tmerge-*)          : plumbing;;\n-\t\tmktree)           : plumbing;;\n-\t\tmktag)            : plumbing;;\n-\t\tpack-objects)     : plumbing;;\n-\t\tpack-redundant)   : plumbing;;\n-\t\tpack-refs)        : plumbing;;\n-\t\tparse-remote)     : plumbing;;\n-\t\tpatch-id)         : plumbing;;\n-\t\tprune)            : plumbing;;\n-\t\tprune-packed)     : plumbing;;\n-\t\tquiltimport)      : import;;\n-\t\tread-tree)        : plumbing;;\n-\t\treceive-pack)     : plumbing;;\n-\t\tremote-*)         : transport;;\n-\t\trerere)           : plumbing;;\n-\t\trev-list)         : plumbing;;\n-\t\trev-parse)        : plumbing;;\n-\t\trunstatus)        : plumbing;;\n-\t\tsh-setup)         : internal;;\n-\t\tshell)            : daemon;;\n-\t\tshow-ref)         : plumbing;;\n-\t\tsend-pack)        : plumbing;;\n-\t\tshow-index)       : plumbing;;\n-\t\tssh-*)            : transport;;\n-\t\tstripspace)       : plumbing;;\n-\t\tsymbolic-ref)     : plumbing;;\n-\t\tunpack-file)      : plumbing;;\n-\t\tunpack-objects)   : plumbing;;\n-\t\tupdate-index)     : plumbing;;\n-\t\tupdate-ref)       : plumbing;;\n-\t\tupdate-server-info) : daemon;;\n-\t\tupload-archive)   : plumbing;;\n-\t\tupload-pack)      : plumbing;;\n-\t\twrite-tree)       : plumbing;;\n-\t\tvar)              : infrequent;;\n-\t\tverify-pack)      : infrequent;;\n-\t\tverify-tag)       : plumbing;;\n-\t\t*) echo $i;;\n-\t\tesac\n-\tdone\n+\t__git_list_commands porcelain\n }\n \n __git_porcelain_commands=\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 1b34caa1e1..2f16679380 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -13,7 +13,7 @@ complete ()\n \treturn 0\n }\n \n-# Be careful when updating this list:\n+# Be careful when updating these lists:\n #\n # (1) The build tree may have build artifact from different branch, or\n #     the user's $PATH may have a random executable that may begin\n@@ -30,7 +30,8 @@ complete ()\n #     completion for \"git <TAB>\", and a plumbing is excluded.  \"add\",\n #     \"filter-branch\" and \"ls-files\" are listed for this.\n \n-GIT_TESTING_COMMAND_COMPLETION='add checkout check-attr filter-branch ls-files'\n+GIT_TESTING_ALL_COMMAND_LIST='add checkout check-attr filter-branch ls-files'\n+GIT_TESTING_PORCELAIN_COMMAND_LIST='add checkout filter-branch'\n \n . \"$GIT_BUILD_DIR/contrib/completion/git-completion.bash\"\n \n-- \n2.17.0.705.g3525833791\n\n"},{"id":"346895","messageId":"20180507175222.12114-14-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180507175222.12114-1-pclouds@gmail.com","subject":"[PATCH v6 13/13] completion: allow to customize the completable command list","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-07T17:52:22Z","receivedAt":"2018-05-07T17:53:27Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"By default we show porcelain, external commands and a couple others\nthat are also popular. If you are not happy with this list, you can\nnow customize it. See the big comment block for details.\n\nPS. perhaps I should make aliases a group too, which makes it possible\nto _not_ complete aliases by omitting this special group in\n$GIT_COMPLETION_CMD_GROUPS\n---\n contrib/completion/git-completion.bash | 35 ++++++++++++++++++++++++++\n git.c                                  |  2 ++\n help.c                                 | 33 ++++++++++++++++++++++++\n help.h                                 |  1 +\n 4 files changed, 71 insertions(+)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 908692ea52..0fd29803d5 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -38,6 +38,38 @@\n #\n #     When set to \"1\", do not include \"DWIM\" suggestions in git-checkout\n #     completion (e.g., completing \"foo\" when \"origin/foo\" exists).\n+#\n+#   GIT_COMPLETION_CMD_GROUPS\n+#\n+#     When set, \"git --list-cmds=$GIT_COMPLETION_CMD_GROUPS\" will be\n+#     used to get the list of completable commands. The default is\n+#     \"mainporcelain,others,list-complete\" (in English: all porcelain\n+#     commands and external ones are included. Certain non-porcelain\n+#     commands are also marked for completion in command-list.txt).\n+#     You could for example complete all commands with\n+#\n+#         GIT_COMPLETION_CMD_GROUPS=main,others\n+#\n+#     Or you could go with defaults add some extra commands specified\n+#     in the configuration variable completion.commands [1] with\n+#\n+#         GIT_COMPLETION_CMD_GROUPS=mainporcelain,others,list-complete,config\n+#\n+#     Or go completely custom group with\n+#\n+#         GIT_COMPLETION_CMD_GROUPS=config\n+#\n+#     Or you could even play with other command categories found in\n+#     command-list.txt.\n+#\n+#     [1] Note that completion.commands should not be per-repository\n+#         since the command list is generated once and cached.\n+#\n+#         completion.commands could be used to exclude commands as\n+#         well.  If a command in this list begins with '-', then it\n+#         will be excluded from the list of commands gathered by the\n+#         groups specified before \"config\" in\n+#         $GIT_COMPLETION_CMD_GROUPS.\n \n case \"$COMP_WORDBREAKS\" in\n *:*) : great ;;\n@@ -840,6 +872,9 @@ __git_commands () {\n \t\tif test -n \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\"\n \t\tthen\n \t\t\tprintf \"%s\" \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\"\n+\t\telif test -n \"$GIT_COMPLETION_CMD_GROUPS\"\n+\t\tthen\n+\t\t\tgit --list-cmds=\"$GIT_COMPLETION_CMD_GROUPS\"\n \t\telse\n \t\t\tgit --list-cmds=list-mainporcelain,others,list-complete\n \t\tfi\ndiff --git a/git.c b/git.c\nindex 67f3e20ae9..fd08911e11 100644\n--- a/git.c\n+++ b/git.c\n@@ -53,6 +53,8 @@ static int list_cmds(const char *spec)\n \t\t\tlist_all_main_cmds(&list);\n \t\telse if (len == 6 && !strncmp(spec, \"others\", 6))\n \t\t\tlist_all_other_cmds(&list);\n+\t\telse if (len == 6 && !strncmp(spec, \"config\", 6))\n+\t\t\tlist_cmds_by_config(&list);\n \t\telse if (len > 5 && !strncmp(spec, \"list-\", 5)) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n \ndiff --git a/help.c b/help.c\nindex 23924dd300..abf87205b2 100644\n--- a/help.c\n+++ b/help.c\n@@ -366,6 +366,39 @@ void list_cmds_by_category(struct string_list *list,\n \t}\n }\n \n+void list_cmds_by_config(struct string_list *list)\n+{\n+\tconst char *cmd_list;\n+\n+\t/*\n+\t * There's no actual repository setup at this point (and even\n+\t * if there is, we don't really care; only global config\n+\t * matters). If we accidentally set up a repository, it's ok\n+\t * too since the caller (git --list-cmds=) should exit shortly\n+\t * anyway.\n+\t */\n+\tif (git_config_get_string_const(\"completion.commands\", &cmd_list))\n+\t\treturn;\n+\n+\tstring_list_sort(list);\n+\tstring_list_remove_duplicates(list, 0);\n+\n+\twhile (*cmd_list) {\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\t\tconst char *p = strchrnul(cmd_list, ' ');\n+\n+\t\tstrbuf_add(&sb, cmd_list, p - cmd_list);\n+\t\tif (*cmd_list == '-')\n+\t\t\tstring_list_remove(list, cmd_list + 1, 0);\n+\t\telse\n+\t\t\tstring_list_insert(list, sb.buf);\n+\t\tstrbuf_release(&sb);\n+\t\twhile (*p == ' ')\n+\t\t\tp++;\n+\t\tcmd_list = p;\n+\t}\n+}\n+\n void list_common_guides_help(void)\n {\n \tstruct category_description catdesc[] = {\ndiff --git a/help.h b/help.h\nindex b2293e99be..3b38292a1b 100644\n--- a/help.h\n+++ b/help.h\n@@ -26,6 +26,7 @@ extern void list_all_main_cmds(struct string_list *list);\n extern void list_all_other_cmds(struct string_list *list);\n extern void list_cmds_by_category(struct string_list *list,\n \t\t\t\t  const char *category);\n+extern void list_cmds_by_config(struct string_list *list);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"346896","messageId":"20180507175222.12114-11-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180507175222.12114-1-pclouds@gmail.com","subject":"[PATCH v6 10/13] help: use command-list.txt for the source of guides","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-07T17:52:19Z","receivedAt":"2018-05-07T17:53:33Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The help command currently hard codes the list of guides and their\nsummary in C. Let's move this list to command-list.txt. This lets us\nextract summary lines from Documentation/git*.txt. This also\npotentially lets us list guides in git.txt, but I'll leave that for\nnow.\n---\n Documentation/gitattributes.txt        |  2 +-\n Documentation/gitmodules.txt           |  2 +-\n Documentation/gitrevisions.txt         |  2 +-\n Makefile                               |  2 +-\n builtin/help.c                         | 32 --------------------------\n command-list.txt                       | 16 +++++++++++++\n contrib/completion/git-completion.bash | 15 ++++++++----\n help.c                                 | 21 +++++++++++++----\n help.h                                 |  1 +\n t/t0012-help.sh                        |  6 +++++\n 10 files changed, 54 insertions(+), 45 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex 1094fe2b5b..083c2f380d 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -3,7 +3,7 @@ gitattributes(5)\n \n NAME\n ----\n-gitattributes - defining attributes per path\n+gitattributes - Defining attributes per path\n \n SYNOPSIS\n --------\ndiff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt\nindex db5d47eb19..4d63def206 100644\n--- a/Documentation/gitmodules.txt\n+++ b/Documentation/gitmodules.txt\n@@ -3,7 +3,7 @@ gitmodules(5)\n \n NAME\n ----\n-gitmodules - defining submodule properties\n+gitmodules - Defining submodule properties\n \n SYNOPSIS\n --------\ndiff --git a/Documentation/gitrevisions.txt b/Documentation/gitrevisions.txt\nindex 27dec5b91d..1f6cceaefb 100644\n--- a/Documentation/gitrevisions.txt\n+++ b/Documentation/gitrevisions.txt\n@@ -3,7 +3,7 @@ gitrevisions(7)\n \n NAME\n ----\n-gitrevisions - specifying revisions and ranges for Git\n+gitrevisions - Specifying revisions and ranges for Git\n \n SYNOPSIS\n --------\ndiff --git a/Makefile b/Makefile\nindex a60a78ee67..1efb751e46 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1937,7 +1937,7 @@ $(BUILT_INS): git$X\n \n command-list.h: generate-cmdlist.sh command-list.txt\n \n-command-list.h: $(wildcard Documentation/git-*.txt)\n+command-list.h: $(wildcard Documentation/git*.txt)\n \t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt >$@+ && mv $@+ $@\n \n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 0e0af8426a..5727fb5e51 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -402,38 +402,6 @@ static void show_html_page(const char *git_cmd)\n \topen_html(page_path.buf);\n }\n \n-static struct {\n-\tconst char *name;\n-\tconst char *help;\n-} common_guides[] = {\n-\t{ \"attributes\", N_(\"Defining attributes per path\") },\n-\t{ \"everyday\", N_(\"Everyday Git With 20 Commands Or So\") },\n-\t{ \"glossary\", N_(\"A Git glossary\") },\n-\t{ \"ignore\", N_(\"Specifies intentionally untracked files to ignore\") },\n-\t{ \"modules\", N_(\"Defining submodule properties\") },\n-\t{ \"revisions\", N_(\"Specifying revisions and ranges for Git\") },\n-\t{ \"tutorial\", N_(\"A tutorial introduction to Git (for version 1.5.1 or newer)\") },\n-\t{ \"workflows\", N_(\"An overview of recommended workflows with Git\") },\n-};\n-\n-static void list_common_guides_help(void)\n-{\n-\tint i, longest = 0;\n-\n-\tfor (i = 0; i < ARRAY_SIZE(common_guides); i++) {\n-\t\tif (longest < strlen(common_guides[i].name))\n-\t\t\tlongest = strlen(common_guides[i].name);\n-\t}\n-\n-\tputs(_(\"The common Git guides are:\\n\"));\n-\tfor (i = 0; i < ARRAY_SIZE(common_guides); i++) {\n-\t\tprintf(\"   %s   \", common_guides[i].name);\n-\t\tmput_char(' ', longest - strlen(common_guides[i].name));\n-\t\tputs(_(common_guides[i].help));\n-\t}\n-\tputchar('\\n');\n-}\n-\n static const char *check_git_cmd(const char* cmd)\n {\n \tchar *alias;\ndiff --git a/command-list.txt b/command-list.txt\nindex 3bd23201a6..99ddc231c1 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -139,3 +139,19 @@ gitweb                                  ancillaryinterrogators\n git-whatchanged                         ancillaryinterrogators\n git-worktree                            mainporcelain\n git-write-tree                          plumbingmanipulators\n+gitattributes                           guide\n+gitcli                                  guide\n+gitcore-tutorial                        guide\n+gitcvs-migration                        guide\n+gitdiffcore                             guide\n+giteveryday                             guide\n+gitglossary                             guide\n+githooks                                guide\n+gitignore                               guide\n+gitmodules                              guide\n+gitnamespaces                           guide\n+gitrepository-layout                    guide\n+gitrevisions                            guide\n+gittutorial-2                           guide\n+gittutorial                             guide\n+gitworkflows                            guide\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 62ca8641f4..4e724a5b76 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1575,6 +1575,13 @@ _git_grep ()\n \t__git_complete_refs\n }\n \n+__git_all_guides=\n+__git_compute_all_guides ()\n+{\n+\ttest -n \"$__git_all_guides\" ||\n+\t__git_all_guides=$(git --list-cmds=list-guide)\n+}\n+\n _git_help ()\n {\n \tcase \"$cur\" in\n@@ -1584,11 +1591,9 @@ _git_help ()\n \t\t;;\n \tesac\n \t__git_compute_all_commands\n-\t__gitcomp \"$__git_all_commands $(__git_aliases)\n-\t\tattributes cli core-tutorial cvs-migration\n-\t\tdiffcore everyday gitk glossary hooks ignore modules\n-\t\tnamespaces repository-layout revisions tutorial tutorial-2\n-\t\tworkflows\n+\t__git_compute_all_guides\n+\t__gitcomp \"$__git_all_commands $(__git_aliases) $__git_all_guides\n+\t\tgitk\n \t\t\"\n }\n \ndiff --git a/help.c b/help.c\nindex c7df1d2338..23924dd300 100644\n--- a/help.c\n+++ b/help.c\n@@ -39,12 +39,14 @@ static struct category_description main_categories[] = {\n \t{ 0, NULL }\n };\n \n-static const char *drop_prefix(const char *name)\n+static const char *drop_prefix(const char *name, uint32_t category)\n {\n \tconst char *new_name;\n \n \tif (skip_prefix(name, \"git-\", &new_name))\n \t\treturn new_name;\n+\tif (category == CAT_guide && skip_prefix(name, \"git\", &new_name))\n+\t\treturn new_name;\n \treturn name;\n \n }\n@@ -66,7 +68,7 @@ static void extract_cmds(struct cmdname_help **p_cmds, uint32_t mask)\n \t\t\tcontinue;\n \n \t\tcmds[nr] = *cmd;\n-\t\tcmds[nr].name = drop_prefix(cmd->name);\n+\t\tcmds[nr].name = drop_prefix(cmd->name, cmd->category);\n \n \t\tnr++;\n \t}\n@@ -358,11 +360,22 @@ void list_cmds_by_category(struct string_list *list,\n \tfor (i = 0; i < n; i++) {\n \t\tstruct cmdname_help *cmd = command_list + i;\n \n-\t\tif (cmd->category & cat_id)\n-\t\t\tstring_list_append(list, drop_prefix(cmd->name));\n+\t\tif (!(cmd->category & cat_id))\n+\t\t\tcontinue;\n+\t\tstring_list_append(list, drop_prefix(cmd->name, cmd->category));\n \t}\n }\n \n+void list_common_guides_help(void)\n+{\n+\tstruct category_description catdesc[] = {\n+\t\t{ CAT_guide, N_(\"The common Git guides are:\") },\n+\t\t{ 0, NULL }\n+\t};\n+\tprint_cmd_by_category(catdesc);\n+\tputchar('\\n');\n+}\n+\n void list_all_cmds_help(void)\n {\n \tprint_cmd_by_category(main_categories);\ndiff --git a/help.h b/help.h\nindex 40917fc38c..b2293e99be 100644\n--- a/help.h\n+++ b/help.h\n@@ -20,6 +20,7 @@ static inline void mput_char(char c, unsigned int num)\n \n extern void list_common_cmds_help(void);\n extern void list_all_cmds_help(void);\n+extern void list_common_guides_help(void);\n \n extern void list_all_main_cmds(struct string_list *list);\n extern void list_all_other_cmds(struct string_list *list);\ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex 060df24c2d..bc27df7f38 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -66,6 +66,12 @@ test_expect_success 'git help' '\n \ttest_i18ngrep \"^   commit \" help.output &&\n \ttest_i18ngrep \"^   fetch  \" help.output\n '\n+test_expect_success 'git help -g' '\n+\tgit help -g >help.output &&\n+\ttest_i18ngrep \"^   attributes \" help.output &&\n+\ttest_i18ngrep \"^   everyday   \" help.output &&\n+\ttest_i18ngrep \"^   tutorial   \" help.output\n+'\n \n test_expect_success 'generate builtin list' '\n \tgit --list-cmds=builtins >builtins\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"346897","messageId":"20180507175222.12114-9-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180507175222.12114-1-pclouds@gmail.com","subject":"[PATCH v6 08/13] git: support --list-cmds=list-<category>","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-07T17:52:17Z","receivedAt":"2018-05-07T17:53:33Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This allows us to select any group of commands by a category defined\nin command-list.txt. This is an internal/hidden option so we don't\nhave to be picky about the category name or worried about exposing too\nmuch.\n\nThis will be used later by git-completion.bash to retrieve certain\ncommand groups.\n---\n generate-cmdlist.sh | 17 +++++++++++++++++\n git.c               |  7 +++++++\n help.c              | 23 +++++++++++++++++++++++\n help.h              |  2 ++\n 4 files changed, 49 insertions(+)\n\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 015eef2804..bfd8ef0671 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -45,6 +45,21 @@ define_categories() {\n \ttest \"$bit\" -gt 32 && die \"Urgh.. too many categories?\"\n }\n \n+define_category_names() {\n+\techo\n+\techo \"/* Category names */\"\n+\techo \"static const char *category_names[] = {\"\n+\tbit=0\n+\tcategory_list \"$1\" |\n+\twhile read cat\n+\tdo\n+\t\techo \"\t\\\"$cat\\\", /* (1UL << $bit) */\"\n+\t\tbit=$(($bit+1))\n+\tdone\n+\techo \"\tNULL\"\n+\techo \"};\"\n+}\n+\n print_command_list() {\n \techo \"static struct cmdname_help command_list[] = {\"\n \n@@ -70,4 +85,6 @@ struct cmdname_help {\n \"\n define_categories \"$1\"\n echo\n+define_category_names \"$1\"\n+echo\n print_command_list \"$1\"\ndiff --git a/git.c b/git.c\nindex 3c032d01fc..67f3e20ae9 100644\n--- a/git.c\n+++ b/git.c\n@@ -53,6 +53,13 @@ static int list_cmds(const char *spec)\n \t\t\tlist_all_main_cmds(&list);\n \t\telse if (len == 6 && !strncmp(spec, \"others\", 6))\n \t\t\tlist_all_other_cmds(&list);\n+\t\telse if (len > 5 && !strncmp(spec, \"list-\", 5)) {\n+\t\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\t\tstrbuf_add(&sb, spec + 5, len - 5);\n+\t\t\tlist_cmds_by_category(&list, sb.buf);\n+\t\t\tstrbuf_release(&sb);\n+\t\t}\n \t\telse\n \t\t\tdie(_(\"unsupported command listing type '%s'\"), spec);\n \t\tspec += len;\ndiff --git a/help.c b/help.c\nindex d5ce9dfcbb..1117f7d1d1 100644\n--- a/help.c\n+++ b/help.c\n@@ -329,6 +329,29 @@ void list_all_other_cmds(struct string_list *list)\n \tclean_cmdnames(&other_cmds);\n }\n \n+void list_cmds_by_category(struct string_list *list,\n+\t\t\t   const char *cat)\n+{\n+\tint i, n = ARRAY_SIZE(command_list);\n+\tuint32_t cat_id = 0;\n+\n+\tfor (i = 0; category_names[i]; i++) {\n+\t\tif (!strcmp(cat, category_names[i])) {\n+\t\t\tcat_id = 1UL << i;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\tif (!cat_id)\n+\t\tdie(_(\"unsupported command listing type '%s'\"), cat);\n+\n+\tfor (i = 0; i < n; i++) {\n+\t\tstruct cmdname_help *cmd = command_list + i;\n+\n+\t\tif (cmd->category & cat_id)\n+\t\t\tstring_list_append(list, drop_prefix(cmd->name));\n+\t}\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex 97e6c0965e..734bba32d3 100644\n--- a/help.h\n+++ b/help.h\n@@ -21,6 +21,8 @@ static inline void mput_char(char c, unsigned int num)\n extern void list_common_cmds_help(void);\n extern void list_all_main_cmds(struct string_list *list);\n extern void list_all_other_cmds(struct string_list *list);\n+extern void list_cmds_by_category(struct string_list *list,\n+\t\t\t\t  const char *category);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"346898","messageId":"20180507175222.12114-12-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180507175222.12114-1-pclouds@gmail.com","subject":"[PATCH v6 11/13] command-list.txt: documentation and guide line","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-07T17:52:20Z","receivedAt":"2018-05-07T17:53:37Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is intended to help anybody who needs to update command-list.txt.\nIt gives a brief introduction of all attributes a command can take.\n---\n command-list.txt | 44 ++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 44 insertions(+)\n\ndiff --git a/command-list.txt b/command-list.txt\nindex 99ddc231c1..9c70c69193 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -1,3 +1,47 @@\n+# Command classification list\n+# ---------------------------\n+# All supported commands, builtin or external, must be described in\n+# here. This info is used to list commands in various places. Each\n+# command is on one line followed by one or more attributes.\n+#\n+# The first attribute group is mandatory and indicates the command\n+# type. This group includes:\n+#\n+#   mainporcelain\n+#   ancillarymanipulators\n+#   ancillaryinterrogators\n+#   foreignscminterface\n+#   plumbingmanipulators\n+#   plumbinginterrogators\n+#   synchingrepositories\n+#   synchelpers\n+#   purehelpers\n+#\n+# The type names are self explanatory. But if you want to see what\n+# command belongs to what group to get a better picture, have a look\n+# at \"git\" man page, \"GIT COMMANDS\" section.\n+#\n+# Commands of type mainporcelain can also optionally have one of these\n+# attributes:\n+#\n+#   init\n+#   worktree\n+#   info\n+#   history\n+#   remote\n+#\n+# These commands are considered \"common\" and will show up in \"git\n+# help\" output in groups. Uncommon porcelain commands must not\n+# specify any of these attributes.\n+#\n+# \"complete\" attribute is used to mark that the command should be\n+# completable by git-completion.bash. Note that by default,\n+# mainporcelain commands are completable so you don't need this\n+# attribute.\n+#\n+# While not true commands, guides are also specified here, which can\n+# only have \"guide\" attribute and nothing else.\n+#\n ### command list (do not change this line, also do not change alignment)\n # command name                          category [category] [category]\n git-add                                 mainporcelain           worktree\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"346899","messageId":"20180507175222.12114-4-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180507175222.12114-1-pclouds@gmail.com","subject":"[PATCH v6 03/13] help: use command-list.h for common command list","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-07T17:52:12Z","receivedAt":"2018-05-07T17:53:42Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The previous commit added code generation for all_cmd_desc[] which\nincludes almost everything we need to generate common command list.\nConvert help code to use that array instead and drop common_cmds[] array.\n\nThe description of each common command group is removed from\ncommand-list.txt. This keeps this file format simpler. common-cmds.h\nwill not be generated correctly after this change due to the\ncommand-list.txt format change. But it does not matter and\ncommon-cmds.h will be removed.\n---\n Makefile            |   4 +-\n command-list.txt    |  10 ---\n generate-cmdlist.sh |   4 +-\n help.c              | 145 +++++++++++++++++++++++++++++++++-----------\n t/t0012-help.sh     |   9 +++\n 5 files changed, 122 insertions(+), 50 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 2a8913ea21..5c58b0b692 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1914,9 +1914,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \\\n \t\t$(filter %.o,$^) $(LIBS)\n \n-help.sp help.s help.o: common-cmds.h\n+help.sp help.s help.o: common-cmds.h command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h GIT-PREFIX\n+builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h command-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\ndiff --git a/command-list.txt b/command-list.txt\nindex 786536aba0..3bd23201a6 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -1,13 +1,3 @@\n-# common commands are grouped by themes\n-# these groups are output by 'git help' in the order declared here.\n-# map each common command in the command list to one of these groups.\n-### common groups (do not change this line)\n-init         start a working area (see also: git help tutorial)\n-worktree     work on the current change (see also: git help everyday)\n-info         examine the history and state (see also: git help revisions)\n-history      grow, mark and tweak your common history\n-remote       collaborate (see also: git help workflows)\n-\n ### command list (do not change this line, also do not change alignment)\n # command name                          category [category] [category]\n git-add                                 mainporcelain           worktree\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex c9fd524760..93de8e8f59 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -6,7 +6,7 @@ die () {\n }\n \n command_list () {\n-\tsed '1,/^### command list/d;/^#/d' \"$1\"\n+\tgrep -v '^#' \"$1\"\n }\n \n get_categories() {\n@@ -65,7 +65,7 @@ echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n \tconst char *name;\n \tconst char *help;\n-\tuint32_t group;\n+\tuint32_t category;\n };\n \"\n if [ -z \"$2\" ]\ndiff --git a/help.c b/help.c\nindex 60071a9bea..2d6a3157f8 100644\n--- a/help.c\n+++ b/help.c\n@@ -5,13 +5,114 @@\n #include \"run-command.h\"\n #include \"levenshtein.h\"\n #include \"help.h\"\n-#include \"common-cmds.h\"\n+#include \"command-list.h\"\n #include \"string-list.h\"\n #include \"column.h\"\n #include \"version.h\"\n #include \"refs.h\"\n #include \"parse-options.h\"\n \n+struct category_description {\n+\tuint32_t category;\n+\tconst char *desc;\n+};\n+static uint32_t common_mask =\n+\tCAT_init | CAT_worktree | CAT_info |\n+\tCAT_history | CAT_remote;\n+static struct category_description common_categories[] = {\n+\t{ CAT_init, N_(\"start a working area (see also: git help tutorial)\") },\n+\t{ CAT_worktree, N_(\"work on the current change (see also: git help everyday)\") },\n+\t{ CAT_info, N_(\"examine the history and state (see also: git help revisions)\") },\n+\t{ CAT_history, N_(\"grow, mark and tweak your common history\") },\n+\t{ CAT_remote, N_(\"collaborate (see also: git help workflows)\") },\n+\t{ 0, NULL }\n+};\n+\n+static const char *drop_prefix(const char *name)\n+{\n+\tconst char *new_name;\n+\n+\tif (skip_prefix(name, \"git-\", &new_name))\n+\t\treturn new_name;\n+\treturn name;\n+\n+}\n+\n+static void extract_cmds(struct cmdname_help **p_cmds, uint32_t mask)\n+{\n+\tint i, nr = 0;\n+\tstruct cmdname_help *cmds;\n+\n+\tif (ARRAY_SIZE(command_list) == 0)\n+\t\tBUG(\"empty command_list[] is a sign of broken generate-cmdlist.sh\");\n+\n+\tALLOC_ARRAY(cmds, ARRAY_SIZE(command_list) + 1);\n+\n+\tfor (i = 0; i < ARRAY_SIZE(command_list); i++) {\n+\t\tconst struct cmdname_help *cmd = command_list + i;\n+\n+\t\tif (!(cmd->category & mask))\n+\t\t\tcontinue;\n+\n+\t\tcmds[nr] = *cmd;\n+\t\tcmds[nr].name = drop_prefix(cmd->name);\n+\n+\t\tnr++;\n+\t}\n+\tcmds[nr].name = NULL;\n+\t*p_cmds = cmds;\n+}\n+\n+static void print_command_list(const struct cmdname_help *cmds,\n+\t\t\t       uint32_t mask, int longest)\n+{\n+\tint i;\n+\n+\tfor (i = 0; cmds[i].name; i++) {\n+\t\tif (cmds[i].category & mask) {\n+\t\t\tprintf(\"   %s   \", cmds[i].name);\n+\t\t\tmput_char(' ', longest - strlen(cmds[i].name));\n+\t\t\tputs(_(cmds[i].help));\n+\t\t}\n+\t}\n+}\n+\n+static int cmd_name_cmp(const void *elem1, const void *elem2)\n+{\n+\tconst struct cmdname_help *e1 = elem1;\n+\tconst struct cmdname_help *e2 = elem2;\n+\n+\treturn strcmp(e1->name, e2->name);\n+}\n+\n+static void print_cmd_by_category(const struct category_description *catdesc)\n+{\n+\tstruct cmdname_help *cmds;\n+\tint longest = 0;\n+\tint i, nr = 0;\n+\tuint32_t mask = 0;\n+\n+\tfor (i = 0; catdesc[i].desc; i++)\n+\t\tmask |= catdesc[i].category;\n+\n+\textract_cmds(&cmds, mask);\n+\n+\tfor (i = 0; cmds[i].name; i++, nr++) {\n+\t\tif (longest < strlen(cmds[i].name))\n+\t\t\tlongest = strlen(cmds[i].name);\n+\t}\n+\tQSORT(cmds, nr, cmd_name_cmp);\n+\n+\tfor (i = 0; catdesc[i].desc; i++) {\n+\t\tuint32_t mask = catdesc[i].category;\n+\t\tconst char *desc = catdesc[i].desc;\n+\n+\t\tprintf(\"\\n%s\\n\", _(desc));\n+\t\tprint_command_list(cmds, mask, longest);\n+\t}\n+\tfree(cmds);\n+}\n+\n void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n {\n \tstruct cmdname *ent;\n@@ -190,42 +291,10 @@ void list_commands(unsigned int colopts,\n \t}\n }\n \n-static int cmd_group_cmp(const void *elem1, const void *elem2)\n-{\n-\tconst struct cmdname_help *e1 = elem1;\n-\tconst struct cmdname_help *e2 = elem2;\n-\n-\tif (e1->group < e2->group)\n-\t\treturn -1;\n-\tif (e1->group > e2->group)\n-\t\treturn 1;\n-\treturn strcmp(e1->name, e2->name);\n-}\n-\n void list_common_cmds_help(void)\n {\n-\tint i, longest = 0;\n-\tint current_grp = -1;\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-\tQSORT(common_cmds, ARRAY_SIZE(common_cmds), cmd_group_cmp);\n-\n \tputs(_(\"These are common Git commands used in various situations:\"));\n-\n-\tfor (i = 0; i < ARRAY_SIZE(common_cmds); i++) {\n-\t\tif (common_cmds[i].group != current_grp) {\n-\t\t\tprintf(\"\\n%s\\n\", _(common_cmd_groups[common_cmds[i].group]));\n-\t\t\tcurrent_grp = common_cmds[i].group;\n-\t\t}\n-\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+\tprint_cmd_by_category(common_categories);\n }\n \n int is_in_cmdlist(struct cmdnames *c, const char *s)\n@@ -285,6 +354,7 @@ const char *help_unknown_cmd(const char *cmd)\n {\n \tint i, n, best_similarity = 0;\n \tstruct cmdnames main_cmds, other_cmds;\n+\tstruct cmdname_help *common_cmds;\n \n \tmemset(&main_cmds, 0, sizeof(main_cmds));\n \tmemset(&other_cmds, 0, sizeof(other_cmds));\n@@ -299,6 +369,8 @@ const char *help_unknown_cmd(const char *cmd)\n \tQSORT(main_cmds.names, main_cmds.cnt, cmdname_compare);\n \tuniq(&main_cmds);\n \n+\textract_cmds(&common_cmds, common_mask);\n+\n \t/* This abuses cmdname->len for levenshtein distance */\n \tfor (i = 0, n = 0; i < main_cmds.cnt; i++) {\n \t\tint cmp = 0; /* avoid compiler stupidity */\n@@ -313,10 +385,10 @@ const char *help_unknown_cmd(const char *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\twhile (common_cmds[n].name &&\n \t\t       (cmp = strcmp(common_cmds[n].name, candidate)) < 0)\n \t\t\tn++;\n-\t\tif ((n < ARRAY_SIZE(common_cmds)) && !cmp) {\n+\t\tif (common_cmds[n].name && !cmp) {\n \t\t\t/* Yes, this is one of the common commands */\n \t\t\tn++; /* use the entry from common_cmds[] */\n \t\t\tif (starts_with(candidate, cmd)) {\n@@ -329,6 +401,7 @@ const char *help_unknown_cmd(const char *cmd)\n \t\tmain_cmds.names[i]->len =\n \t\t\tlevenshtein(cmd, candidate, 0, 2, 1, 3) + 1;\n \t}\n+\tFREE_AND_NULL(common_cmds);\n \n \tQSORT(main_cmds.names, main_cmds.cnt, levenshtein_compare);\n \ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex 487b92a5de..c096f33505 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -49,6 +49,15 @@ test_expect_success \"--help does not work for guides\" \"\n \ttest_i18ncmp expect actual\n \"\n \n+test_expect_success 'git help' '\n+\tgit help >help.output &&\n+\ttest_i18ngrep \"^   clone  \" help.output &&\n+\ttest_i18ngrep \"^   add    \" help.output &&\n+\ttest_i18ngrep \"^   log    \" help.output &&\n+\ttest_i18ngrep \"^   commit \" help.output &&\n+\ttest_i18ngrep \"^   fetch  \" help.output\n+'\n+\n test_expect_success 'generate builtin list' '\n \tgit --list-builtins >builtins\n '\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"346958","messageId":"xmqqmuxan70f.fsf@gitster-ct.c.googlers.com","threadId":"48155","inReplyTo":"20180507175222.12114-3-pclouds@gmail.com","subject":"Re: [PATCH v6 02/13] generate-cmds.sh: export all commands to command-list.h","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-08T03:47:12Z","receivedAt":"2018-05-08T03:47:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> The current generate-cmds.sh generates just enough to print \"git help\"\n> output. That is, it only extracts help text for common commands.\n>\n> The script is now updated to extract help text for all commands and\n> keep command classification a new file, command-list.h. This will be\n> useful later:\n>\n> - \"git help -a\" could print a short summary of all commands instead of\n>   just the common ones.\n>\n> - \"git\" could produce a list of commands of one or more category. One\n>   of its use is to reduce another command classification embedded in\n>   git-completion.bash.\n>\n> The new file can be generated but is not used anywhere yet. The plan\n> is we migrate away from common-cmds.h. Then we can kill off\n> common-cmds.h build rules and generation code (and also delete\n> duplicate content in command-list.h which we keep for now to not mess\n> generate-cmds.sh up too much).\n>\n> PS. The new fixed column requirement on command-list.txt is\n> technically not needed. But it helps simplify the code a bit at this\n> stage. We could lift this restriction later if we want to.\n> ---\n\nMissing sign-off.\n\n> diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\n> index 31b6d886cb..c9fd524760 100755\n> --- a/generate-cmdlist.sh\n> +++ b/generate-cmdlist.sh\n> @@ -1,5 +1,27 @@\n>  #!/bin/sh\n>  \n> +die () {\n> +\techo \"$@\" >&2\n> +\texit 1\n> +}\n> +\n> +command_list () {\n> +\tsed '1,/^### command list/d;/^#/d' \"$1\"\n> +}\n> +\n> +get_categories() {\n\nHere and define_categories() below lack SP before (), and all others\ndo.  Be consistent.\n\n> +\ttr ' ' '\\n'|\n> +\tgrep -v '^$' |\n> +\tsort |\n> +\tuniq\n> +}\n> +\n> +category_list () {\n> +\tcommand_list \"$1\" |\n> +\tcut -c 40- |\n> +\tget_categories\n> +}\n> +\n>  get_synopsis () {\n>  \tsed -n '\n>  \t\t/^NAME/,/'\"$1\"'/H\n> @@ -10,14 +32,51 @@ get_synopsis () {\n>  \t\t}' \"Documentation/$1.txt\"\n>  }\n>  \n> +define_categories() {\n> +\techo\n> +\techo \"/* Command categories */\"\n> +...\n>  };\n> +\"\n> +if [ -z \"$2\" ]\n\nif test -z \"$2\"\n\n"},{"id":"346960","messageId":"xmqqin7yn6us.fsf@gitster-ct.c.googlers.com","threadId":"48155","inReplyTo":"20180507175222.12114-6-pclouds@gmail.com","subject":"Re: [PATCH v6 05/13] git.c: convert --list-* to --list-cmds=*","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-08T03:50:35Z","receivedAt":"2018-05-08T03:50:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> Even if these are hidden options, let's make them a bit more generic\n> since we're introducing more listing types shortly. The code is\n> structured to allow combining multiple listing types together because\n> we will soon add more types the 'builtins'.\n>\n> 'parseopt' remains separate because it has separate (SPC) to match\n> git-completion.bash needs and will not combine with others.\n> ---\n\nMissing sign-off.\n\n> +static int list_cmds(const char *spec)\n> +{\n> +\twhile (*spec) {\n> +\t\tconst char *sep = strchrnul(spec, ',');\n> +\t\tint len = sep - spec;\n> +\n> +\t\tif (len == 8 && !strncmp(spec, \"builtins\", 8))\n> +\t\t\tlist_builtins(0, '\\n');\n\nThis is the origin of ugliness we see in later steps that follow the\nsame\n\n\tif (len == strlen(constS) && !strncmp(spec, constS, strlen(constS))\n\npattern added here.  Could we have a small helper that takes len,\nspec, and constS to abstract \"8\" away?\n"},{"id":"346961","messageId":"xmqqefimn6en.fsf@gitster-ct.c.googlers.com","threadId":"48155","inReplyTo":"20180507175222.12114-9-pclouds@gmail.com","subject":"Re: [PATCH v6 08/13] git: support --list-cmds=list-<category>","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-08T04:00:16Z","receivedAt":"2018-05-08T04:00:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> This allows us to select any group of commands by a category defined\n> in command-list.txt. This is an internal/hidden option so we don't\n> have to be picky about the category name or worried about exposing too\n> much.\n>\n> This will be used later by git-completion.bash to retrieve certain\n> command groups.\n> ---\n\nMissing sign-off.\n\n>\n> diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\n> index 015eef2804..bfd8ef0671 100755\n> --- a/generate-cmdlist.sh\n> +++ b/generate-cmdlist.sh\n> @@ -45,6 +45,21 @@ define_categories() {\n>  \ttest \"$bit\" -gt 32 && die \"Urgh.. too many categories?\"\n>  }\n>  \n> +define_category_names() {\n\nStyle.\n\n>  print_command_list() {\n\nDitto (but needs fixing in an earlier step).\n\n> diff --git a/git.c b/git.c\n> index 3c032d01fc..67f3e20ae9 100644\n> --- a/git.c\n> +++ b/git.c\n> @@ -53,6 +53,13 @@ static int list_cmds(const char *spec)\n>  \t\t\tlist_all_main_cmds(&list);\n>  \t\telse if (len == 6 && !strncmp(spec, \"others\", 6))\n>  \t\t\tlist_all_other_cmds(&list);\n> +\t\telse if (len > 5 && !strncmp(spec, \"list-\", 5)) {\n\nEarlier I asked to have a small helper to avoid the constant length that\nhas to go together with a constant string, e.g.\n\n\t\thas_prefix(spec, len, \"others\")\n\nbut this new one may make it a bit tricky.\n\n\telse if (has_prefix(spec, len, \"others\")\n\t\t...\n\telse if (has_prefix(spec, len, \"list-\") &&\n\t\tspec[strlen(\"list-\")] != '\\0' ) {\n\t\t...\n\ndoes look a bit ugly.  Others may be able to help with better ideas.\n\nThansk.\n"},{"id":"346963","messageId":"xmqqa7tan68a.fsf@gitster-ct.c.googlers.com","threadId":"48155","inReplyTo":"20180507175222.12114-11-pclouds@gmail.com","subject":"Re: [PATCH v6 10/13] help: use command-list.txt for the source of guides","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-08T04:04:05Z","receivedAt":"2018-05-08T04:04:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> The help command currently hard codes the list of guides and their\n> summary in C. Let's move this list to command-list.txt. This lets us\n> extract summary lines from Documentation/git*.txt. This also\n> potentially lets us list guides in git.txt, but I'll leave that for\n> now.\n> ---\n\nNice.\n\nMissing sign-off.\n\n"},{"id":"347187","messageId":"20180510084652.25880-1-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180507175222.12114-1-pclouds@gmail.com","subject":"[PATCH v7 00/13] Keep all info in command-list.txt in git binary","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T08:46:39Z","receivedAt":"2018-05-10T08:47:06Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"v7 is mostly code cleanup plus one more change:\n\ngit-completion.bash now always checks completion.commands config key.\nThis makes it much more convenient to customize the command complete\nlist. You only have to fall back to setting $GIT_COMPLETION_CMD_GROUPS\nwhen you have very special needs.\n\nInterdiff\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 2659153cb3..91f7eaed7b 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1343,6 +1343,16 @@ credential.<url>.*::\n credentialCache.ignoreSIGHUP::\n \tTell git-credential-cache--daemon to ignore SIGHUP, instead of quitting.\n \n+completion.commands::\n+\tThis is only used by git-completion.bash to add or remove\n+\tcommands from the complete list. Normally only porcelain\n+\tcommands and a few select others are in the complete list. You\n+\tcan add more commands, separated by space, in this\n+\tvariable. Prefixing a command with '-' will remove it from\n+\tthe existing list.\n++\n+This variable should not be per-repository.\n+\n include::diff-config.txt[]\n \n difftool.<tool>.path::\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 0fd29803d5..f7ca9a4d4f 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -50,10 +50,10 @@\n #\n #         GIT_COMPLETION_CMD_GROUPS=main,others\n #\n-#     Or you could go with defaults add some extra commands specified\n-#     in the configuration variable completion.commands [1] with\n+#     Or you could go with main porcelain only and extra commands in\n+#     the configuration variable completion.commands with\n #\n-#         GIT_COMPLETION_CMD_GROUPS=mainporcelain,others,list-complete,config\n+#         GIT_COMPLETION_CMD_GROUPS=mainporcelain,config\n #\n #     Or go completely custom group with\n #\n@@ -61,15 +61,6 @@\n #\n #     Or you could even play with other command categories found in\n #     command-list.txt.\n-#\n-#     [1] Note that completion.commands should not be per-repository\n-#         since the command list is generated once and cached.\n-#\n-#         completion.commands could be used to exclude commands as\n-#         well.  If a command in this list begins with '-', then it\n-#         will be excluded from the list of commands gathered by the\n-#         groups specified before \"config\" in\n-#         $GIT_COMPLETION_CMD_GROUPS.\n \n case \"$COMP_WORDBREAKS\" in\n *:*) : great ;;\n@@ -876,7 +867,7 @@ __git_commands () {\n \t\tthen\n \t\t\tgit --list-cmds=\"$GIT_COMPLETION_CMD_GROUPS\"\n \t\telse\n-\t\t\tgit --list-cmds=list-mainporcelain,others,list-complete\n+\t\t\tgit --list-cmds=list-mainporcelain,others,list-complete,config\n \t\tfi\n \t\t;;\n \tall)\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex bfd8ef0671..8d6d8b45ce 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -9,7 +9,7 @@ command_list () {\n \tgrep -v '^#' \"$1\"\n }\n \n-get_categories() {\n+get_categories () {\n \ttr ' ' '\\n'|\n \tgrep -v '^$' |\n \tsort |\n@@ -32,7 +32,7 @@ get_synopsis () {\n \t\t}' \"Documentation/$1.txt\"\n }\n \n-define_categories() {\n+define_categories () {\n \techo\n \techo \"/* Command categories */\"\n \tbit=0\n@@ -45,7 +45,7 @@ define_categories() {\n \ttest \"$bit\" -gt 32 && die \"Urgh.. too many categories?\"\n }\n \n-define_category_names() {\n+define_category_names () {\n \techo\n \techo \"/* Category names */\"\n \techo \"static const char *category_names[] = {\"\n@@ -60,7 +60,7 @@ define_category_names() {\n \techo \"};\"\n }\n \n-print_command_list() {\n+print_command_list () {\n \techo \"static struct cmdname_help command_list[] = {\"\n \n \tcommand_list \"$1\" |\ndiff --git a/git.c b/git.c\nindex fd08911e11..ea4feedd0b 100644\n--- a/git.c\n+++ b/git.c\n@@ -38,6 +38,13 @@ static int use_pager = -1;\n \n static void list_builtins(struct string_list *list, unsigned int exclude_option);\n \n+static int match_token(const char *spec, int len, const char *token)\n+{\n+\tint token_len = strlen(token);\n+\n+\treturn len == token_len && !strncmp(spec, token, token_len);\n+}\n+\n static int list_cmds(const char *spec)\n {\n \tstruct string_list list = STRING_LIST_INIT_DUP;\n@@ -47,13 +54,13 @@ static int list_cmds(const char *spec)\n \t\tconst char *sep = strchrnul(spec, ',');\n \t\tint len = sep - spec;\n \n-\t\tif (len == 8 && !strncmp(spec, \"builtins\", 8))\n+\t\tif (match_token(spec, len, \"builtins\"))\n \t\t\tlist_builtins(&list, 0);\n-\t\telse if (len == 4 && !strncmp(spec, \"main\", 4))\n+\t\telse if (match_token(spec, len, \"main\"))\n \t\t\tlist_all_main_cmds(&list);\n-\t\telse if (len == 6 && !strncmp(spec, \"others\", 6))\n+\t\telse if (match_token(spec, len, \"others\"))\n \t\t\tlist_all_other_cmds(&list);\n-\t\telse if (len == 6 && !strncmp(spec, \"config\", 6))\n+\t\telse if (match_token(spec, len, \"config\"))\n \t\t\tlist_cmds_by_config(&list);\n \t\telse if (len > 5 && !strncmp(spec, \"list-\", 5)) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n\nNguyễn Thái Ngọc Duy (13):\n  generate-cmds.sh: factor out synopsis extract code\n  generate-cmds.sh: export all commands to command-list.h\n  help: use command-list.h for common command list\n  Remove common-cmds.h\n  git.c: convert --list-* to --list-cmds=*\n  git --list-cmds: collect command list in a string_list\n  completion: implement and use --list-cmds=main,others\n  git: support --list-cmds=list-<category>\n  help: add \"-a --verbose\" to list all commands with synopsis\n  help: use command-list.txt for the source of guides\n  command-list.txt: documentation and guide line\n  completion: let git provide the completable command list\n  completion: allow to customize the completable command list\n\n .gitignore                             |   2 +-\n Documentation/config.txt               |  10 +\n Documentation/git-help.txt             |   4 +-\n Documentation/gitattributes.txt        |   2 +-\n Documentation/gitmodules.txt           |   2 +-\n Documentation/gitrevisions.txt         |   2 +-\n Makefile                               |  16 +-\n builtin/help.c                         |  39 +---\n command-list.txt                       | 111 ++++++++---\n contrib/completion/git-completion.bash | 160 +++++++---------\n generate-cmdlist.sh                    | 126 ++++++++-----\n git.c                                  |  68 ++++++-\n help.c                                 | 244 ++++++++++++++++++++++---\n help.h                                 |  10 +\n t/t0012-help.sh                        |  26 ++-\n t/t9902-completion.sh                  |   5 +-\n 16 files changed, 573 insertions(+), 254 deletions(-)\n\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347188","messageId":"20180510084652.25880-2-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180510084652.25880-1-pclouds@gmail.com","subject":"[PATCH v7 01/13] generate-cmds.sh: factor out synopsis extract code","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T08:46:40Z","receivedAt":"2018-05-10T08:47:08Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This makes it easier to reuse the same code in another place (very\nsoon).\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n generate-cmdlist.sh | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex eeea4b67ea..31b6d886cb 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -1,5 +1,15 @@\n #!/bin/sh\n \n+get_synopsis () {\n+\tsed -n '\n+\t\t/^NAME/,/'\"$1\"'/H\n+\t\t${\n+\t\t\tx\n+\t\t\ts/.*'\"$1\"' - \\(.*\\)/N_(\"\\1\")/\n+\t\t\tp\n+\t\t}' \"Documentation/$1.txt\"\n+}\n+\n echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n \tchar name[16];\n@@ -39,12 +49,6 @@ sort |\n while read cmd tags\n do\n \ttag=$(echo \"$tags\" | sed \"$substnum; s/[^0-9]//g\")\n-\tsed -n '\n-\t\t/^NAME/,/git-'\"$cmd\"'/H\n-\t\t${\n-\t\t\tx\n-\t\t\ts/.*git-'\"$cmd\"' - \\(.*\\)/\t{\"'\"$cmd\"'\", N_(\"\\1\"), '$tag'},/\n-\t\t\tp\n-\t\t}' \"Documentation/git-$cmd.txt\"\n+\techo \"\t{\\\"$cmd\\\", $(get_synopsis git-$cmd), $tag},\"\n done\n echo \"};\"\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347189","messageId":"20180510084652.25880-4-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180510084652.25880-1-pclouds@gmail.com","subject":"[PATCH v7 03/13] help: use command-list.h for common command list","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T08:46:42Z","receivedAt":"2018-05-10T08:47:15Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The previous commit added code generation for all_cmd_desc[] which\nincludes almost everything we need to generate common command list.\nConvert help code to use that array instead and drop common_cmds[] array.\n\nThe description of each common command group is removed from\ncommand-list.txt. This keeps this file format simpler. common-cmds.h\nwill not be generated correctly after this change due to the\ncommand-list.txt format change. But it does not matter and\ncommon-cmds.h will be removed.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Makefile            |   4 +-\n command-list.txt    |  10 ---\n generate-cmdlist.sh |   4 +-\n help.c              | 145 +++++++++++++++++++++++++++++++++-----------\n t/t0012-help.sh     |   9 +++\n 5 files changed, 122 insertions(+), 50 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 2a8913ea21..5c58b0b692 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1914,9 +1914,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \\\n \t\t$(filter %.o,$^) $(LIBS)\n \n-help.sp help.s help.o: common-cmds.h\n+help.sp help.s help.o: common-cmds.h command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h GIT-PREFIX\n+builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h command-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\ndiff --git a/command-list.txt b/command-list.txt\nindex 786536aba0..3bd23201a6 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -1,13 +1,3 @@\n-# common commands are grouped by themes\n-# these groups are output by 'git help' in the order declared here.\n-# map each common command in the command list to one of these groups.\n-### common groups (do not change this line)\n-init         start a working area (see also: git help tutorial)\n-worktree     work on the current change (see also: git help everyday)\n-info         examine the history and state (see also: git help revisions)\n-history      grow, mark and tweak your common history\n-remote       collaborate (see also: git help workflows)\n-\n ### command list (do not change this line, also do not change alignment)\n # command name                          category [category] [category]\n git-add                                 mainporcelain           worktree\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 870d3b626a..9eb22c4ef1 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -6,7 +6,7 @@ die () {\n }\n \n command_list () {\n-\tsed '1,/^### command list/d;/^#/d' \"$1\"\n+\tgrep -v '^#' \"$1\"\n }\n \n get_categories () {\n@@ -65,7 +65,7 @@ echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n \tconst char *name;\n \tconst char *help;\n-\tuint32_t group;\n+\tuint32_t category;\n };\n \"\n if test -z \"$2\"\ndiff --git a/help.c b/help.c\nindex 60071a9bea..2d6a3157f8 100644\n--- a/help.c\n+++ b/help.c\n@@ -5,13 +5,114 @@\n #include \"run-command.h\"\n #include \"levenshtein.h\"\n #include \"help.h\"\n-#include \"common-cmds.h\"\n+#include \"command-list.h\"\n #include \"string-list.h\"\n #include \"column.h\"\n #include \"version.h\"\n #include \"refs.h\"\n #include \"parse-options.h\"\n \n+struct category_description {\n+\tuint32_t category;\n+\tconst char *desc;\n+};\n+static uint32_t common_mask =\n+\tCAT_init | CAT_worktree | CAT_info |\n+\tCAT_history | CAT_remote;\n+static struct category_description common_categories[] = {\n+\t{ CAT_init, N_(\"start a working area (see also: git help tutorial)\") },\n+\t{ CAT_worktree, N_(\"work on the current change (see also: git help everyday)\") },\n+\t{ CAT_info, N_(\"examine the history and state (see also: git help revisions)\") },\n+\t{ CAT_history, N_(\"grow, mark and tweak your common history\") },\n+\t{ CAT_remote, N_(\"collaborate (see also: git help workflows)\") },\n+\t{ 0, NULL }\n+};\n+\n+static const char *drop_prefix(const char *name)\n+{\n+\tconst char *new_name;\n+\n+\tif (skip_prefix(name, \"git-\", &new_name))\n+\t\treturn new_name;\n+\treturn name;\n+\n+}\n+\n+static void extract_cmds(struct cmdname_help **p_cmds, uint32_t mask)\n+{\n+\tint i, nr = 0;\n+\tstruct cmdname_help *cmds;\n+\n+\tif (ARRAY_SIZE(command_list) == 0)\n+\t\tBUG(\"empty command_list[] is a sign of broken generate-cmdlist.sh\");\n+\n+\tALLOC_ARRAY(cmds, ARRAY_SIZE(command_list) + 1);\n+\n+\tfor (i = 0; i < ARRAY_SIZE(command_list); i++) {\n+\t\tconst struct cmdname_help *cmd = command_list + i;\n+\n+\t\tif (!(cmd->category & mask))\n+\t\t\tcontinue;\n+\n+\t\tcmds[nr] = *cmd;\n+\t\tcmds[nr].name = drop_prefix(cmd->name);\n+\n+\t\tnr++;\n+\t}\n+\tcmds[nr].name = NULL;\n+\t*p_cmds = cmds;\n+}\n+\n+static void print_command_list(const struct cmdname_help *cmds,\n+\t\t\t       uint32_t mask, int longest)\n+{\n+\tint i;\n+\n+\tfor (i = 0; cmds[i].name; i++) {\n+\t\tif (cmds[i].category & mask) {\n+\t\t\tprintf(\"   %s   \", cmds[i].name);\n+\t\t\tmput_char(' ', longest - strlen(cmds[i].name));\n+\t\t\tputs(_(cmds[i].help));\n+\t\t}\n+\t}\n+}\n+\n+static int cmd_name_cmp(const void *elem1, const void *elem2)\n+{\n+\tconst struct cmdname_help *e1 = elem1;\n+\tconst struct cmdname_help *e2 = elem2;\n+\n+\treturn strcmp(e1->name, e2->name);\n+}\n+\n+static void print_cmd_by_category(const struct category_description *catdesc)\n+{\n+\tstruct cmdname_help *cmds;\n+\tint longest = 0;\n+\tint i, nr = 0;\n+\tuint32_t mask = 0;\n+\n+\tfor (i = 0; catdesc[i].desc; i++)\n+\t\tmask |= catdesc[i].category;\n+\n+\textract_cmds(&cmds, mask);\n+\n+\tfor (i = 0; cmds[i].name; i++, nr++) {\n+\t\tif (longest < strlen(cmds[i].name))\n+\t\t\tlongest = strlen(cmds[i].name);\n+\t}\n+\tQSORT(cmds, nr, cmd_name_cmp);\n+\n+\tfor (i = 0; catdesc[i].desc; i++) {\n+\t\tuint32_t mask = catdesc[i].category;\n+\t\tconst char *desc = catdesc[i].desc;\n+\n+\t\tprintf(\"\\n%s\\n\", _(desc));\n+\t\tprint_command_list(cmds, mask, longest);\n+\t}\n+\tfree(cmds);\n+}\n+\n void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n {\n \tstruct cmdname *ent;\n@@ -190,42 +291,10 @@ void list_commands(unsigned int colopts,\n \t}\n }\n \n-static int cmd_group_cmp(const void *elem1, const void *elem2)\n-{\n-\tconst struct cmdname_help *e1 = elem1;\n-\tconst struct cmdname_help *e2 = elem2;\n-\n-\tif (e1->group < e2->group)\n-\t\treturn -1;\n-\tif (e1->group > e2->group)\n-\t\treturn 1;\n-\treturn strcmp(e1->name, e2->name);\n-}\n-\n void list_common_cmds_help(void)\n {\n-\tint i, longest = 0;\n-\tint current_grp = -1;\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-\tQSORT(common_cmds, ARRAY_SIZE(common_cmds), cmd_group_cmp);\n-\n \tputs(_(\"These are common Git commands used in various situations:\"));\n-\n-\tfor (i = 0; i < ARRAY_SIZE(common_cmds); i++) {\n-\t\tif (common_cmds[i].group != current_grp) {\n-\t\t\tprintf(\"\\n%s\\n\", _(common_cmd_groups[common_cmds[i].group]));\n-\t\t\tcurrent_grp = common_cmds[i].group;\n-\t\t}\n-\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+\tprint_cmd_by_category(common_categories);\n }\n \n int is_in_cmdlist(struct cmdnames *c, const char *s)\n@@ -285,6 +354,7 @@ const char *help_unknown_cmd(const char *cmd)\n {\n \tint i, n, best_similarity = 0;\n \tstruct cmdnames main_cmds, other_cmds;\n+\tstruct cmdname_help *common_cmds;\n \n \tmemset(&main_cmds, 0, sizeof(main_cmds));\n \tmemset(&other_cmds, 0, sizeof(other_cmds));\n@@ -299,6 +369,8 @@ const char *help_unknown_cmd(const char *cmd)\n \tQSORT(main_cmds.names, main_cmds.cnt, cmdname_compare);\n \tuniq(&main_cmds);\n \n+\textract_cmds(&common_cmds, common_mask);\n+\n \t/* This abuses cmdname->len for levenshtein distance */\n \tfor (i = 0, n = 0; i < main_cmds.cnt; i++) {\n \t\tint cmp = 0; /* avoid compiler stupidity */\n@@ -313,10 +385,10 @@ const char *help_unknown_cmd(const char *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\twhile (common_cmds[n].name &&\n \t\t       (cmp = strcmp(common_cmds[n].name, candidate)) < 0)\n \t\t\tn++;\n-\t\tif ((n < ARRAY_SIZE(common_cmds)) && !cmp) {\n+\t\tif (common_cmds[n].name && !cmp) {\n \t\t\t/* Yes, this is one of the common commands */\n \t\t\tn++; /* use the entry from common_cmds[] */\n \t\t\tif (starts_with(candidate, cmd)) {\n@@ -329,6 +401,7 @@ const char *help_unknown_cmd(const char *cmd)\n \t\tmain_cmds.names[i]->len =\n \t\t\tlevenshtein(cmd, candidate, 0, 2, 1, 3) + 1;\n \t}\n+\tFREE_AND_NULL(common_cmds);\n \n \tQSORT(main_cmds.names, main_cmds.cnt, levenshtein_compare);\n \ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex 487b92a5de..c096f33505 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -49,6 +49,15 @@ test_expect_success \"--help does not work for guides\" \"\n \ttest_i18ncmp expect actual\n \"\n \n+test_expect_success 'git help' '\n+\tgit help >help.output &&\n+\ttest_i18ngrep \"^   clone  \" help.output &&\n+\ttest_i18ngrep \"^   add    \" help.output &&\n+\ttest_i18ngrep \"^   log    \" help.output &&\n+\ttest_i18ngrep \"^   commit \" help.output &&\n+\ttest_i18ngrep \"^   fetch  \" help.output\n+'\n+\n test_expect_success 'generate builtin list' '\n \tgit --list-builtins >builtins\n '\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347190","messageId":"20180510084652.25880-3-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180510084652.25880-1-pclouds@gmail.com","subject":"[PATCH v7 02/13] generate-cmds.sh: export all commands to command-list.h","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T08:46:41Z","receivedAt":"2018-05-10T08:47:15Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The current generate-cmds.sh generates just enough to print \"git help\"\noutput. That is, it only extracts help text for common commands.\n\nThe script is now updated to extract help text for all commands and\nkeep command classification a new file, command-list.h. This will be\nuseful later:\n\n- \"git help -a\" could print a short summary of all commands instead of\n  just the common ones.\n\n- \"git\" could produce a list of commands of one or more category. One\n  of its use is to reduce another command classification embedded in\n  git-completion.bash.\n\nThe new file can be generated but is not used anywhere yet. The plan\nis we migrate away from common-cmds.h. Then we can kill off\ncommon-cmds.h build rules and generation code (and also delete\nduplicate content in command-list.h which we keep for now to not mess\ngenerate-cmds.sh up too much).\n\nPS. The new fixed column requirement on command-list.txt is\ntechnically not needed. But it helps simplify the code a bit at this\nstage. We could lift this restriction later if we want to.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n .gitignore          |  1 +\n Makefile            | 13 ++++++---\n command-list.txt    |  4 +--\n generate-cmdlist.sh | 67 ++++++++++++++++++++++++++++++++++++++++++---\n 4 files changed, 75 insertions(+), 10 deletions(-)\n\ndiff --git a/.gitignore b/.gitignore\nindex 833ef3b0b7..d4c3914167 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -180,6 +180,7 @@\n /gitweb/static/gitweb.js\n /gitweb/static/gitweb.min.*\n /common-cmds.h\n+/command-list.h\n *.tar.gz\n *.dsc\n *.deb\ndiff --git a/Makefile b/Makefile\nindex f181687250..2a8913ea21 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -757,7 +757,7 @@ LIB_FILE = libgit.a\n XDIFF_LIB = xdiff/lib.a\n VCSSVN_LIB = vcs-svn/lib.a\n \n-GENERATED_H += common-cmds.h\n+GENERATED_H += common-cmds.h command-list.h\n \n LIB_H = $(shell $(FIND) . \\\n \t-name .git -prune -o \\\n@@ -1938,6 +1938,11 @@ $(BUILT_INS): git$X\n common-cmds.h: generate-cmdlist.sh command-list.txt\n \n common-cmds.h: $(wildcard Documentation/git-*.txt)\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt COMMON >$@+ && mv $@+ $@\n+\n+command-list.h: generate-cmdlist.sh command-list.txt\n+\n+command-list.h: $(wildcard Documentation/git-*.txt)\n \t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt >$@+ && mv $@+ $@\n \n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\n@@ -2148,7 +2153,7 @@ else\n # Dependencies on header files, for platforms that do not support\n # the gcc -MMD option.\n #\n-# Dependencies on automatically generated headers such as common-cmds.h\n+# Dependencies on automatically generated headers such as common-cmds.h or command-list.h\n # should _not_ be included here, since they are necessary even when\n # building an object for the first time.\n \n@@ -2527,7 +2532,7 @@ sparse: $(SP_OBJ)\n style:\n \tgit clang-format --style file --diff --extensions c,h\n \n-check: common-cmds.h\n+check: common-cmds.h command-list.h\n \t@if sparse; \\\n \tthen \\\n \t\techo >&2 \"Use 'make sparse' instead\"; \\\n@@ -2775,7 +2780,7 @@ clean: profile-clean coverage-clean\n \t$(RM) $(TEST_PROGRAMS) $(NO_INSTALL)\n \t$(RM) -r bin-wrappers $(dep_dirs)\n \t$(RM) -r po/build/\n-\t$(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h $(ETAGS_TARGET) tags cscope*\n+\t$(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h command-list.h $(ETAGS_TARGET) tags cscope*\n \t$(RM) -r $(GIT_TARNAME) .doc-tmp-dir\n \t$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz\n \t$(RM) $(htmldocs).tar.gz $(manpages).tar.gz\ndiff --git a/command-list.txt b/command-list.txt\nindex a1fad28fd8..786536aba0 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -8,8 +8,8 @@ info         examine the history and state (see also: git help revisions)\n history      grow, mark and tweak your common history\n remote       collaborate (see also: git help workflows)\n \n-### command list (do not change this line)\n-# command name                          category [deprecated] [common]\n+### command list (do not change this line, also do not change alignment)\n+# command name                          category [category] [category]\n git-add                                 mainporcelain           worktree\n git-am                                  mainporcelain\n git-annotate                            ancillaryinterrogators\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 31b6d886cb..870d3b626a 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -1,5 +1,27 @@\n #!/bin/sh\n \n+die () {\n+\techo \"$@\" >&2\n+\texit 1\n+}\n+\n+command_list () {\n+\tsed '1,/^### command list/d;/^#/d' \"$1\"\n+}\n+\n+get_categories () {\n+\ttr ' ' '\\n'|\n+\tgrep -v '^$' |\n+\tsort |\n+\tuniq\n+}\n+\n+category_list () {\n+\tcommand_list \"$1\" |\n+\tcut -c 40- |\n+\tget_categories\n+}\n+\n get_synopsis () {\n \tsed -n '\n \t\t/^NAME/,/'\"$1\"'/H\n@@ -10,14 +32,51 @@ get_synopsis () {\n \t\t}' \"Documentation/$1.txt\"\n }\n \n+define_categories () {\n+\techo\n+\techo \"/* Command categories */\"\n+\tbit=0\n+\tcategory_list \"$1\" |\n+\twhile read cat\n+\tdo\n+\t\techo \"#define CAT_$cat (1UL << $bit)\"\n+\t\tbit=$(($bit+1))\n+\tdone\n+\ttest \"$bit\" -gt 32 && die \"Urgh.. too many categories?\"\n+}\n+\n+print_command_list () {\n+\techo \"static struct cmdname_help command_list[] = {\"\n+\n+\tcommand_list \"$1\" |\n+\twhile read cmd rest\n+\tdo\n+\t\tprintf \"\t{ \\\"$cmd\\\", $(get_synopsis $cmd), 0\"\n+\t\tfor cat in $(echo \"$rest\" | get_categories)\n+\t\tdo\n+\t\t\tprintf \" | CAT_$cat\"\n+\t\tdone\n+\t\techo \" },\"\n+\tdone\n+\techo \"};\"\n+}\n+\n echo \"/* Automatically generated by generate-cmdlist.sh */\n struct cmdname_help {\n-\tchar name[16];\n-\tchar help[80];\n-\tunsigned char group;\n+\tconst char *name;\n+\tconst char *help;\n+\tuint32_t group;\n };\n+\"\n+if test -z \"$2\"\n+then\n+\tdefine_categories \"$1\"\n+\techo\n+\tprint_command_list \"$1\"\n+\texit 0\n+fi\n \n-static const char *common_cmd_groups[] = {\"\n+echo \"static const char *common_cmd_groups[] = {\"\n \n grps=grps$$.tmp\n match=match$$.tmp\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347191","messageId":"20180510084652.25880-5-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180510084652.25880-1-pclouds@gmail.com","subject":"[PATCH v7 04/13] Remove common-cmds.h","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T08:46:43Z","receivedAt":"2018-05-10T08:47:18Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"After the last patch, common-cmds.h is no longer used (and it was\nactually broken). Remove all related code. command-list.h will take\nits place from now on.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n .gitignore          |  1 -\n Makefile            | 17 ++++++-----------\n generate-cmdlist.sh | 46 +++------------------------------------------\n 3 files changed, 9 insertions(+), 55 deletions(-)\n\ndiff --git a/.gitignore b/.gitignore\nindex d4c3914167..0836083992 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -179,7 +179,6 @@\n /gitweb/gitweb.cgi\n /gitweb/static/gitweb.js\n /gitweb/static/gitweb.min.*\n-/common-cmds.h\n /command-list.h\n *.tar.gz\n *.dsc\ndiff --git a/Makefile b/Makefile\nindex 5c58b0b692..a60a78ee67 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -757,7 +757,7 @@ LIB_FILE = libgit.a\n XDIFF_LIB = xdiff/lib.a\n VCSSVN_LIB = vcs-svn/lib.a\n \n-GENERATED_H += common-cmds.h command-list.h\n+GENERATED_H += command-list.h\n \n LIB_H = $(shell $(FIND) . \\\n \t-name .git -prune -o \\\n@@ -1914,9 +1914,9 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \\\n \t\t$(filter %.o,$^) $(LIBS)\n \n-help.sp help.s help.o: common-cmds.h command-list.h\n+help.sp help.s help.o: command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h command-list.h GIT-PREFIX\n+builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n@@ -1935,11 +1935,6 @@ $(BUILT_INS): git$X\n \tln -s $< $@ 2>/dev/null || \\\n \tcp $< $@\n \n-common-cmds.h: generate-cmdlist.sh command-list.txt\n-\n-common-cmds.h: $(wildcard Documentation/git-*.txt)\n-\t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt COMMON >$@+ && mv $@+ $@\n-\n command-list.h: generate-cmdlist.sh command-list.txt\n \n command-list.h: $(wildcard Documentation/git-*.txt)\n@@ -2153,7 +2148,7 @@ else\n # Dependencies on header files, for platforms that do not support\n # the gcc -MMD option.\n #\n-# Dependencies on automatically generated headers such as common-cmds.h or command-list.h\n+# Dependencies on automatically generated headers such as command-list.h\n # should _not_ be included here, since they are necessary even when\n # building an object for the first time.\n \n@@ -2532,7 +2527,7 @@ sparse: $(SP_OBJ)\n style:\n \tgit clang-format --style file --diff --extensions c,h\n \n-check: common-cmds.h command-list.h\n+check: command-list.h\n \t@if sparse; \\\n \tthen \\\n \t\techo >&2 \"Use 'make sparse' instead\"; \\\n@@ -2780,7 +2775,7 @@ clean: profile-clean coverage-clean\n \t$(RM) $(TEST_PROGRAMS) $(NO_INSTALL)\n \t$(RM) -r bin-wrappers $(dep_dirs)\n \t$(RM) -r po/build/\n-\t$(RM) *.pyc *.pyo */*.pyc */*.pyo common-cmds.h command-list.h $(ETAGS_TARGET) tags cscope*\n+\t$(RM) *.pyc *.pyo */*.pyc */*.pyo command-list.h $(ETAGS_TARGET) tags cscope*\n \t$(RM) -r $(GIT_TARNAME) .doc-tmp-dir\n \t$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz\n \t$(RM) $(htmldocs).tar.gz $(manpages).tar.gz\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 9eb22c4ef1..3bcc1ee57d 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -68,46 +68,6 @@ struct cmdname_help {\n \tuint32_t category;\n };\n \"\n-if test -z \"$2\"\n-then\n-\tdefine_categories \"$1\"\n-\techo\n-\tprint_command_list \"$1\"\n-\texit 0\n-fi\n-\n-echo \"static const char *common_cmd_groups[] = {\"\n-\n-grps=grps$$.tmp\n-match=match$$.tmp\n-trap \"rm -f '$grps' '$match'\" 0 1 2 3 15\n-\n-sed -n '\n-\t1,/^### common groups/b\n-\t/^### command list/q\n-\t/^#/b\n-\t/^[ \t]*$/b\n-\th;s/^[^ \t][^ \t]*[ \t][ \t]*\\(.*\\)/\tN_(\"\\1\"),/p\n-\tg;s/^\\([^ \t][^ \t]*\\)[ \t].*/\\1/w '$grps'\n-\t' \"$1\"\n-printf '};\\n\\n'\n-\n-n=0\n-substnum=\n-while read grp\n-do\n-\techo \"^git-..*[ \t]$grp\"\n-\tsubstnum=\"$substnum${substnum:+;}s/[ \t]$grp/$n/\"\n-\tn=$(($n+1))\n-done <\"$grps\" >\"$match\"\n-\n-printf 'static struct cmdname_help common_cmds[] = {\\n'\n-grep -f \"$match\" \"$1\" |\n-sed 's/^git-//' |\n-sort |\n-while read cmd tags\n-do\n-\ttag=$(echo \"$tags\" | sed \"$substnum; s/[^0-9]//g\")\n-\techo \"\t{\\\"$cmd\\\", $(get_synopsis git-$cmd), $tag},\"\n-done\n-echo \"};\"\n+define_categories \"$1\"\n+echo\n+print_command_list \"$1\"\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347192","messageId":"20180510084652.25880-12-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180510084652.25880-1-pclouds@gmail.com","subject":"[PATCH v7 11/13] command-list.txt: documentation and guide line","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T08:46:50Z","receivedAt":"2018-05-10T08:47:25Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is intended to help anybody who needs to update command-list.txt.\nIt gives a brief introduction of all attributes a command can take.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n command-list.txt | 44 ++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 44 insertions(+)\n\ndiff --git a/command-list.txt b/command-list.txt\nindex 99ddc231c1..9c70c69193 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -1,3 +1,47 @@\n+# Command classification list\n+# ---------------------------\n+# All supported commands, builtin or external, must be described in\n+# here. This info is used to list commands in various places. Each\n+# command is on one line followed by one or more attributes.\n+#\n+# The first attribute group is mandatory and indicates the command\n+# type. This group includes:\n+#\n+#   mainporcelain\n+#   ancillarymanipulators\n+#   ancillaryinterrogators\n+#   foreignscminterface\n+#   plumbingmanipulators\n+#   plumbinginterrogators\n+#   synchingrepositories\n+#   synchelpers\n+#   purehelpers\n+#\n+# The type names are self explanatory. But if you want to see what\n+# command belongs to what group to get a better picture, have a look\n+# at \"git\" man page, \"GIT COMMANDS\" section.\n+#\n+# Commands of type mainporcelain can also optionally have one of these\n+# attributes:\n+#\n+#   init\n+#   worktree\n+#   info\n+#   history\n+#   remote\n+#\n+# These commands are considered \"common\" and will show up in \"git\n+# help\" output in groups. Uncommon porcelain commands must not\n+# specify any of these attributes.\n+#\n+# \"complete\" attribute is used to mark that the command should be\n+# completable by git-completion.bash. Note that by default,\n+# mainporcelain commands are completable so you don't need this\n+# attribute.\n+#\n+# While not true commands, guides are also specified here, which can\n+# only have \"guide\" attribute and nothing else.\n+#\n ### command list (do not change this line, also do not change alignment)\n # command name                          category [category] [category]\n git-add                                 mainporcelain           worktree\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347193","messageId":"20180510084652.25880-11-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180510084652.25880-1-pclouds@gmail.com","subject":"[PATCH v7 10/13] help: use command-list.txt for the source of guides","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T08:46:49Z","receivedAt":"2018-05-10T08:47:31Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The help command currently hard codes the list of guides and their\nsummary in C. Let's move this list to command-list.txt. This lets us\nextract summary lines from Documentation/git*.txt. This also\npotentially lets us list guides in git.txt, but I'll leave that for\nnow.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/gitattributes.txt        |  2 +-\n Documentation/gitmodules.txt           |  2 +-\n Documentation/gitrevisions.txt         |  2 +-\n Makefile                               |  2 +-\n builtin/help.c                         | 32 --------------------------\n command-list.txt                       | 16 +++++++++++++\n contrib/completion/git-completion.bash | 15 ++++++++----\n help.c                                 | 21 +++++++++++++----\n help.h                                 |  1 +\n t/t0012-help.sh                        |  6 +++++\n 10 files changed, 54 insertions(+), 45 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex 1094fe2b5b..083c2f380d 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -3,7 +3,7 @@ gitattributes(5)\n \n NAME\n ----\n-gitattributes - defining attributes per path\n+gitattributes - Defining attributes per path\n \n SYNOPSIS\n --------\ndiff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt\nindex db5d47eb19..4d63def206 100644\n--- a/Documentation/gitmodules.txt\n+++ b/Documentation/gitmodules.txt\n@@ -3,7 +3,7 @@ gitmodules(5)\n \n NAME\n ----\n-gitmodules - defining submodule properties\n+gitmodules - Defining submodule properties\n \n SYNOPSIS\n --------\ndiff --git a/Documentation/gitrevisions.txt b/Documentation/gitrevisions.txt\nindex 27dec5b91d..1f6cceaefb 100644\n--- a/Documentation/gitrevisions.txt\n+++ b/Documentation/gitrevisions.txt\n@@ -3,7 +3,7 @@ gitrevisions(7)\n \n NAME\n ----\n-gitrevisions - specifying revisions and ranges for Git\n+gitrevisions - Specifying revisions and ranges for Git\n \n SYNOPSIS\n --------\ndiff --git a/Makefile b/Makefile\nindex a60a78ee67..1efb751e46 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1937,7 +1937,7 @@ $(BUILT_INS): git$X\n \n command-list.h: generate-cmdlist.sh command-list.txt\n \n-command-list.h: $(wildcard Documentation/git-*.txt)\n+command-list.h: $(wildcard Documentation/git*.txt)\n \t$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt >$@+ && mv $@+ $@\n \n SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\\\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 0e0af8426a..5727fb5e51 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -402,38 +402,6 @@ static void show_html_page(const char *git_cmd)\n \topen_html(page_path.buf);\n }\n \n-static struct {\n-\tconst char *name;\n-\tconst char *help;\n-} common_guides[] = {\n-\t{ \"attributes\", N_(\"Defining attributes per path\") },\n-\t{ \"everyday\", N_(\"Everyday Git With 20 Commands Or So\") },\n-\t{ \"glossary\", N_(\"A Git glossary\") },\n-\t{ \"ignore\", N_(\"Specifies intentionally untracked files to ignore\") },\n-\t{ \"modules\", N_(\"Defining submodule properties\") },\n-\t{ \"revisions\", N_(\"Specifying revisions and ranges for Git\") },\n-\t{ \"tutorial\", N_(\"A tutorial introduction to Git (for version 1.5.1 or newer)\") },\n-\t{ \"workflows\", N_(\"An overview of recommended workflows with Git\") },\n-};\n-\n-static void list_common_guides_help(void)\n-{\n-\tint i, longest = 0;\n-\n-\tfor (i = 0; i < ARRAY_SIZE(common_guides); i++) {\n-\t\tif (longest < strlen(common_guides[i].name))\n-\t\t\tlongest = strlen(common_guides[i].name);\n-\t}\n-\n-\tputs(_(\"The common Git guides are:\\n\"));\n-\tfor (i = 0; i < ARRAY_SIZE(common_guides); i++) {\n-\t\tprintf(\"   %s   \", common_guides[i].name);\n-\t\tmput_char(' ', longest - strlen(common_guides[i].name));\n-\t\tputs(_(common_guides[i].help));\n-\t}\n-\tputchar('\\n');\n-}\n-\n static const char *check_git_cmd(const char* cmd)\n {\n \tchar *alias;\ndiff --git a/command-list.txt b/command-list.txt\nindex 3bd23201a6..99ddc231c1 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -139,3 +139,19 @@ gitweb                                  ancillaryinterrogators\n git-whatchanged                         ancillaryinterrogators\n git-worktree                            mainporcelain\n git-write-tree                          plumbingmanipulators\n+gitattributes                           guide\n+gitcli                                  guide\n+gitcore-tutorial                        guide\n+gitcvs-migration                        guide\n+gitdiffcore                             guide\n+giteveryday                             guide\n+gitglossary                             guide\n+githooks                                guide\n+gitignore                               guide\n+gitmodules                              guide\n+gitnamespaces                           guide\n+gitrepository-layout                    guide\n+gitrevisions                            guide\n+gittutorial-2                           guide\n+gittutorial                             guide\n+gitworkflows                            guide\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 62ca8641f4..4e724a5b76 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1575,6 +1575,13 @@ _git_grep ()\n \t__git_complete_refs\n }\n \n+__git_all_guides=\n+__git_compute_all_guides ()\n+{\n+\ttest -n \"$__git_all_guides\" ||\n+\t__git_all_guides=$(git --list-cmds=list-guide)\n+}\n+\n _git_help ()\n {\n \tcase \"$cur\" in\n@@ -1584,11 +1591,9 @@ _git_help ()\n \t\t;;\n \tesac\n \t__git_compute_all_commands\n-\t__gitcomp \"$__git_all_commands $(__git_aliases)\n-\t\tattributes cli core-tutorial cvs-migration\n-\t\tdiffcore everyday gitk glossary hooks ignore modules\n-\t\tnamespaces repository-layout revisions tutorial tutorial-2\n-\t\tworkflows\n+\t__git_compute_all_guides\n+\t__gitcomp \"$__git_all_commands $(__git_aliases) $__git_all_guides\n+\t\tgitk\n \t\t\"\n }\n \ndiff --git a/help.c b/help.c\nindex c7df1d2338..23924dd300 100644\n--- a/help.c\n+++ b/help.c\n@@ -39,12 +39,14 @@ static struct category_description main_categories[] = {\n \t{ 0, NULL }\n };\n \n-static const char *drop_prefix(const char *name)\n+static const char *drop_prefix(const char *name, uint32_t category)\n {\n \tconst char *new_name;\n \n \tif (skip_prefix(name, \"git-\", &new_name))\n \t\treturn new_name;\n+\tif (category == CAT_guide && skip_prefix(name, \"git\", &new_name))\n+\t\treturn new_name;\n \treturn name;\n \n }\n@@ -66,7 +68,7 @@ static void extract_cmds(struct cmdname_help **p_cmds, uint32_t mask)\n \t\t\tcontinue;\n \n \t\tcmds[nr] = *cmd;\n-\t\tcmds[nr].name = drop_prefix(cmd->name);\n+\t\tcmds[nr].name = drop_prefix(cmd->name, cmd->category);\n \n \t\tnr++;\n \t}\n@@ -358,11 +360,22 @@ void list_cmds_by_category(struct string_list *list,\n \tfor (i = 0; i < n; i++) {\n \t\tstruct cmdname_help *cmd = command_list + i;\n \n-\t\tif (cmd->category & cat_id)\n-\t\t\tstring_list_append(list, drop_prefix(cmd->name));\n+\t\tif (!(cmd->category & cat_id))\n+\t\t\tcontinue;\n+\t\tstring_list_append(list, drop_prefix(cmd->name, cmd->category));\n \t}\n }\n \n+void list_common_guides_help(void)\n+{\n+\tstruct category_description catdesc[] = {\n+\t\t{ CAT_guide, N_(\"The common Git guides are:\") },\n+\t\t{ 0, NULL }\n+\t};\n+\tprint_cmd_by_category(catdesc);\n+\tputchar('\\n');\n+}\n+\n void list_all_cmds_help(void)\n {\n \tprint_cmd_by_category(main_categories);\ndiff --git a/help.h b/help.h\nindex 40917fc38c..b2293e99be 100644\n--- a/help.h\n+++ b/help.h\n@@ -20,6 +20,7 @@ static inline void mput_char(char c, unsigned int num)\n \n extern void list_common_cmds_help(void);\n extern void list_all_cmds_help(void);\n+extern void list_common_guides_help(void);\n \n extern void list_all_main_cmds(struct string_list *list);\n extern void list_all_other_cmds(struct string_list *list);\ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex 060df24c2d..bc27df7f38 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -66,6 +66,12 @@ test_expect_success 'git help' '\n \ttest_i18ngrep \"^   commit \" help.output &&\n \ttest_i18ngrep \"^   fetch  \" help.output\n '\n+test_expect_success 'git help -g' '\n+\tgit help -g >help.output &&\n+\ttest_i18ngrep \"^   attributes \" help.output &&\n+\ttest_i18ngrep \"^   everyday   \" help.output &&\n+\ttest_i18ngrep \"^   tutorial   \" help.output\n+'\n \n test_expect_success 'generate builtin list' '\n \tgit --list-cmds=builtins >builtins\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347194","messageId":"20180510084652.25880-13-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180510084652.25880-1-pclouds@gmail.com","subject":"[PATCH v7 12/13] completion: let git provide the completable command list","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T08:46:51Z","receivedAt":"2018-05-10T08:47:35Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Instead of maintaining a separate list of command classification,\nwhich often could go out of date, let's centralize the information\nback in git.\n\nWhile the function in git-completion.bash implies \"list porcelain\ncommands\", that's not exactly what it does. It gets all commands (aka\n--list-cmds=main,others) then exclude certain non-porcelain ones. We\ncould almost recreate this list two lists list-mainporcelain and\nothers. The non-porcelain-but-included-anyway is added by the third\ncategory list-complete.\n\nlist-complete does not recreate exactly the command list before this\npatch though. The following commands are not part of neither\nlist-mainporcelain nor list-complete and as a result no longer\ncompletes:\n\n- annotate             obsolete, discouraged to use\n- difftool-helper      not an end user command\n- filter-branch        not often used\n- get-tar-commit-id    not often used\n- imap-send            not often used\n- interpreter-trailers not for interactive use\n- lost-found           obsolete\n- p4                   too short and probably not often used (*)\n- peek-remote          deprecated\n- svn                  same category as p4 (*)\n- tar-tree             obsolete\n- verify-commit        not often used\n\nNote that the current completion script incorrectly classifies\nfilter-branch as porcelain and t9902 tests this behavior. We keep it\nthis way in t9902 because this test does not really care which\nparticular command is porcelain or plubmbing, they're just names.\n\n(*) to be fair, send-email command which is in the same\nforeignscminterface group as svn and p4 does get completion, just\nbecause it's used by git and kernel development. So maybe should\ninclude them.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n command-list.txt                       |  37 ++++----\n contrib/completion/git-completion.bash | 117 ++++++-------------------\n t/t9902-completion.sh                  |   5 +-\n 3 files changed, 48 insertions(+), 111 deletions(-)\n\ndiff --git a/command-list.txt b/command-list.txt\nindex 9c70c69193..3e21ddfcfb 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -47,11 +47,11 @@\n git-add                                 mainporcelain           worktree\n git-am                                  mainporcelain\n git-annotate                            ancillaryinterrogators\n-git-apply                               plumbingmanipulators\n+git-apply                               plumbingmanipulators            complete\n git-archimport                          foreignscminterface\n git-archive                             mainporcelain\n git-bisect                              mainporcelain           info\n-git-blame                               ancillaryinterrogators\n+git-blame                               ancillaryinterrogators          complete\n git-branch                              mainporcelain           history\n git-bundle                              mainporcelain\n git-cat-file                            plumbinginterrogators\n@@ -61,7 +61,7 @@ git-check-mailmap                       purehelpers\n git-checkout                            mainporcelain           history\n git-checkout-index                      plumbingmanipulators\n git-check-ref-format                    purehelpers\n-git-cherry                              ancillaryinterrogators\n+git-cherry                              ancillaryinterrogators          complete\n git-cherry-pick                         mainporcelain\n git-citool                              mainporcelain\n git-clean                               mainporcelain\n@@ -69,7 +69,7 @@ git-clone                               mainporcelain           init\n git-column                              purehelpers\n git-commit                              mainporcelain           history\n git-commit-tree                         plumbingmanipulators\n-git-config                              ancillarymanipulators\n+git-config                              ancillarymanipulators           complete\n git-count-objects                       ancillaryinterrogators\n git-credential                          purehelpers\n git-credential-cache                    purehelpers\n@@ -83,7 +83,7 @@ git-diff                                mainporcelain           history\n git-diff-files                          plumbinginterrogators\n git-diff-index                          plumbinginterrogators\n git-diff-tree                           plumbinginterrogators\n-git-difftool                            ancillaryinterrogators\n+git-difftool                            ancillaryinterrogators          complete\n git-fast-export                         ancillarymanipulators\n git-fast-import                         ancillarymanipulators\n git-fetch                               mainporcelain           remote\n@@ -92,20 +92,20 @@ git-filter-branch                       ancillarymanipulators\n git-fmt-merge-msg                       purehelpers\n git-for-each-ref                        plumbinginterrogators\n git-format-patch                        mainporcelain\n-git-fsck                                ancillaryinterrogators\n+git-fsck                                ancillaryinterrogators          complete\n git-gc                                  mainporcelain\n git-get-tar-commit-id                   ancillaryinterrogators\n git-grep                                mainporcelain           info\n git-gui                                 mainporcelain\n git-hash-object                         plumbingmanipulators\n-git-help                                ancillaryinterrogators\n+git-help                                ancillaryinterrogators          complete\n git-http-backend                        synchingrepositories\n git-http-fetch                          synchelpers\n git-http-push                           synchelpers\n git-imap-send                           foreignscminterface\n git-index-pack                          plumbingmanipulators\n git-init                                mainporcelain           init\n-git-instaweb                            ancillaryinterrogators\n+git-instaweb                            ancillaryinterrogators          complete\n git-interpret-trailers                  purehelpers\n gitk                                    mainporcelain\n git-log                                 mainporcelain           info\n@@ -119,12 +119,12 @@ git-merge-base                          plumbinginterrogators\n git-merge-file                          plumbingmanipulators\n git-merge-index                         plumbingmanipulators\n git-merge-one-file                      purehelpers\n-git-mergetool                           ancillarymanipulators\n+git-mergetool                           ancillarymanipulators           complete\n git-merge-tree                          ancillaryinterrogators\n git-mktag                               plumbingmanipulators\n git-mktree                              plumbingmanipulators\n git-mv                                  mainporcelain           worktree\n-git-name-rev                            plumbinginterrogators\n+git-name-rev                            plumbinginterrogators           complete\n git-notes                               mainporcelain\n git-p4                                  foreignscminterface\n git-pack-objects                        plumbingmanipulators\n@@ -140,28 +140,29 @@ git-quiltimport                         foreignscminterface\n git-read-tree                           plumbingmanipulators\n git-rebase                              mainporcelain           history\n git-receive-pack                        synchelpers\n-git-reflog                              ancillarymanipulators\n-git-remote                              ancillarymanipulators\n-git-repack                              ancillarymanipulators\n-git-replace                             ancillarymanipulators\n-git-request-pull                        foreignscminterface\n+git-reflog                              ancillarymanipulators           complete\n+git-remote                              ancillarymanipulators           complete\n+git-repack                              ancillarymanipulators           complete\n+git-replace                             ancillarymanipulators           complete\n+git-request-pull                        foreignscminterface             complete\n git-rerere                              ancillaryinterrogators\n git-reset                               mainporcelain           worktree\n git-revert                              mainporcelain\n git-rev-list                            plumbinginterrogators\n git-rev-parse                           ancillaryinterrogators\n git-rm                                  mainporcelain           worktree\n-git-send-email                          foreignscminterface\n+git-send-email                          foreignscminterface             complete\n git-send-pack                           synchingrepositories\n git-shell                               synchelpers\n git-shortlog                            mainporcelain\n git-show                                mainporcelain           info\n-git-show-branch                         ancillaryinterrogators\n+git-show-branch                         ancillaryinterrogators          complete\n git-show-index                          plumbinginterrogators\n git-show-ref                            plumbinginterrogators\n git-sh-i18n                             purehelpers\n git-sh-setup                            purehelpers\n git-stash                               mainporcelain\n+git-stage                                                               complete\n git-status                              mainporcelain           info\n git-stripspace                          purehelpers\n git-submodule                           mainporcelain\n@@ -180,7 +181,7 @@ git-verify-commit                       ancillaryinterrogators\n git-verify-pack                         plumbinginterrogators\n git-verify-tag                          ancillaryinterrogators\n gitweb                                  ancillaryinterrogators\n-git-whatchanged                         ancillaryinterrogators\n+git-whatchanged                         ancillaryinterrogators          complete\n git-worktree                            mainporcelain\n git-write-tree                          plumbingmanipulators\n gitattributes                           guide\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 4e724a5b76..908692ea52 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -835,18 +835,30 @@ __git_complete_strategy ()\n }\n \n __git_commands () {\n-\tif test -n \"${GIT_TESTING_COMMAND_COMPLETION:-}\"\n-\tthen\n-\t\tprintf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n-\telse\n-\t\tgit --list-cmds=main,others\n-\tfi\n+\tcase \"$1\" in\n+\tporcelain)\n+\t\tif test -n \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\"\n+\t\tthen\n+\t\t\tprintf \"%s\" \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\"\n+\t\telse\n+\t\t\tgit --list-cmds=list-mainporcelain,others,list-complete\n+\t\tfi\n+\t\t;;\n+\tall)\n+\t\tif test -n \"$GIT_TESTING_ALL_COMMAND_LIST\"\n+\t\tthen\n+\t\t\tprintf \"%s\" \"$GIT_TESTING_ALL_COMMAND_LIST\"\n+\t\telse\n+\t\t\tgit --list-cmds=main,others\n+\t\tfi\n+\t\t;;\n+\tesac\n }\n \n-__git_list_all_commands ()\n+__git_list_commands ()\n {\n \tlocal i IFS=\" \"$'\\n'\n-\tfor i in $(__git_commands)\n+\tfor i in $(__git_commands $1)\n \tdo\n \t\tcase $i in\n \t\t*--*)             : helper pattern;;\n@@ -855,6 +867,11 @@ __git_list_all_commands ()\n \tdone\n }\n \n+__git_list_all_commands ()\n+{\n+\t__git_list_commands all\n+}\n+\n __git_all_commands=\n __git_compute_all_commands ()\n {\n@@ -864,89 +881,7 @@ __git_compute_all_commands ()\n \n __git_list_porcelain_commands ()\n {\n-\tlocal i IFS=\" \"$'\\n'\n-\t__git_compute_all_commands\n-\tfor i in $__git_all_commands\n-\tdo\n-\t\tcase $i in\n-\t\t*--*)             : helper pattern;;\n-\t\tapplymbox)        : ask gittus;;\n-\t\tapplypatch)       : ask gittus;;\n-\t\tarchimport)       : import;;\n-\t\tcat-file)         : plumbing;;\n-\t\tcheck-attr)       : plumbing;;\n-\t\tcheck-ignore)     : plumbing;;\n-\t\tcheck-mailmap)    : plumbing;;\n-\t\tcheck-ref-format) : plumbing;;\n-\t\tcheckout-index)   : plumbing;;\n-\t\tcolumn)           : internal helper;;\n-\t\tcommit-tree)      : plumbing;;\n-\t\tcount-objects)    : infrequent;;\n-\t\tcredential)       : credentials;;\n-\t\tcredential-*)     : credentials helper;;\n-\t\tcvsexportcommit)  : export;;\n-\t\tcvsimport)        : import;;\n-\t\tcvsserver)        : daemon;;\n-\t\tdaemon)           : daemon;;\n-\t\tdiff-files)       : plumbing;;\n-\t\tdiff-index)       : plumbing;;\n-\t\tdiff-tree)        : plumbing;;\n-\t\tfast-import)      : import;;\n-\t\tfast-export)      : export;;\n-\t\tfsck-objects)     : plumbing;;\n-\t\tfetch-pack)       : plumbing;;\n-\t\tfmt-merge-msg)    : plumbing;;\n-\t\tfor-each-ref)     : plumbing;;\n-\t\thash-object)      : plumbing;;\n-\t\thttp-*)           : transport;;\n-\t\tindex-pack)       : plumbing;;\n-\t\tinit-db)          : deprecated;;\n-\t\tlocal-fetch)      : plumbing;;\n-\t\tls-files)         : plumbing;;\n-\t\tls-remote)        : plumbing;;\n-\t\tls-tree)          : plumbing;;\n-\t\tmailinfo)         : plumbing;;\n-\t\tmailsplit)        : plumbing;;\n-\t\tmerge-*)          : plumbing;;\n-\t\tmktree)           : plumbing;;\n-\t\tmktag)            : plumbing;;\n-\t\tpack-objects)     : plumbing;;\n-\t\tpack-redundant)   : plumbing;;\n-\t\tpack-refs)        : plumbing;;\n-\t\tparse-remote)     : plumbing;;\n-\t\tpatch-id)         : plumbing;;\n-\t\tprune)            : plumbing;;\n-\t\tprune-packed)     : plumbing;;\n-\t\tquiltimport)      : import;;\n-\t\tread-tree)        : plumbing;;\n-\t\treceive-pack)     : plumbing;;\n-\t\tremote-*)         : transport;;\n-\t\trerere)           : plumbing;;\n-\t\trev-list)         : plumbing;;\n-\t\trev-parse)        : plumbing;;\n-\t\trunstatus)        : plumbing;;\n-\t\tsh-setup)         : internal;;\n-\t\tshell)            : daemon;;\n-\t\tshow-ref)         : plumbing;;\n-\t\tsend-pack)        : plumbing;;\n-\t\tshow-index)       : plumbing;;\n-\t\tssh-*)            : transport;;\n-\t\tstripspace)       : plumbing;;\n-\t\tsymbolic-ref)     : plumbing;;\n-\t\tunpack-file)      : plumbing;;\n-\t\tunpack-objects)   : plumbing;;\n-\t\tupdate-index)     : plumbing;;\n-\t\tupdate-ref)       : plumbing;;\n-\t\tupdate-server-info) : daemon;;\n-\t\tupload-archive)   : plumbing;;\n-\t\tupload-pack)      : plumbing;;\n-\t\twrite-tree)       : plumbing;;\n-\t\tvar)              : infrequent;;\n-\t\tverify-pack)      : infrequent;;\n-\t\tverify-tag)       : plumbing;;\n-\t\t*) echo $i;;\n-\t\tesac\n-\tdone\n+\t__git_list_commands porcelain\n }\n \n __git_porcelain_commands=\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 1b34caa1e1..2f16679380 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -13,7 +13,7 @@ complete ()\n \treturn 0\n }\n \n-# Be careful when updating this list:\n+# Be careful when updating these lists:\n #\n # (1) The build tree may have build artifact from different branch, or\n #     the user's $PATH may have a random executable that may begin\n@@ -30,7 +30,8 @@ complete ()\n #     completion for \"git <TAB>\", and a plumbing is excluded.  \"add\",\n #     \"filter-branch\" and \"ls-files\" are listed for this.\n \n-GIT_TESTING_COMMAND_COMPLETION='add checkout check-attr filter-branch ls-files'\n+GIT_TESTING_ALL_COMMAND_LIST='add checkout check-attr filter-branch ls-files'\n+GIT_TESTING_PORCELAIN_COMMAND_LIST='add checkout filter-branch'\n \n . \"$GIT_BUILD_DIR/contrib/completion/git-completion.bash\"\n \n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347195","messageId":"20180510084652.25880-14-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180510084652.25880-1-pclouds@gmail.com","subject":"[PATCH v7 13/13] completion: allow to customize the completable command list","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T08:46:52Z","receivedAt":"2018-05-10T08:47:38Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"By default we show porcelain, external commands and a couple others\nthat are also popular. If you are not happy with this list, you can\nnow customize it. See the big comment block for details.\n\nPS. perhaps I should make aliases a group too, which makes it possible\nto _not_ complete aliases by omitting this special group in\n$GIT_COMPLETION_CMD_GROUPS\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/config.txt               | 10 ++++++++\n contrib/completion/git-completion.bash | 28 +++++++++++++++++++++-\n git.c                                  |  2 ++\n help.c                                 | 33 ++++++++++++++++++++++++++\n help.h                                 |  1 +\n 5 files changed, 73 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 2659153cb3..91f7eaed7b 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1343,6 +1343,16 @@ credential.<url>.*::\n credentialCache.ignoreSIGHUP::\n \tTell git-credential-cache--daemon to ignore SIGHUP, instead of quitting.\n \n+completion.commands::\n+\tThis is only used by git-completion.bash to add or remove\n+\tcommands from the complete list. Normally only porcelain\n+\tcommands and a few select others are in the complete list. You\n+\tcan add more commands, separated by space, in this\n+\tvariable. Prefixing the command with '-' will remove it from\n+\tthe existing list.\n++\n+This variable should not be per-repository.\n+\n include::diff-config.txt[]\n \n difftool.<tool>.path::\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 908692ea52..f7ca9a4d4f 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -38,6 +38,29 @@\n #\n #     When set to \"1\", do not include \"DWIM\" suggestions in git-checkout\n #     completion (e.g., completing \"foo\" when \"origin/foo\" exists).\n+#\n+#   GIT_COMPLETION_CMD_GROUPS\n+#\n+#     When set, \"git --list-cmds=$GIT_COMPLETION_CMD_GROUPS\" will be\n+#     used to get the list of completable commands. The default is\n+#     \"mainporcelain,others,list-complete\" (in English: all porcelain\n+#     commands and external ones are included. Certain non-porcelain\n+#     commands are also marked for completion in command-list.txt).\n+#     You could for example complete all commands with\n+#\n+#         GIT_COMPLETION_CMD_GROUPS=main,others\n+#\n+#     Or you could go with main porcelain only and extra commands in\n+#     the configuration variable completion.commands with\n+#\n+#         GIT_COMPLETION_CMD_GROUPS=mainporcelain,config\n+#\n+#     Or go completely custom group with\n+#\n+#         GIT_COMPLETION_CMD_GROUPS=config\n+#\n+#     Or you could even play with other command categories found in\n+#     command-list.txt.\n \n case \"$COMP_WORDBREAKS\" in\n *:*) : great ;;\n@@ -840,8 +863,11 @@ __git_commands () {\n \t\tif test -n \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\"\n \t\tthen\n \t\t\tprintf \"%s\" \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\"\n+\t\telif test -n \"$GIT_COMPLETION_CMD_GROUPS\"\n+\t\tthen\n+\t\t\tgit --list-cmds=\"$GIT_COMPLETION_CMD_GROUPS\"\n \t\telse\n-\t\t\tgit --list-cmds=list-mainporcelain,others,list-complete\n+\t\t\tgit --list-cmds=list-mainporcelain,others,list-complete,config\n \t\tfi\n \t\t;;\n \tall)\ndiff --git a/git.c b/git.c\nindex 4d5b8a9931..ea4feedd0b 100644\n--- a/git.c\n+++ b/git.c\n@@ -60,6 +60,8 @@ static int list_cmds(const char *spec)\n \t\t\tlist_all_main_cmds(&list);\n \t\telse if (match_token(spec, len, \"others\"))\n \t\t\tlist_all_other_cmds(&list);\n+\t\telse if (match_token(spec, len, \"config\"))\n+\t\t\tlist_cmds_by_config(&list);\n \t\telse if (len > 5 && !strncmp(spec, \"list-\", 5)) {\n \t\t\tstruct strbuf sb = STRBUF_INIT;\n \ndiff --git a/help.c b/help.c\nindex 23924dd300..abf87205b2 100644\n--- a/help.c\n+++ b/help.c\n@@ -366,6 +366,39 @@ void list_cmds_by_category(struct string_list *list,\n \t}\n }\n \n+void list_cmds_by_config(struct string_list *list)\n+{\n+\tconst char *cmd_list;\n+\n+\t/*\n+\t * There's no actual repository setup at this point (and even\n+\t * if there is, we don't really care; only global config\n+\t * matters). If we accidentally set up a repository, it's ok\n+\t * too since the caller (git --list-cmds=) should exit shortly\n+\t * anyway.\n+\t */\n+\tif (git_config_get_string_const(\"completion.commands\", &cmd_list))\n+\t\treturn;\n+\n+\tstring_list_sort(list);\n+\tstring_list_remove_duplicates(list, 0);\n+\n+\twhile (*cmd_list) {\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\t\tconst char *p = strchrnul(cmd_list, ' ');\n+\n+\t\tstrbuf_add(&sb, cmd_list, p - cmd_list);\n+\t\tif (*cmd_list == '-')\n+\t\t\tstring_list_remove(list, cmd_list + 1, 0);\n+\t\telse\n+\t\t\tstring_list_insert(list, sb.buf);\n+\t\tstrbuf_release(&sb);\n+\t\twhile (*p == ' ')\n+\t\t\tp++;\n+\t\tcmd_list = p;\n+\t}\n+}\n+\n void list_common_guides_help(void)\n {\n \tstruct category_description catdesc[] = {\ndiff --git a/help.h b/help.h\nindex b2293e99be..3b38292a1b 100644\n--- a/help.h\n+++ b/help.h\n@@ -26,6 +26,7 @@ extern void list_all_main_cmds(struct string_list *list);\n extern void list_all_other_cmds(struct string_list *list);\n extern void list_cmds_by_category(struct string_list *list,\n \t\t\t\t  const char *category);\n+extern void list_cmds_by_config(struct string_list *list);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347196","messageId":"20180510084652.25880-6-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180510084652.25880-1-pclouds@gmail.com","subject":"[PATCH v7 05/13] git.c: convert --list-* to --list-cmds=*","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T08:46:44Z","receivedAt":"2018-05-10T08:47:47Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Even if these are hidden options, let's make them a bit more generic\nsince we're introducing more listing types shortly. The code is\nstructured to allow combining multiple listing types together because\nwe will soon add more types the 'builtins'.\n\n'parseopt' remains separate because it has separate (SPC) to match\ngit-completion.bash needs and will not combine with others.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash |  2 +-\n git.c                                  | 37 +++++++++++++++++++++-----\n t/t0012-help.sh                        |  2 +-\n 3 files changed, 33 insertions(+), 8 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex a757073945..3556838759 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -3049,7 +3049,7 @@ __git_complete_common () {\n __git_cmds_with_parseopt_helper=\n __git_support_parseopt_helper () {\n \ttest -n \"$__git_cmds_with_parseopt_helper\" ||\n-\t\t__git_cmds_with_parseopt_helper=\"$(__git --list-parseopt-builtins)\"\n+\t\t__git_cmds_with_parseopt_helper=\"$(__git --list-cmds=parseopt)\"\n \n \tcase \" $__git_cmds_with_parseopt_helper \" in\n \t*\" $1 \"*)\ndiff --git a/git.c b/git.c\nindex 3a89893712..cd85355d81 100644\n--- a/git.c\n+++ b/git.c\n@@ -38,6 +38,30 @@ static int use_pager = -1;\n \n static void list_builtins(unsigned int exclude_option, char sep);\n \n+static int match_token(const char *spec, int len, const char *token)\n+{\n+\tint token_len = strlen(token);\n+\n+\treturn len == token_len && !strncmp(spec, token, token_len);\n+}\n+\n+static int list_cmds(const char *spec)\n+{\n+\twhile (*spec) {\n+\t\tconst char *sep = strchrnul(spec, ',');\n+\t\tint len = sep - spec;\n+\n+\t\tif (match_token(spec, len, \"builtins\"))\n+\t\t\tlist_builtins(0, '\\n');\n+\t\telse\n+\t\t\tdie(_(\"unsupported command listing type '%s'\"), spec);\n+\t\tspec += len;\n+\t\tif (*spec == ',')\n+\t\t\tspec++;\n+\t}\n+\treturn 0;\n+}\n+\n static void commit_pager_choice(void) {\n \tswitch (use_pager) {\n \tcase 0:\n@@ -223,12 +247,13 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t}\n \t\t\t(*argv)++;\n \t\t\t(*argc)--;\n-\t\t} else if (!strcmp(cmd, \"--list-builtins\")) {\n-\t\t\tlist_builtins(0, '\\n');\n-\t\t\texit(0);\n-\t\t} else if (!strcmp(cmd, \"--list-parseopt-builtins\")) {\n-\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n-\t\t\texit(0);\n+\t\t} else if (skip_prefix(cmd, \"--list-cmds=\", &cmd)) {\n+\t\t\tif (!strcmp(cmd, \"parseopt\")) {\n+\t\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n+\t\t\t\texit(0);\n+\t\t\t} else {\n+\t\t\t\texit(list_cmds(cmd));\n+\t\t\t}\n \t\t} else {\n \t\t\tfprintf(stderr, _(\"unknown option: %s\\n\"), cmd);\n \t\t\tusage(git_usage_string);\ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex c096f33505..3c91a9024a 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -59,7 +59,7 @@ test_expect_success 'git help' '\n '\n \n test_expect_success 'generate builtin list' '\n-\tgit --list-builtins >builtins\n+\tgit --list-cmds=builtins >builtins\n '\n \n while read builtin\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347197","messageId":"20180510084652.25880-7-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180510084652.25880-1-pclouds@gmail.com","subject":"[PATCH v7 06/13] git --list-cmds: collect command list in a string_list","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T08:46:45Z","receivedAt":"2018-05-10T08:47:49Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Instead of printing the command directly one by one, keep them in a\nlist and print at the end. This allows more modification before we\nprint out (e.g. sorting, removing duplicates or even excluding some\nitems).\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n git.c | 22 +++++++++++++++++-----\n 1 file changed, 17 insertions(+), 5 deletions(-)\n\ndiff --git a/git.c b/git.c\nindex cd85355d81..376a59b97f 100644\n--- a/git.c\n+++ b/git.c\n@@ -36,7 +36,7 @@ const char git_more_info_string[] =\n \n static int use_pager = -1;\n \n-static void list_builtins(unsigned int exclude_option, char sep);\n+static void list_builtins(struct string_list *list, unsigned int exclude_option);\n \n static int match_token(const char *spec, int len, const char *token)\n {\n@@ -47,18 +47,24 @@ static int match_token(const char *spec, int len, const char *token)\n \n static int list_cmds(const char *spec)\n {\n+\tstruct string_list list = STRING_LIST_INIT_DUP;\n+\tint i;\n+\n \twhile (*spec) {\n \t\tconst char *sep = strchrnul(spec, ',');\n \t\tint len = sep - spec;\n \n \t\tif (match_token(spec, len, \"builtins\"))\n-\t\t\tlist_builtins(0, '\\n');\n+\t\t\tlist_builtins(&list, 0);\n \t\telse\n \t\t\tdie(_(\"unsupported command listing type '%s'\"), spec);\n \t\tspec += len;\n \t\tif (*spec == ',')\n \t\t\tspec++;\n \t}\n+\tfor (i = 0; i < list.nr; i++)\n+\t\tputs(list.items[i].string);\n+\tstring_list_clear(&list, 0);\n \treturn 0;\n }\n \n@@ -249,7 +255,13 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)\n \t\t\t(*argc)--;\n \t\t} else if (skip_prefix(cmd, \"--list-cmds=\", &cmd)) {\n \t\t\tif (!strcmp(cmd, \"parseopt\")) {\n-\t\t\t\tlist_builtins(NO_PARSEOPT, ' ');\n+\t\t\t\tstruct string_list list = STRING_LIST_INIT_DUP;\n+\t\t\t\tint i;\n+\n+\t\t\t\tlist_builtins(&list, NO_PARSEOPT);\n+\t\t\t\tfor (i = 0; i < list.nr; i++)\n+\t\t\t\t\tprintf(\"%s \", list.items[i].string);\n+\t\t\t\tstring_list_clear(&list, 0);\n \t\t\t\texit(0);\n \t\t\t} else {\n \t\t\t\texit(list_cmds(cmd));\n@@ -533,14 +545,14 @@ int is_builtin(const char *s)\n \treturn !!get_builtin(s);\n }\n \n-static void list_builtins(unsigned int exclude_option, char sep)\n+static void list_builtins(struct string_list *out, unsigned int exclude_option)\n {\n \tint i;\n \tfor (i = 0; i < ARRAY_SIZE(commands); i++) {\n \t\tif (exclude_option &&\n \t\t    (commands[i].option & exclude_option))\n \t\t\tcontinue;\n-\t\tprintf(\"%s%c\", commands[i].cmd, sep);\n+\t\tstring_list_append(out, commands[i].cmd);\n \t}\n }\n \n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347198","messageId":"20180510084652.25880-8-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180510084652.25880-1-pclouds@gmail.com","subject":"[PATCH v7 07/13] completion: implement and use --list-cmds=main,others","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T08:46:46Z","receivedAt":"2018-05-10T08:47:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Instead of parsing \"git help -a\" output, which is tricky to get right,\nless elegant and also slow, make git provide the list in a\nmachine-friendly form. This adds two separate listing types, main and\nothers, instead of just \"all\" for more flexibility.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n contrib/completion/git-completion.bash |  2 +-\n git.c                                  |  4 ++++\n help.c                                 | 32 ++++++++++++++++++++++++++\n help.h                                 |  4 ++++\n 4 files changed, 41 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 3556838759..62ca8641f4 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -839,7 +839,7 @@ __git_commands () {\n \tthen\n \t\tprintf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n \telse\n-\t\tgit help -a|egrep '^  [a-zA-Z0-9]'\n+\t\tgit --list-cmds=main,others\n \tfi\n }\n \ndiff --git a/git.c b/git.c\nindex 376a59b97f..10907f7266 100644\n--- a/git.c\n+++ b/git.c\n@@ -56,6 +56,10 @@ static int list_cmds(const char *spec)\n \n \t\tif (match_token(spec, len, \"builtins\"))\n \t\t\tlist_builtins(&list, 0);\n+\t\telse if (match_token(spec, len, \"main\"))\n+\t\t\tlist_all_main_cmds(&list);\n+\t\telse if (match_token(spec, len, \"others\"))\n+\t\t\tlist_all_other_cmds(&list);\n \t\telse\n \t\t\tdie(_(\"unsupported command listing type '%s'\"), spec);\n \t\tspec += len;\ndiff --git a/help.c b/help.c\nindex 2d6a3157f8..d5ce9dfcbb 100644\n--- a/help.c\n+++ b/help.c\n@@ -297,6 +297,38 @@ void list_common_cmds_help(void)\n \tprint_cmd_by_category(common_categories);\n }\n \n+void list_all_main_cmds(struct string_list *list)\n+{\n+\tstruct cmdnames main_cmds, other_cmds;\n+\tint i;\n+\n+\tmemset(&main_cmds, 0, sizeof(main_cmds));\n+\tmemset(&other_cmds, 0, sizeof(other_cmds));\n+\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n+\n+\tfor (i = 0; i < main_cmds.cnt; i++)\n+\t\tstring_list_append(list, main_cmds.names[i]->name);\n+\n+\tclean_cmdnames(&main_cmds);\n+\tclean_cmdnames(&other_cmds);\n+}\n+\n+void list_all_other_cmds(struct string_list *list)\n+{\n+\tstruct cmdnames main_cmds, other_cmds;\n+\tint i;\n+\n+\tmemset(&main_cmds, 0, sizeof(main_cmds));\n+\tmemset(&other_cmds, 0, sizeof(other_cmds));\n+\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n+\n+\tfor (i = 0; i < other_cmds.cnt; i++)\n+\t\tstring_list_append(list, other_cmds.names[i]->name);\n+\n+\tclean_cmdnames(&main_cmds);\n+\tclean_cmdnames(&other_cmds);\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex b21d7c94e8..97e6c0965e 100644\n--- a/help.h\n+++ b/help.h\n@@ -1,6 +1,8 @@\n #ifndef HELP_H\n #define HELP_H\n \n+struct string_list;\n+\n struct cmdnames {\n \tint alloc;\n \tint cnt;\n@@ -17,6 +19,8 @@ static inline void mput_char(char c, unsigned int num)\n }\n \n extern void list_common_cmds_help(void);\n+extern void list_all_main_cmds(struct string_list *list);\n+extern void list_all_other_cmds(struct string_list *list);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347199","messageId":"20180510084652.25880-9-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180510084652.25880-1-pclouds@gmail.com","subject":"[PATCH v7 08/13] git: support --list-cmds=list-<category>","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T08:46:47Z","receivedAt":"2018-05-10T08:47:53Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This allows us to select any group of commands by a category defined\nin command-list.txt. This is an internal/hidden option so we don't\nhave to be picky about the category name or worried about exposing too\nmuch.\n\nThis will be used later by git-completion.bash to retrieve certain\ncommand groups.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n generate-cmdlist.sh | 17 +++++++++++++++++\n git.c               |  7 +++++++\n help.c              | 23 +++++++++++++++++++++++\n help.h              |  2 ++\n 4 files changed, 49 insertions(+)\n\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 3bcc1ee57d..8d6d8b45ce 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -45,6 +45,21 @@ define_categories () {\n \ttest \"$bit\" -gt 32 && die \"Urgh.. too many categories?\"\n }\n \n+define_category_names () {\n+\techo\n+\techo \"/* Category names */\"\n+\techo \"static const char *category_names[] = {\"\n+\tbit=0\n+\tcategory_list \"$1\" |\n+\twhile read cat\n+\tdo\n+\t\techo \"\t\\\"$cat\\\", /* (1UL << $bit) */\"\n+\t\tbit=$(($bit+1))\n+\tdone\n+\techo \"\tNULL\"\n+\techo \"};\"\n+}\n+\n print_command_list () {\n \techo \"static struct cmdname_help command_list[] = {\"\n \n@@ -70,4 +85,6 @@ struct cmdname_help {\n \"\n define_categories \"$1\"\n echo\n+define_category_names \"$1\"\n+echo\n print_command_list \"$1\"\ndiff --git a/git.c b/git.c\nindex 10907f7266..4d5b8a9931 100644\n--- a/git.c\n+++ b/git.c\n@@ -60,6 +60,13 @@ static int list_cmds(const char *spec)\n \t\t\tlist_all_main_cmds(&list);\n \t\telse if (match_token(spec, len, \"others\"))\n \t\t\tlist_all_other_cmds(&list);\n+\t\telse if (len > 5 && !strncmp(spec, \"list-\", 5)) {\n+\t\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\t\tstrbuf_add(&sb, spec + 5, len - 5);\n+\t\t\tlist_cmds_by_category(&list, sb.buf);\n+\t\t\tstrbuf_release(&sb);\n+\t\t}\n \t\telse\n \t\t\tdie(_(\"unsupported command listing type '%s'\"), spec);\n \t\tspec += len;\ndiff --git a/help.c b/help.c\nindex d5ce9dfcbb..1117f7d1d1 100644\n--- a/help.c\n+++ b/help.c\n@@ -329,6 +329,29 @@ void list_all_other_cmds(struct string_list *list)\n \tclean_cmdnames(&other_cmds);\n }\n \n+void list_cmds_by_category(struct string_list *list,\n+\t\t\t   const char *cat)\n+{\n+\tint i, n = ARRAY_SIZE(command_list);\n+\tuint32_t cat_id = 0;\n+\n+\tfor (i = 0; category_names[i]; i++) {\n+\t\tif (!strcmp(cat, category_names[i])) {\n+\t\t\tcat_id = 1UL << i;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\tif (!cat_id)\n+\t\tdie(_(\"unsupported command listing type '%s'\"), cat);\n+\n+\tfor (i = 0; i < n; i++) {\n+\t\tstruct cmdname_help *cmd = command_list + i;\n+\n+\t\tif (cmd->category & cat_id)\n+\t\t\tstring_list_append(list, drop_prefix(cmd->name));\n+\t}\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex 97e6c0965e..734bba32d3 100644\n--- a/help.h\n+++ b/help.h\n@@ -21,6 +21,8 @@ static inline void mput_char(char c, unsigned int num)\n extern void list_common_cmds_help(void);\n extern void list_all_main_cmds(struct string_list *list);\n extern void list_all_other_cmds(struct string_list *list);\n+extern void list_cmds_by_category(struct string_list *list,\n+\t\t\t\t  const char *category);\n extern const char *help_unknown_cmd(const char *cmd);\n extern void load_command_list(const char *prefix,\n \t\t\t      struct cmdnames *main_cmds,\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347200","messageId":"20180510084652.25880-10-pclouds@gmail.com","threadId":"48155","inReplyTo":"20180510084652.25880-1-pclouds@gmail.com","subject":"[PATCH v7 09/13] help: add \"-a --verbose\" to list all commands with synopsis","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T08:46:48Z","receivedAt":"2018-05-10T08:47:57Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This lists all recognized commands [1] by category. The group order\nfollows closely git.txt.\n\n[1] We may actually show commands that are not built (e.g. if you set\nNO_PERL you don't have git-instaweb but it's still listed here). I\nignore the problem because on Linux a git package could be split\nanyway. The \"git-core\" package may not contain git-instaweb even if\nit's built because it may end up in a separate package. We can't know\nanyway.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-help.txt |  4 +++-\n builtin/help.c             |  7 +++++++\n help.c                     | 16 ++++++++++++++++\n help.h                     |  2 ++\n t/t0012-help.sh            |  9 +++++++++\n 5 files changed, 37 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-help.txt b/Documentation/git-help.txt\nindex 40d328a4b3..a40fc38d8b 100644\n--- a/Documentation/git-help.txt\n+++ b/Documentation/git-help.txt\n@@ -8,7 +8,7 @@ git-help - Display help information about Git\n SYNOPSIS\n --------\n [verse]\n-'git help' [-a|--all] [-g|--guide]\n+'git help' [-a|--all [--verbose]] [-g|--guide]\n \t   [-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE]\n \n DESCRIPTION\n@@ -42,6 +42,8 @@ OPTIONS\n --all::\n \tPrints all the available commands on the standard output. This\n \toption overrides any given command or guide name.\n+\tWhen used with `--verbose` print description for all recognized\n+\tcommands.\n \n -g::\n --guides::\ndiff --git a/builtin/help.c b/builtin/help.c\nindex 598867cfea..0e0af8426a 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -36,6 +36,7 @@ static const char *html_path;\n \n static int show_all = 0;\n static int show_guides = 0;\n+static int verbose;\n static unsigned int colopts;\n static enum help_format help_format = HELP_FORMAT_NONE;\n static int exclude_guides;\n@@ -48,6 +49,7 @@ static struct option builtin_help_options[] = {\n \t\t\tHELP_FORMAT_WEB),\n \tOPT_SET_INT('i', \"info\", &help_format, N_(\"show info page\"),\n \t\t\tHELP_FORMAT_INFO),\n+\tOPT__VERBOSE(&verbose, N_(\"print command description\")),\n \tOPT_END(),\n };\n \n@@ -463,6 +465,11 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \tif (show_all) {\n \t\tgit_config(git_help_config, NULL);\n+\t\tif (verbose) {\n+\t\t\tsetup_pager();\n+\t\t\tlist_all_cmds_help();\n+\t\t\treturn 0;\n+\t\t}\n \t\tprintf(_(\"usage: %s%s\"), _(git_usage_string), \"\\n\\n\");\n \t\tload_command_list(\"git-\", &main_cmds, &other_cmds);\n \t\tlist_commands(colopts, &main_cmds, &other_cmds);\ndiff --git a/help.c b/help.c\nindex 1117f7d1d1..c7df1d2338 100644\n--- a/help.c\n+++ b/help.c\n@@ -27,6 +27,17 @@ static struct category_description common_categories[] = {\n \t{ CAT_remote, N_(\"collaborate (see also: git help workflows)\") },\n \t{ 0, NULL }\n };\n+static struct category_description main_categories[] = {\n+\t{ CAT_mainporcelain, N_(\"Main Porcelain Commands\") },\n+\t{ CAT_ancillarymanipulators, N_(\"Ancillary Commands / Manipulators\") },\n+\t{ CAT_ancillaryinterrogators, N_(\"Ancillary Commands / Interrogators\") },\n+\t{ CAT_foreignscminterface, N_(\"Interacting with Others\") },\n+\t{ CAT_plumbingmanipulators, N_(\"Low-level Commands / Manipulators\") },\n+\t{ CAT_plumbinginterrogators, N_(\"Low-level Commands / Interrogators\") },\n+\t{ CAT_synchingrepositories, N_(\"Low-level Commands / Synching Repositories\") },\n+\t{ CAT_purehelpers, N_(\"Low-level Commands / Internal Helpers\") },\n+\t{ 0, NULL }\n+};\n \n static const char *drop_prefix(const char *name)\n {\n@@ -352,6 +363,11 @@ void list_cmds_by_category(struct string_list *list,\n \t}\n }\n \n+void list_all_cmds_help(void)\n+{\n+\tprint_cmd_by_category(main_categories);\n+}\n+\n int is_in_cmdlist(struct cmdnames *c, const char *s)\n {\n \tint i;\ndiff --git a/help.h b/help.h\nindex 734bba32d3..40917fc38c 100644\n--- a/help.h\n+++ b/help.h\n@@ -19,6 +19,8 @@ static inline void mput_char(char c, unsigned int num)\n }\n \n extern void list_common_cmds_help(void);\n+extern void list_all_cmds_help(void);\n+\n extern void list_all_main_cmds(struct string_list *list);\n extern void list_all_other_cmds(struct string_list *list);\n extern void list_cmds_by_category(struct string_list *list,\ndiff --git a/t/t0012-help.sh b/t/t0012-help.sh\nindex 3c91a9024a..060df24c2d 100755\n--- a/t/t0012-help.sh\n+++ b/t/t0012-help.sh\n@@ -25,6 +25,15 @@ test_expect_success \"setup\" '\n \tEOF\n '\n \n+# make sure to exercise these code paths, the output is a bit tricky\n+# to verify\n+test_expect_success 'basic help commands' '\n+\tgit help >/dev/null &&\n+\tgit help -a >/dev/null &&\n+\tgit help -g >/dev/null &&\n+\tgit help -av >/dev/null\n+'\n+\n test_expect_success \"works for commands and guides by default\" '\n \tconfigure_help &&\n \tgit help status &&\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347357","messageId":"CAM0VKjk3kqKpVz0ZjX58REwP8rz08kLsiVR4NWDO6-9iPGPe9g@mail.gmail.com","threadId":"48155","inReplyTo":"20180510084652.25880-8-pclouds@gmail.com","subject":"Re: [PATCH v7 07/13] completion: implement and use --list-cmds=main,others","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-05-11T14:06:27Z","receivedAt":"2018-05-11T14:06:31Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Thu, May 10, 2018 at 10:46 AM, Nguyễn Thái Ngọc Duy\n<pclouds@gmail.com> wrote:\n> Instead of parsing \"git help -a\" output, which is tricky to get right,\n> less elegant and also slow,\n\nIs it tricky?  It seems rather straightforward.\nIs it slow?  Well, there is a pipe and an egrep, sure, but thanks to\ncaching it's only run once, so basically doesn't matter.\n\nOTOH you don't mention the most important reason, namely that the\ncompletion script contains a long hard-coded list of the names of all\nknown plumbing commands to filter out, which is redundant with the\ncategorization in 'command-list.txt', is a maintenance burden, and\ntends to get out-of-sync when new plumbing commands are added.\n\n> make git provide the list in a\n> machine-friendly form. This adds two separate listing types, main and\n> others, instead of just \"all\" for more flexibility.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  contrib/completion/git-completion.bash |  2 +-\n>  git.c                                  |  4 ++++\n>  help.c                                 | 32 ++++++++++++++++++++++++++\n>  help.h                                 |  4 ++++\n>  4 files changed, 41 insertions(+), 1 deletion(-)\n>\n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> index 3556838759..62ca8641f4 100644\n> --- a/contrib/completion/git-completion.bash\n> +++ b/contrib/completion/git-completion.bash\n> @@ -839,7 +839,7 @@ __git_commands () {\n>         then\n>                 printf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n>         else\n> -               git help -a|egrep '^  [a-zA-Z0-9]'\n> +               git --list-cmds=main,others\n>         fi\n>  }\n>\n> diff --git a/git.c b/git.c\n> index 376a59b97f..10907f7266 100644\n> --- a/git.c\n> +++ b/git.c\n> @@ -56,6 +56,10 @@ static int list_cmds(const char *spec)\n>\n>                 if (match_token(spec, len, \"builtins\"))\n>                         list_builtins(&list, 0);\n> +               else if (match_token(spec, len, \"main\"))\n> +                       list_all_main_cmds(&list);\n> +               else if (match_token(spec, len, \"others\"))\n> +                       list_all_other_cmds(&list);\n>                 else\n>                         die(_(\"unsupported command listing type '%s'\"), spec);\n>                 spec += len;\n> diff --git a/help.c b/help.c\n> index 2d6a3157f8..d5ce9dfcbb 100644\n> --- a/help.c\n> +++ b/help.c\n> @@ -297,6 +297,38 @@ void list_common_cmds_help(void)\n>         print_cmd_by_category(common_categories);\n>  }\n>\n> +void list_all_main_cmds(struct string_list *list)\n> +{\n> +       struct cmdnames main_cmds, other_cmds;\n> +       int i;\n> +\n> +       memset(&main_cmds, 0, sizeof(main_cmds));\n> +       memset(&other_cmds, 0, sizeof(other_cmds));\n> +       load_command_list(\"git-\", &main_cmds, &other_cmds);\n> +\n> +       for (i = 0; i < main_cmds.cnt; i++)\n> +               string_list_append(list, main_cmds.names[i]->name);\n> +\n> +       clean_cmdnames(&main_cmds);\n> +       clean_cmdnames(&other_cmds);\n> +}\n> +\n> +void list_all_other_cmds(struct string_list *list)\n> +{\n> +       struct cmdnames main_cmds, other_cmds;\n> +       int i;\n> +\n> +       memset(&main_cmds, 0, sizeof(main_cmds));\n> +       memset(&other_cmds, 0, sizeof(other_cmds));\n> +       load_command_list(\"git-\", &main_cmds, &other_cmds);\n> +\n> +       for (i = 0; i < other_cmds.cnt; i++)\n> +               string_list_append(list, other_cmds.names[i]->name);\n> +\n> +       clean_cmdnames(&main_cmds);\n> +       clean_cmdnames(&other_cmds);\n> +}\n> +\n>  int is_in_cmdlist(struct cmdnames *c, const char *s)\n>  {\n>         int i;\n> diff --git a/help.h b/help.h\n> index b21d7c94e8..97e6c0965e 100644\n> --- a/help.h\n> +++ b/help.h\n> @@ -1,6 +1,8 @@\n>  #ifndef HELP_H\n>  #define HELP_H\n>\n> +struct string_list;\n> +\n>  struct cmdnames {\n>         int alloc;\n>         int cnt;\n> @@ -17,6 +19,8 @@ static inline void mput_char(char c, unsigned int num)\n>  }\n>\n>  extern void list_common_cmds_help(void);\n> +extern void list_all_main_cmds(struct string_list *list);\n> +extern void list_all_other_cmds(struct string_list *list);\n>  extern const char *help_unknown_cmd(const char *cmd);\n>  extern void load_command_list(const char *prefix,\n>                               struct cmdnames *main_cmds,\n> --\n> 2.17.0.705.g3525833791\n>\n"},{"id":"347358","messageId":"CAM0VKjnvLV-QPUGtGZUPc4A2nxL2SzWzg7SPWc76hOfQ--2sYQ@mail.gmail.com","threadId":"48155","inReplyTo":"CAM0VKjk3kqKpVz0ZjX58REwP8rz08kLsiVR4NWDO6-9iPGPe9g@mail.gmail.com","subject":"Re: [PATCH v7 07/13] completion: implement and use --list-cmds=main,others","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-05-11T14:32:24Z","receivedAt":"2018-05-11T14:32:28Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Fri, May 11, 2018 at 4:06 PM, SZEDER Gábor <szeder.dev@gmail.com> wrote:\n> OTOH you don't mention the most important reason, namely that the\n> completion script contains a long hard-coded list of the names of all\n> known plumbing commands to filter out, which is redundant with the\n> categorization in 'command-list.txt', is a maintenance burden, and\n> tends to get out-of-sync when new plumbing commands are added.\n\nOops, sorry, got lost among the many patches, please just forget this\nparagraph.\n"},{"id":"347361","messageId":"CAM0VKjmL=OfKcveHRW+eAzvwS2o8TjcOS-uRNzD1JuKY2DYfFw@mail.gmail.com","threadId":"48155","inReplyTo":"20180510084652.25880-13-pclouds@gmail.com","subject":"Re: [PATCH v7 12/13] completion: let git provide the completable command list","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-05-11T15:05:42Z","receivedAt":"2018-05-11T15:05:48Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Thu, May 10, 2018 at 10:46 AM, Nguyễn Thái Ngọc Duy\n<pclouds@gmail.com> wrote:\n> Instead of maintaining a separate list of command classification,\n> which often could go out of date, let's centralize the information\n> back in git.\n>\n> While the function in git-completion.bash implies \"list porcelain\n> commands\", that's not exactly what it does. It gets all commands (aka\n> --list-cmds=main,others) then exclude certain non-porcelain ones. We\n> could almost recreate this list two lists list-mainporcelain and\n> others. The non-porcelain-but-included-anyway is added by the third\n> category list-complete.\n>\n> list-complete does not recreate exactly the command list before this\n> patch though. The following commands are not part of neither\n> list-mainporcelain nor list-complete and as a result no longer\n> completes:\n>\n> - annotate             obsolete, discouraged to use\n> - difftool-helper      not an end user command\n> - filter-branch        not often used\n> - get-tar-commit-id    not often used\n> - imap-send            not often used\n> - interpreter-trailers not for interactive use\n> - lost-found           obsolete\n> - p4                   too short and probably not often used (*)\n> - peek-remote          deprecated\n> - svn                  same category as p4 (*)\n> - tar-tree             obsolete\n> - verify-commit        not often used\n\n'git name-rev' is plumbing as well.\n\nI think this commit should be split into two:\n\n  - first do the unequivocally beneficial thing and get rid of the\n    long, hard-coded command list in __git_list_porcelain_commands(),\n    while keeping its output unchanged,\n\n  - then do the arguable thing and change the list of commands.\n\n> Note that the current completion script incorrectly classifies\n> filter-branch as porcelain and t9902 tests this behavior. We keep it\n> this way in t9902 because this test does not really care which\n> particular command is porcelain or plubmbing, they're just names.\n>\n> (*) to be fair, send-email command which is in the same\n> foreignscminterface group as svn and p4 does get completion, just\n> because it's used by git and kernel development. So maybe should\n> include them.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  command-list.txt                       |  37 ++++----\n>  contrib/completion/git-completion.bash | 117 ++++++-------------------\n>  t/t9902-completion.sh                  |   5 +-\n>  3 files changed, 48 insertions(+), 111 deletions(-)\n\n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> index 4e724a5b76..908692ea52 100644\n> --- a/contrib/completion/git-completion.bash\n> +++ b/contrib/completion/git-completion.bash\n> @@ -835,18 +835,30 @@ __git_complete_strategy ()\n>  }\n>\n>  __git_commands () {\n> -       if test -n \"${GIT_TESTING_COMMAND_COMPLETION:-}\"\n> -       then\n> -               printf \"%s\" \"${GIT_TESTING_COMMAND_COMPLETION}\"\n> -       else\n> -               git --list-cmds=main,others\n> -       fi\n> +       case \"$1\" in\n> +       porcelain)\n> +               if test -n \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\"\n> +               then\n> +                       printf \"%s\" \"$GIT_TESTING_PORCELAIN_COMMAND_LIST\"\n> +               else\n> +                       git --list-cmds=list-mainporcelain,others,list-complete\n> +               fi\n> +               ;;\n> +       all)\n> +               if test -n \"$GIT_TESTING_ALL_COMMAND_LIST\"\n> +               then\n> +                       printf \"%s\" \"$GIT_TESTING_ALL_COMMAND_LIST\"\n> +               else\n> +                       git --list-cmds=main,others\n> +               fi\n> +               ;;\n> +       esac\n>  }\n>\n> -__git_list_all_commands ()\n> +__git_list_commands ()\n\nPlease add comments before these functions to document their mandatory\nargument.\n\n>  {\n>         local i IFS=\" \"$'\\n'\n> -       for i in $(__git_commands)\n> +       for i in $(__git_commands $1)\n>         do\n>                 case $i in\n>                 *--*)             : helper pattern;;\n\nIs this loop to exclude helper commands with doubledash in their name\nstill necessary?\n"},{"id":"347364","messageId":"CACsJy8Dxaizn7O1cVVXA9Gzywj7nQ5K0YMzgMkB3BQbV=W6Npg@mail.gmail.com","threadId":"48155","inReplyTo":"CAM0VKjk3kqKpVz0ZjX58REwP8rz08kLsiVR4NWDO6-9iPGPe9g@mail.gmail.com","subject":"Re: [PATCH v7 07/13] completion: implement and use --list-cmds=main,others","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-11T16:33:44Z","receivedAt":"2018-05-11T16:34:18Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, May 11, 2018 at 4:06 PM, SZEDER Gábor <szeder.dev@gmail.com> wrote:\n> On Thu, May 10, 2018 at 10:46 AM, Nguyễn Thái Ngọc Duy\n> <pclouds@gmail.com> wrote:\n>> Instead of parsing \"git help -a\" output, which is tricky to get right,\n>> less elegant and also slow,\n>\n> Is it tricky?  It seems rather straightforward.\n\nBut there are traps. [1] is a reported one. And since you're parsing\nwhat's meant for human reader, this code could easily break in the\nfuture.\n\n[1] https://public-inbox.org/git/CAPQz56bts8zFfUHyKJqnefQoH97L5TTA-k3be=5HsdeEbcMqOA@mail.gmail.com/\n\n> Is it slow?  Well, there is a pipe and an egrep, sure, but thanks to\n> caching it's only run once, so basically doesn't matter.\n\nThis I agree is an exaggeration. Ultimately though I am breaking down\nand providing the information pieces to\n__git_list_porcelain_commands() and it happens to benefit this one\ntoo. Perhaps I should rephrase my commit to say this.\n-- \nDuy\n"},{"id":"347465","messageId":"E92D8A89AD3E49229B84F08DDE883ED8@PhilipOakley","threadId":"48155","inReplyTo":"20180507175222.12114-12-pclouds@gmail.com","subject":"Re: [PATCH v6 11/13] command-list.txt: documentation and guide line","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2018-05-12T17:50:06Z","receivedAt":"2018-05-12T17:50:17Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"Hi Duy,\n\nFrom: \"Nguyễn Thái Ngọc Duy\" <pclouds@gmail.com> : Monday, May 07, 2018\n> This is intended to help anybody who needs to update command-list.txt.\n> It gives a brief introduction of all attributes a command can take.\n> ---\n> command-list.txt | 44 ++++++++++++++++++++++++++++++++++++++++++++\n> 1 file changed, 44 insertions(+)\n>\n> diff --git a/command-list.txt b/command-list.txt\n> index 99ddc231c1..9c70c69193 100644\n> --- a/command-list.txt\n> +++ b/command-list.txt\n> @@ -1,3 +1,47 @@\n> +# Command classification list\n> +# ---------------------------\n> +# All supported commands, builtin or external, must be described in\n> +# here. This info is used to list commands in various places. Each\n> +# command is on one line followed by one or more attributes.\n> +#\n> +# The first attribute group is mandatory and indicates the command\n> +# type. This group includes:\n> +#\n> +#   mainporcelain\n> +#   ancillarymanipulators\n> +#   ancillaryinterrogators\n> +#   foreignscminterface\n> +#   plumbingmanipulators\n> +#   plumbinginterrogators\n> +#   synchingrepositories\n> +#   synchelpers\n> +#   purehelpers\n> +#\n> +# The type names are self explanatory. But if you want to see what\n> +# command belongs to what group to get a better picture, have a look\n> +# at \"git\" man page, \"GIT COMMANDS\" section.\n> +#\n> +# Commands of type mainporcelain can also optionally have one of these\n> +# attributes:\n> +#\n> +#   init\n> +#   worktree\n> +#   info\n> +#   history\n> +#   remote\n> +#\n> +# These commands are considered \"common\" and will show up in \"git\n> +# help\" output in groups. Uncommon porcelain commands must not\n> +# specify any of these attributes.\n> +#\n> +# \"complete\" attribute is used to mark that the command should be\n> +# completable by git-completion.bash. Note that by default,\n> +# mainporcelain commands are completable so you don't need this\n> +# attribute.\n> +#\n> +# While not true commands, guides are also specified here, which can\n> +# only have \"guide\" attribute and nothing else.\n\nWhile the file is called ~ \"Command List\", the list is here as a support to\nthe Help function, and ultimately to the user's reading of the man pages,\nincluding the man(5/7) guides, so I'd view the man page guides as first\nclass citizens.\n\nPerhaps:\n# As part of the Git man page list, the man(5/7) guides are also specified\n# here, which can only have \"guide\" attribute and nothing else.\n\n--\nPhilip\n\n> +#\n> ### command list (do not change this line, also do not change alignment)\n> # command name                          category [category] [category]\n> git-add                                 mainporcelain           worktree\n> -- \n> 2.17.0.705.g3525833791\n>\n>\n\n"},{"id":"347529","messageId":"CACsJy8D+xes0+Lqyh+QEmTBuGm47nbbKQdcBRiCx-p5s7SoXnQ@mail.gmail.com","threadId":"48155","inReplyTo":"CAM0VKjmL=OfKcveHRW+eAzvwS2o8TjcOS-uRNzD1JuKY2DYfFw@mail.gmail.com","subject":"Re: [PATCH v7 12/13] completion: let git provide the completable command list","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-13T06:50:08Z","receivedAt":"2018-05-13T06:50:42Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, May 11, 2018 at 5:05 PM, SZEDER Gábor <szeder.dev@gmail.com> wrote:\n> On Thu, May 10, 2018 at 10:46 AM, Nguyễn Thái Ngọc Duy\n> <pclouds@gmail.com> wrote:\n>> Instead of maintaining a separate list of command classification,\n>> which often could go out of date, let's centralize the information\n>> back in git.\n>>\n>> While the function in git-completion.bash implies \"list porcelain\n>> commands\", that's not exactly what it does. It gets all commands (aka\n>> --list-cmds=main,others) then exclude certain non-porcelain ones. We\n>> could almost recreate this list two lists list-mainporcelain and\n>> others. The non-porcelain-but-included-anyway is added by the third\n>> category list-complete.\n>>\n>> list-complete does not recreate exactly the command list before this\n>> patch though. The following commands are not part of neither\n>> list-mainporcelain nor list-complete and as a result no longer\n>> completes:\n>>\n>> - annotate             obsolete, discouraged to use\n>> - difftool-helper      not an end user command\n>> - filter-branch        not often used\n>> - get-tar-commit-id    not often used\n>> - imap-send            not often used\n>> - interpreter-trailers not for interactive use\n>> - lost-found           obsolete\n>> - p4                   too short and probably not often used (*)\n>> - peek-remote          deprecated\n>> - svn                  same category as p4 (*)\n>> - tar-tree             obsolete\n>> - verify-commit        not often used\n>\n> 'git name-rev' is plumbing as well.\n\nSo? name-rev remains completable like before and is not mentioned in\nthe above list. Am I missing something?\n\n> I think this commit should be split into two:\n>\n>   - first do the unequivocally beneficial thing and get rid of the\n>     long, hard-coded command list in __git_list_porcelain_commands(),\n>     while keeping its output unchanged,\n>\n>   - then do the arguable thing and change the list of commands.\n\nI will. Though the first commit still changes the output slightly\nbecause there are three commands not in command-list.txt. To keep the\noutput unchanged, I would need to add them back in command-list.txt\nfirst (and find the right group for them) only to remove those lines\nlater (two of them deprecated, the other does not even have a man\npage). It's not worth the effort.\n\n>>  {\n>>         local i IFS=\" \"$'\\n'\n>> -       for i in $(__git_commands)\n>> +       for i in $(__git_commands $1)\n>>         do\n>>                 case $i in\n>>                 *--*)             : helper pattern;;\n>\n> Is this loop to exclude helper commands with doubledash in their name\n> still necessary?\n\nIt is needed for __git_list_all_commands() because that one still\nessentially grabs \"git help -a\", which includes command--helpers.\n-- \nDuy\n"}]}