{"thread":{"id":"14690","subject":"[PATCH 1/7] Make is_git_command() usable outside builtin-help","startedAt":"2008-07-26T11:54:43Z","lastAt":"2008-07-29T00:01:04Z","messageCount":46,"participants":["Miklos Vajna","Johannes Schindelin","Jonathan Nieder","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":7},"messages":[{"id":"85050","messageId":"cover.1217037178.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":null,"subject":"[PATCH 0/7] Allow custom merge strategies","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-26T11:54:43Z","receivedAt":"2008-07-26T11:54:43Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"Hi,\n\nThis series adds support for custom merge strategies.\n\nThe first 3 patches modify builtin-help to allow using it from other\nbuiltins. This is necessary because in the error message of 'git merge\n-s foobar' we show something like 'git help -a', but we list only merge\nstrategies. A command is considered a merge strategy if it has a\ngit-merge- prefix and is listed in the all_strategy array or it is\nsomewhere in PATH, but outside `git --exec-path`, so that git-merge-ours\nand other strategies are shown, git-merge-index and other\ngit-merge-named (but not strategy) commands are hidden.\n\nThe last two is about removing those problematic 'git-merge-index',\n'git-merge-tree' and other bogus commands from the output of 'git merge\n-s foobar'. I think the benefit of doing it that way is that we don't\nhave to maintain a list of commands which are named git-merge-foo but\nnot strategies _and_ the custom strategies can have a form of\ngit-merge-foo, without adding extra complexity (like forcing users to\nname them git-merge-custom-foo).\n\nNOTE: At the moment the custom strategies are named as git-merge-foo as\nwell, mainly because I think it's not that problematic to exclude the\nalready existing git-merge-fo non-strategy commands, but this can be\nchanged to git-merge-strategy-foo if we really want so.\n\nAlso, I'm aware that this is a feature and we are in rc freeze, I just\ndid not want to keep back this series till 1.6.0 is out.\n\nMiklos Vajna (7):\n  Make is_git_command() usable outside builtin-help\n  builtin-help: change the current directory back in\n    list_commands_in_dir()\n  builtin-help: make list_commands() a bit more generic\n  builtin-merge: allow using a custom strategy\n  Add a new test for using a custom merge strategy\n  builtin-help: make it possible to exclude some commands in\n    list_commands()\n  builtin-merge: avoid non-strategy git-merge commands in error message\n\n Makefile                |    1 +\n builtin-merge.c         |   30 +++++++++++++++++++++------\n help.c                  |   50 ++++++++++++++++++++++++----------------------\n help.h                  |   19 +++++++++++++++++\n t/t7606-merge-custom.sh |   45 ++++++++++++++++++++++++++++++++++++++++++\n 5 files changed, 114 insertions(+), 31 deletions(-)\n create mode 100644 help.h\n create mode 100755 t/t7606-merge-custom.sh\n"},{"id":"85043","messageId":"f311372167c02868ccf5aa4dc03c97b7f956d855.1217037178.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"cover.1217037178.git.vmiklos@frugalware.org","subject":"[PATCH 1/7] Make is_git_command() usable outside builtin-help","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-26T11:54:44Z","receivedAt":"2008-07-26T11:54:44Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"Other builtins may want to check if a given command is a valid git\ncommand or not as well. Additionally add a new parameter that specifies\na custom prefix, so that the \"git-\" prefix is no longer hardwired.\nUseful for example to limit the search for \"git-merge-*\".\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n Makefile |    1 +\n help.c   |   25 ++++++++++++++-----------\n help.h   |    6 ++++++\n 3 files changed, 21 insertions(+), 11 deletions(-)\n create mode 100644 help.h\n\ndiff --git a/Makefile b/Makefile\nindex b01cf1c..85e79f6 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -346,6 +346,7 @@ LIB_H += git-compat-util.h\n LIB_H += graph.h\n LIB_H += grep.h\n LIB_H += hash.h\n+LIB_H += help.h\n LIB_H += list-objects.h\n LIB_H += ll-merge.h\n LIB_H += log-tree.h\ndiff --git a/help.c b/help.c\nindex bfc84ae..fb93df0 100644\n--- a/help.c\n+++ b/help.c\n@@ -418,17 +418,20 @@ static int is_executable(const char *name)\n }\n \n static unsigned int list_commands_in_dir(struct cmdnames *cmds,\n-\t\t\t\t\t const char *path)\n+\t\t\t\t\t const char *path,\n+\t\t\t\t\t const char *prefix)\n {\n \tunsigned int longest = 0;\n-\tconst char *prefix = \"git-\";\n-\tint prefix_len = strlen(prefix);\n+\tint prefix_len;\n \tDIR *dir = opendir(path);\n \tstruct dirent *de;\n \n \tif (!dir || chdir(path))\n \t\treturn 0;\n \n+\tif (!prefix)\n+\t\tprefix = \"git-\";\n+       \tprefix_len = strlen(prefix);\n \twhile ((de = readdir(dir)) != NULL) {\n \t\tint entlen;\n \n@@ -452,7 +455,7 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,\n \treturn longest;\n }\n \n-static unsigned int load_command_list(void)\n+static unsigned int load_command_list(const char *prefix)\n {\n \tunsigned int longest = 0;\n \tunsigned int len;\n@@ -461,7 +464,7 @@ static unsigned int load_command_list(void)\n \tconst char *exec_path = git_exec_path();\n \n \tif (exec_path)\n-\t\tlongest = list_commands_in_dir(&main_cmds, exec_path);\n+\t\tlongest = list_commands_in_dir(&main_cmds, exec_path, prefix);\n \n \tif (!env_path) {\n \t\tfprintf(stderr, \"PATH not set\\n\");\n@@ -473,7 +476,7 @@ static unsigned int load_command_list(void)\n \t\tif ((colon = strchr(path, PATH_SEP)))\n \t\t\t*colon = 0;\n \n-\t\tlen = list_commands_in_dir(&other_cmds, path);\n+\t\tlen = list_commands_in_dir(&other_cmds, path, prefix);\n \t\tif (len > longest)\n \t\t\tlongest = len;\n \n@@ -497,7 +500,7 @@ static unsigned int load_command_list(void)\n \n static void list_commands(void)\n {\n-\tunsigned int longest = load_command_list();\n+\tunsigned int longest = load_command_list(NULL);\n \tconst char *exec_path = git_exec_path();\n \n \tif (main_cmds.cnt) {\n@@ -543,9 +546,9 @@ static int is_in_cmdlist(struct cmdnames *c, const char *s)\n \treturn 0;\n }\n \n-static int is_git_command(const char *s)\n+int is_git_command(const char *s, const char *prefix)\n {\n-\tload_command_list();\n+\tload_command_list(prefix);\n \treturn is_in_cmdlist(&main_cmds, s) ||\n \t\tis_in_cmdlist(&other_cmds, s);\n }\n@@ -566,7 +569,7 @@ static const char *cmd_to_page(const char *git_cmd)\n \t\treturn \"git\";\n \telse if (!prefixcmp(git_cmd, \"git\"))\n \t\treturn git_cmd;\n-\telse if (is_git_command(git_cmd))\n+\telse if (is_git_command(git_cmd, NULL))\n \t\treturn prepend(\"git-\", git_cmd);\n \telse\n \t\treturn prepend(\"git\", git_cmd);\n@@ -704,7 +707,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \t}\n \n \talias = alias_lookup(argv[0]);\n-\tif (alias && !is_git_command(argv[0])) {\n+\tif (alias && !is_git_command(argv[0], NULL)) {\n \t\tprintf(\"`git %s' is aliased to `%s'\\n\", argv[0], alias);\n \t\treturn 0;\n \t}\ndiff --git a/help.h b/help.h\nnew file mode 100644\nindex 0000000..73da8d6\n--- /dev/null\n+++ b/help.h\n@@ -0,0 +1,6 @@\n+#ifndef HELP_H\n+#define HELP_H\n+\n+int is_git_command(const char *s, const char *prefix);\n+\n+#endif /* HELP_H */\n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85048","messageId":"1217073292-27945-1-git-send-email-vmiklos@frugalware.org","threadId":"14690","inReplyTo":"f311372167c02868ccf5aa4dc03c97b7f956d855.1217037178.git.vmiklos@frugalware.org","subject":"[PATCH] t7601: extend the 'merge picks up the best result' test","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-26T11:54:45Z","receivedAt":"2008-07-26T11:54:45Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"The test only checked if the best result picking code works if there are\nmultiple strategies set in the config. Add a similar one that tests if\nthe same true if the -s option of git merge was used multiple times.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n\nOn Tue, Jul 22, 2008 at 01:24:14AM -0700, Junio C Hamano <gitster@pobox.com> wrote:\n> Don't.  pull.* has always been defined as \"list of strategies\", and -s\n> has\n> always been defined to take \"a\" strategy.\n\nOK. Here is a testcase for the later. As far as I see the behaviour of\nmultiple -s was not checked till now.\n\n t/t7601-merge-pull-config.sh |   15 +++++++++++++++\n 1 files changed, 15 insertions(+), 0 deletions(-)\n\ndiff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh\nindex 6b9f638..55aa6b5 100755\n--- a/t/t7601-merge-pull-config.sh\n+++ b/t/t7601-merge-pull-config.sh\n@@ -112,6 +112,21 @@ test_expect_success 'setup conflicted merge' '\n # recusive is choosen.\n \n test_expect_success 'merge picks up the best result' '\n+\tgit config --unset-all pull.twohead &&\n+\tgit reset --hard c5 &&\n+\tgit merge -s resolve c6\n+\tresolve_count=$(conflict_count) &&\n+\tgit reset --hard c5 &&\n+\tgit merge -s recursive c6\n+\trecursive_count=$(conflict_count) &&\n+\tgit reset --hard c5 &&\n+\tgit merge -s recursive -s resolve c6\n+\tauto_count=$(conflict_count) &&\n+\ttest $auto_count = $recursive_count &&\n+\ttest $auto_count != $resolve_count\n+'\n+\n+test_expect_success 'merge picks up the best result (from config)' '\n \tgit config pull.twohead \"recursive resolve\" &&\n \tgit reset --hard c5 &&\n \tgit merge -s resolve c6\n-- \n1.5.6.4.433.g09651.dirty\n"},{"id":"85051","messageId":"4f2b03391e3f85cf2224f97a2a7765d08707bd73.1217037178.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"1217073292-27945-1-git-send-email-vmiklos@frugalware.org","subject":"[PATCH 2/7] builtin-help: change the current directory back in list_commands_in_dir()","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-26T11:54:46Z","receivedAt":"2008-07-26T11:54:46Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"That function used to do a chdir() without switching back to the\noriginal directory. That was not a problem till this function was used\nonly inside builtin-help, but once other builtins use it as well, this\nis a problem, for example when the object database path is relative.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n help.c |    3 +++\n 1 files changed, 3 insertions(+), 0 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex fb93df0..d71937e 100644\n--- a/help.c\n+++ b/help.c\n@@ -425,7 +425,9 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,\n \tint prefix_len;\n \tDIR *dir = opendir(path);\n \tstruct dirent *de;\n+\tstatic char old_path[PATH_MAX+1];\n \n+\tgetcwd(old_path, sizeof(old_path));\n \tif (!dir || chdir(path))\n \t\treturn 0;\n \n@@ -452,6 +454,7 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,\n \t}\n \tclosedir(dir);\n \n+\tchdir(old_path);\n \treturn longest;\n }\n \n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85045","messageId":"68749731fe8de8b2a9ffc53963291aeab9256b82.1217037178.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"4f2b03391e3f85cf2224f97a2a7765d08707bd73.1217037178.git.vmiklos@frugalware.org","subject":"[PATCH 3/7] builtin-help: make list_commands() a bit more generic","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-26T11:54:47Z","receivedAt":"2008-07-26T11:54:47Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"That function now takes two paramters to control the prefix of the\nlisted commands, and a second parameter to specify the title of the\ntable. This can be useful for listing not only all git commands, but\nspecific ones, like merge strategies.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n help.c |   10 +++++-----\n help.h |    1 +\n 2 files changed, 6 insertions(+), 5 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex d71937e..f71fff4 100644\n--- a/help.c\n+++ b/help.c\n@@ -501,13 +501,13 @@ static unsigned int load_command_list(const char *prefix)\n \treturn longest;\n }\n \n-static void list_commands(void)\n+void list_commands(const char *prefix, const char *title)\n {\n-\tunsigned int longest = load_command_list(NULL);\n+\tunsigned int longest = load_command_list(prefix);\n \tconst char *exec_path = git_exec_path();\n \n \tif (main_cmds.cnt) {\n-\t\tprintf(\"available git commands in '%s'\\n\", exec_path);\n+\t\tprintf(\"available %s in '%s'\\n\", title, exec_path);\n \t\tprintf(\"----------------------------\");\n \t\tmput_char('-', strlen(exec_path));\n \t\tputchar('\\n');\n@@ -516,7 +516,7 @@ static void list_commands(void)\n \t}\n \n \tif (other_cmds.cnt) {\n-\t\tprintf(\"git commands available from elsewhere on your $PATH\\n\");\n+\t\tprintf(\"%s available from elsewhere on your $PATH\\n\", title);\n \t\tprintf(\"---------------------------------------------------\\n\");\n \t\tpretty_print_string_list(&other_cmds, longest);\n \t\tputchar('\\n');\n@@ -697,7 +697,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \tif (show_all) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n-\t\tlist_commands();\n+\t\tlist_commands(\"git-\", \"git commands\");\n \t\tprintf(\"%s\\n\", git_more_info_string);\n \t\treturn 0;\n \t}\ndiff --git a/help.h b/help.h\nindex 73da8d6..0741662 100644\n--- a/help.h\n+++ b/help.h\n@@ -2,5 +2,6 @@\n #define HELP_H\n \n int is_git_command(const char *s, const char *prefix);\n+void list_commands(const char *prefix, const char *title);\n \n #endif /* HELP_H */\n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85047","messageId":"99c90877657be0ed439a9918f500d6ad132550a2.1217037178.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"68749731fe8de8b2a9ffc53963291aeab9256b82.1217037178.git.vmiklos@frugalware.org","subject":"[PATCH 4/7] builtin-merge: allow using a custom strategy","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-26T11:54:48Z","receivedAt":"2008-07-26T11:54:48Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"Allow using a custom strategy, as long as it's named git-merge-foo. The\nerror handling is now done using is_git_command(). The list of available\nstrategies is now shown by list_commands().\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n builtin-merge.c |   19 ++++++++++++-------\n 1 files changed, 12 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin-merge.c b/builtin-merge.c\nindex e78fa18..cdbc692 100644\n--- a/builtin-merge.c\n+++ b/builtin-merge.c\n@@ -22,6 +22,7 @@\n #include \"log-tree.h\"\n #include \"color.h\"\n #include \"rerere.h\"\n+#include \"help.h\"\n \n #define DEFAULT_TWOHEAD (1<<0)\n #define DEFAULT_OCTOPUS (1<<1)\n@@ -77,7 +78,7 @@ static int option_parse_message(const struct option *opt,\n static struct strategy *get_strategy(const char *name)\n {\n \tint i;\n-\tstruct strbuf err;\n+\tstruct strategy *ret;\n \n \tif (!name)\n \t\treturn NULL;\n@@ -86,12 +87,16 @@ static struct strategy *get_strategy(const char *name)\n \t\tif (!strcmp(name, all_strategy[i].name))\n \t\t\treturn &all_strategy[i];\n \n-\tstrbuf_init(&err, 0);\n-\tfor (i = 0; i < ARRAY_SIZE(all_strategy); i++)\n-\t\tstrbuf_addf(&err, \" %s\", all_strategy[i].name);\n-\tfprintf(stderr, \"Could not find merge strategy '%s'.\\n\", name);\n-\tfprintf(stderr, \"Available strategies are:%s.\\n\", err.buf);\n-\texit(1);\n+\tif (!is_git_command(name, \"git-merge-\")) {\n+\t\tfprintf(stderr, \"Could not find merge strategy '%s'.\\n\\n\", name);\n+\t\tlist_commands(\"git-merge-\", \"strategies\");\n+\t\texit(1);\n+\t}\n+\n+\tret = xmalloc(sizeof(struct strategy));\n+\tmemset(ret, 0, sizeof(struct strategy));\n+\tret->name = xstrdup(name);\n+\treturn ret;\n }\n \n static void append_strategy(struct strategy *s)\n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85049","messageId":"13f39dd6752a34beeb6ecccb51dbc7546ef87182.1217037178.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"99c90877657be0ed439a9918f500d6ad132550a2.1217037178.git.vmiklos@frugalware.org","subject":"[PATCH 5/7] Add a new test for using a custom merge strategy","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-26T11:54:49Z","receivedAt":"2008-07-26T11:54:49Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"Testing is done by creating a simple git-merge-theirs strategy which is\nthe opposite of ours. Using this in real merges is not recommended but\nit's perfect for our testing needs.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n t/t7606-merge-custom.sh |   45 +++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 45 insertions(+), 0 deletions(-)\n create mode 100755 t/t7606-merge-custom.sh\n\ndiff --git a/t/t7606-merge-custom.sh b/t/t7606-merge-custom.sh\nnew file mode 100755\nindex 0000000..f295e56\n--- /dev/null\n+++ b/t/t7606-merge-custom.sh\n@@ -0,0 +1,45 @@\n+#!/bin/sh\n+\n+test_description='git-merge\n+\n+Testing a custom strategy.'\n+\n+. ./test-lib.sh\n+\n+cat > git-merge-theirs << EOF\n+#!/bin/sh\n+eval git read-tree --reset -u \\\\\\$\\$#\n+EOF\n+chmod +x git-merge-theirs\n+PATH=.:$PATH\n+export PATH\n+\n+test_expect_success 'setup' '\n+\techo c0 > c0.c &&\n+\tgit add c0.c &&\n+\tgit commit -m c0 &&\n+\tgit tag c0 &&\n+\techo c1 > c1.c &&\n+\tgit add c1.c &&\n+\tgit commit -m c1 &&\n+\tgit tag c1 &&\n+\tgit reset --hard c0 &&\n+\techo c2 > c2.c &&\n+\tgit add c2.c &&\n+\tgit commit -m c2 &&\n+\tgit tag c2\n+'\n+\n+test_expect_success 'merge c2 with a custom strategy' '\n+\tgit reset --hard c1 &&\n+\tgit merge -s theirs c2 &&\n+\ttest \"$(git rev-parse c1)\" != \"$(git rev-parse HEAD)\" &&\n+\ttest \"$(git rev-parse c1)\" = \"$(git rev-parse HEAD^1)\" &&\n+\ttest \"$(git rev-parse c2)\" = \"$(git rev-parse HEAD^2)\" &&\n+\tgit diff --exit-code &&\n+\ttest -f c0.c &&\n+\ttest ! -f c1.c &&\n+\ttest -f c2.c\n+'\n+\n+test_done\n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85044","messageId":"fc448aa651ad9e8e9d1cf5556a665b5bd6074628.1217037178.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"13f39dd6752a34beeb6ecccb51dbc7546ef87182.1217037178.git.vmiklos@frugalware.org","subject":"[PATCH 6/7] builtin-help: make it possible to exclude some commands in list_commands()","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-26T11:54:50Z","receivedAt":"2008-07-26T11:54:50Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"The supposed method is to build a list of commands to be excluded using\nadd_cmdname(), then pass the list as the new exclude parameter. If no\nexclude is needed, NULL should be used.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n help.c |   24 ++++++++++--------------\n help.h |   14 +++++++++++++-\n 2 files changed, 23 insertions(+), 15 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex f71fff4..de1be6d 100644\n--- a/help.c\n+++ b/help.c\n@@ -9,6 +9,7 @@\n #include \"common-cmds.h\"\n #include \"parse-options.h\"\n #include \"run-command.h\"\n+#include \"help.h\"\n \n static struct man_viewer_list {\n \tstruct man_viewer_list *next;\n@@ -300,16 +301,9 @@ static inline void mput_char(char c, unsigned int num)\n \t\tputchar(c);\n }\n \n-static struct cmdnames {\n-\tint alloc;\n-\tint cnt;\n-\tstruct cmdname {\n-\t\tsize_t len;\n-\t\tchar name[1];\n-\t} **names;\n-} main_cmds, other_cmds;\n+struct cmdnames main_cmds, other_cmds;\n \n-static void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n+void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n {\n \tstruct cmdname *ent = xmalloc(sizeof(*ent) + len);\n \n@@ -458,7 +452,7 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,\n \treturn longest;\n }\n \n-static unsigned int load_command_list(const char *prefix)\n+static unsigned int load_command_list(const char *prefix, struct cmdnames *exclude)\n {\n \tunsigned int longest = 0;\n \tunsigned int len;\n@@ -497,13 +491,15 @@ static unsigned int load_command_list(const char *prefix)\n \t      sizeof(*other_cmds.names), cmdname_compare);\n \tuniq(&other_cmds);\n \texclude_cmds(&other_cmds, &main_cmds);\n+\tif (exclude)\n+\t\texclude_cmds(&main_cmds, exclude);\n \n \treturn longest;\n }\n \n-void list_commands(const char *prefix, const char *title)\n+void list_commands(const char *prefix, const char *title, struct cmdnames *exclude)\n {\n-\tunsigned int longest = load_command_list(prefix);\n+\tunsigned int longest = load_command_list(prefix, exclude);\n \tconst char *exec_path = git_exec_path();\n \n \tif (main_cmds.cnt) {\n@@ -551,7 +547,7 @@ static int is_in_cmdlist(struct cmdnames *c, const char *s)\n \n int is_git_command(const char *s, const char *prefix)\n {\n-\tload_command_list(prefix);\n+\tload_command_list(prefix, NULL);\n \treturn is_in_cmdlist(&main_cmds, s) ||\n \t\tis_in_cmdlist(&other_cmds, s);\n }\n@@ -697,7 +693,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \tif (show_all) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n-\t\tlist_commands(\"git-\", \"git commands\");\n+\t\tlist_commands(\"git-\", \"git commands\", NULL);\n \t\tprintf(\"%s\\n\", git_more_info_string);\n \t\treturn 0;\n \t}\ndiff --git a/help.h b/help.h\nindex 0741662..85d3b74 100644\n--- a/help.h\n+++ b/help.h\n@@ -1,7 +1,19 @@\n #ifndef HELP_H\n #define HELP_H\n \n+struct cmdnames {\n+\tint alloc;\n+\tint cnt;\n+\tstruct cmdname {\n+\t\tsize_t len;\n+\t\tchar name[1];\n+\t} **names;\n+};\n+\n int is_git_command(const char *s, const char *prefix);\n-void list_commands(const char *prefix, const char *title);\n+void list_commands(const char *prefix, const char *title, struct cmdnames *exclude);\n+void add_cmdname(struct cmdnames *cmds, const char *name, int len);\n+\n+extern struct cmdnames main_cmds, other_cmds;\n \n #endif /* HELP_H */\n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85046","messageId":"65a569c389352c5d0500b8c44c28e5572352e6ba.1217037178.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"fc448aa651ad9e8e9d1cf5556a665b5bd6074628.1217037178.git.vmiklos@frugalware.org","subject":"[PATCH 7/7] builtin-merge: avoid non-strategy git-merge commands in error message","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-26T11:54:51Z","receivedAt":"2008-07-26T11:54:51Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"If an invalid strategy is supplied, like -s foobar, then git-merge\nlisted all git-merge-* commands. This is not perfect, since for example\ngit-merge-index is not a valid strategy.\n\nThese are now removed from the output by scanning the list of main\ncommands; if the git-merge-foo command is listed in the all_strategy\nlist, then it's shown, otherwise excluded. This does not exclude\ncommands somewhere else in the PATH, where custom strategies are\nexpected.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n builtin-merge.c |   13 ++++++++++++-\n 1 files changed, 12 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin-merge.c b/builtin-merge.c\nindex cdbc692..4084e07 100644\n--- a/builtin-merge.c\n+++ b/builtin-merge.c\n@@ -88,8 +88,19 @@ static struct strategy *get_strategy(const char *name)\n \t\t\treturn &all_strategy[i];\n \n \tif (!is_git_command(name, \"git-merge-\")) {\n+\t\tstruct cmdnames not_strategies;\n+\n+\t\tmemset(&not_strategies, 0, sizeof(struct cmdnames));\n+\t\tfor (i = 0; i < main_cmds.cnt; i++) {\n+\t\t\tint j, found = 0;\n+\t\t\tfor (j = 0; j < ARRAY_SIZE(all_strategy); j++)\n+\t\t\t\tif (!strcmp(main_cmds.names[i]->name, all_strategy[j].name))\n+\t\t\t\t\tfound = 1;\n+\t\t\tif (!found)\n+\t\t\t\tadd_cmdname(&not_strategies, main_cmds.names[i]->name, strlen(main_cmds.names[i]->name));\n+\t\t}\n \t\tfprintf(stderr, \"Could not find merge strategy '%s'.\\n\\n\", name);\n-\t\tlist_commands(\"git-merge-\", \"strategies\");\n+\t\tlist_commands(\"git-merge-\", \"strategies\", &not_strategies);\n \t\texit(1);\n \t}\n \n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85053","messageId":"20080726123345.GH32057@genesis.frugalware.org","threadId":"14690","inReplyTo":"1217073292-27945-1-git-send-email-vmiklos@frugalware.org","subject":"Re: [PATCH] t7601: extend the 'merge picks up the best result' test","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-26T12:33:45Z","receivedAt":"2008-07-26T12:33:45Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Sat, Jul 26, 2008 at 01:54:45PM +0200, Miklos Vajna <vmiklos@frugalware.org> wrote:\n> The test only checked if the best result picking code works if there are\n> multiple strategies set in the config. Add a similar one that tests if\n> the same true if the -s option of git merge was used multiple times.\n\nIgnore this one. I run git send-email *.patch when sending out the other\nseries and forgot to do an rm *.patch before format-patch.\n\nSorry,\nMiklos\n"},{"id":"85066","messageId":"alpine.DEB.1.00.0807261657150.26810@eeepc-johanness","threadId":"14690","inReplyTo":"4f2b03391e3f85cf2224f97a2a7765d08707bd73.1217037178.git.vmiklos@frugalware.org","subject":"Re: [PATCH 2/7] builtin-help: change the current directory back in list_commands_in_dir()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-26T14:58:02Z","receivedAt":"2008-07-26T14:58:02Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sat, 26 Jul 2008, Miklos Vajna wrote:\n\n> That function used to do a chdir() without switching back to the \n> original directory. That was not a problem till this function was used \n> only inside builtin-help, but once other builtins use it as well, this \n> is a problem, for example when the object database path is relative.\n\nI had to work around that in my patch \"git wrapper: DWIM mistyped \ncommands\", too :-)\n\nCiao,\nDscho\n"},{"id":"85067","messageId":"alpine.DEB.1.00.0807261701520.26810@eeepc-johanness","threadId":"14690","inReplyTo":"65a569c389352c5d0500b8c44c28e5572352e6ba.1217037178.git.vmiklos@frugalware.org","subject":"Re: [PATCH 7/7] builtin-merge: avoid non-strategy git-merge commands in error message","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-26T15:08:11Z","receivedAt":"2008-07-26T15:08:11Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sat, 26 Jul 2008, Miklos Vajna wrote:\n\n> +\t\tmemset(&not_strategies, 0, sizeof(struct cmdnames));\n> +\t\tfor (i = 0; i < main_cmds.cnt; i++) {\n\nLooking through all the discovered git commands?  Cute...  But does that \nnot exclude the commands that are in PATH, starting with git-merge-, even \nif they are custom strategies?\n\n> +\t\t\tint j, found = 0;\n> +\t\t\tfor (j = 0; j < ARRAY_SIZE(all_strategy); j++)\n> +\t\t\t\tif (!strcmp(main_cmds.names[i]->name, all_strategy[j].name))\n> +\t\t\t\t\tfound = 1;\n> +\t\t\tif (!found)\n> +\t\t\t\tadd_cmdname(&not_strategies, main_cmds.names[i]->name, strlen(main_cmds.names[i]->name));\n\nBetter have a local variable \"name\" instead of writing out \n\"main_cmds.names[i]->name\" all the time...\n\nOh, and you assume that the names are NUL-terminated (which I assume is \nnot the case in general, as the len member is the only thing that makes \nstruct cmdnames different from struct string_list.\n\nCiao,\nDscho\n"},{"id":"85073","messageId":"20080726152502.GL32057@genesis.frugalware.org","threadId":"14690","inReplyTo":"alpine.DEB.1.00.0807261701520.26810@eeepc-johanness","subject":"Re: [PATCH 7/7] builtin-merge: avoid non-strategy git-merge commands in error message","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-26T15:25:02Z","receivedAt":"2008-07-26T15:25:02Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Sat, Jul 26, 2008 at 05:08:11PM +0200, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> > +\t\tmemset(&not_strategies, 0, sizeof(struct cmdnames));\n> > +\t\tfor (i = 0; i < main_cmds.cnt; i++) {\n> \n> Looking through all the discovered git commands?  Cute...  But does that \n> not exclude the commands that are in PATH, starting with git-merge-, even \n> if they are custom strategies?\n\nmain_cmds contains only commands in /usr/libexec/git-core, while I guess\ncustom strategies are elsewhere in PATH, which commands are in\nother_cmds, not in main_cmds.\n\nSample output at me:\n\n$ git merge -s theirss c2\nHEAD is now at 1f5e3cc c1\nCould not find merge strategy 'theirss'.\n\navailable strategies in '/usr/libexec/git-core/'\n--------------------------------------------------\n  octopus     ours        recursive   resolve     subtree\n\nstrategies available from elsewhere on your $PATH\n---------------------------------------------------\n  theirs\n\nand I have git-merge-theirs in ~/bin (which is in PATH).\n\n> \n> > +\t\t\tint j, found = 0;\n> > +\t\t\tfor (j = 0; j < ARRAY_SIZE(all_strategy); j++)\n> > +\t\t\t\tif (!strcmp(main_cmds.names[i]->name, all_strategy[j].name))\n> > +\t\t\t\t\tfound = 1;\n> > +\t\t\tif (!found)\n> > +\t\t\t\tadd_cmdname(&not_strategies, main_cmds.names[i]->name, strlen(main_cmds.names[i]->name));\n> \n> Better have a local variable \"name\" instead of writing out \n> \"main_cmds.names[i]->name\" all the time...\n\nFixed.\n\n> Oh, and you assume that the names are NUL-terminated (which I assume is \n> not the case in general, as the len member is the only thing that makes \n> struct cmdnames different from struct string_list.\n\nI think the purpose of it is different, but the argument is still valie.\nThat len member is to be able to have ->name contain \"foo.exe\" while\nhaving len at 3, so that git help -a will avoid the .exe suffixes.\n\nChanged.\n\n(I do not want to resend a full series yet, but I pushed out an amended\npatch to repo.or.cz in the 'merge-custom' branch.)\n\ndiff --git a/builtin-merge.c b/builtin-merge.c\nindex 4084e07..b0d1de5 100644\n--- a/builtin-merge.c\n+++ b/builtin-merge.c\n@@ -93,11 +93,12 @@ static struct strategy *get_strategy(const char *name)\n \t\tmemset(&not_strategies, 0, sizeof(struct cmdnames));\n \t\tfor (i = 0; i < main_cmds.cnt; i++) {\n \t\t\tint j, found = 0;\n+\t\t\tchar *ent = main_cmds.names[i];\n \t\t\tfor (j = 0; j < ARRAY_SIZE(all_strategy); j++)\n-\t\t\t\tif (!strcmp(main_cmds.names[i]->name, all_strategy[j].name))\n+\t\t\t\tif (!strncmp(ent->name, all_strategy[j].name, ent->len))\n \t\t\t\t\tfound = 1;\n \t\t\tif (!found)\n-\t\t\t\tadd_cmdname(&not_strategies, main_cmds.names[i]->name, strlen(main_cmds.names[i]->name));\n+\t\t\t\tadd_cmdname(&not_strategies, ent->name, ent->len);\n \t\t}\n \t\tfprintf(stderr, \"Could not find merge strategy '%s'.\\n\\n\", name);\n \t\tlist_commands(\"git-merge-\", \"strategies\", &not_strategies);\n"},{"id":"85074","messageId":"1217086044-28713-1-git-send-email-vmiklos@frugalware.org","threadId":"14690","inReplyTo":"20080726152502.GL32057@genesis.frugalware.org","subject":"[PATCH 7/7] builtin-merge: avoid non-strategy git-merge commands in error message","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-26T15:27:24Z","receivedAt":"2008-07-26T15:27:24Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"If an invalid strategy is supplied, like -s foobar, then git-merge\nlisted all git-merge-* commands. This is not perfect, since for example\ngit-merge-index is not a valid strategy.\n\nThese are now removed from the output by scanning the list of main\ncommands; if the git-merge-foo command is listed in the all_strategy\nlist, then it's shown, otherwise excluded. This does not exclude\ncommands somewhere else in the PATH, where custom strategies are\nexpected.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n\nI just realized I can resend the last patch as the others are unchanged,\nso here it is.\n\n builtin-merge.c |   14 +++++++++++++-\n 1 files changed, 13 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin-merge.c b/builtin-merge.c\nindex cdbc692..b0d1de5 100644\n--- a/builtin-merge.c\n+++ b/builtin-merge.c\n@@ -88,8 +88,20 @@ static struct strategy *get_strategy(const char *name)\n \t\t\treturn &all_strategy[i];\n \n \tif (!is_git_command(name, \"git-merge-\")) {\n+\t\tstruct cmdnames not_strategies;\n+\n+\t\tmemset(&not_strategies, 0, sizeof(struct cmdnames));\n+\t\tfor (i = 0; i < main_cmds.cnt; i++) {\n+\t\t\tint j, found = 0;\n+\t\t\tchar *ent = main_cmds.names[i];\n+\t\t\tfor (j = 0; j < ARRAY_SIZE(all_strategy); j++)\n+\t\t\t\tif (!strncmp(ent->name, all_strategy[j].name, ent->len))\n+\t\t\t\t\tfound = 1;\n+\t\t\tif (!found)\n+\t\t\t\tadd_cmdname(&not_strategies, ent->name, ent->len);\n+\t\t}\n \t\tfprintf(stderr, \"Could not find merge strategy '%s'.\\n\\n\", name);\n-\t\tlist_commands(\"git-merge-\", \"strategies\");\n+\t\tlist_commands(\"git-merge-\", \"strategies\", &not_strategies);\n \t\texit(1);\n \t}\n \n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85078","messageId":"alpine.DEB.1.00.0807261737260.26810@eeepc-johanness","threadId":"14690","inReplyTo":"20080726152502.GL32057@genesis.frugalware.org","subject":"Re: [PATCH 7/7] builtin-merge: avoid non-strategy git-merge commands in error message","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-26T15:38:55Z","receivedAt":"2008-07-26T15:38:55Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sat, 26 Jul 2008, Miklos Vajna wrote:\n\n> On Sat, Jul 26, 2008 at 05:08:11PM +0200, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> > > +\t\tmemset(&not_strategies, 0, sizeof(struct cmdnames));\n> > > +\t\tfor (i = 0; i < main_cmds.cnt; i++) {\n> > \n> > Looking through all the discovered git commands?  Cute...  But does \n> > that not exclude the commands that are in PATH, starting with \n> > git-merge-, even if they are custom strategies?\n> \n> main_cmds contains only commands in /usr/libexec/git-core, while I guess \n> custom strategies are elsewhere in PATH, which commands are in \n> other_cmds, not in main_cmds.\n\nThanks.\n\n> -\t\t\t\tif (!strcmp(main_cmds.names[i]->name, all_strategy[j].name))\n> +\t\t\t\tif (!strncmp(ent->name, all_strategy[j].name, ent->len))\n\nOops... that is not what I meant.  You'd have to check if \n!all_strategy[j].name[ent->len], too...\n\nCiao,\nDscho\n"},{"id":"85084","messageId":"20080726160022.GM32057@genesis.frugalware.org","threadId":"14690","inReplyTo":"alpine.DEB.1.00.0807261737260.26810@eeepc-johanness","subject":"Re: [PATCH 7/7] builtin-merge: avoid non-strategy git-merge commands in error message","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-26T16:00:22Z","receivedAt":"2008-07-26T16:00:22Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Sat, Jul 26, 2008 at 05:38:55PM +0200, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> > -\t\t\t\tif (!strcmp(main_cmds.names[i]->name, all_strategy[j].name))\n> > +\t\t\t\tif (!strncmp(ent->name, all_strategy[j].name, ent->len))\n> \n> Oops... that is not what I meant.  You'd have to check if \n> !all_strategy[j].name[ent->len], too...\n\nHmm. So let's say ent->name is \"ours.exe\", ent->len is set to 4.\n\nThen !strncmp(ent->name, all_strategy[j].name, ent->len) will be true,\nand the command will not be added to the exclude list.\n\nHowever, if I check for !all_strategy[j].name[ent->len], that will be\nfalse, so 'ours' will be excluded from the available strategy list.\n\nHave I missed something?\n\nThanks.\n"},{"id":"85093","messageId":"alpine.DEB.1.00.0807261900180.26810@eeepc-johanness","threadId":"14690","inReplyTo":"20080726160022.GM32057@genesis.frugalware.org","subject":"Re: [PATCH 7/7] builtin-merge: avoid non-strategy git-merge commands in error message","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-26T17:01:16Z","receivedAt":"2008-07-26T17:01:16Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sat, 26 Jul 2008, Miklos Vajna wrote:\n\n> On Sat, Jul 26, 2008 at 05:38:55PM +0200, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> > > -\t\t\t\tif (!strcmp(main_cmds.names[i]->name, all_strategy[j].name))\n> > > +\t\t\t\tif (!strncmp(ent->name, all_strategy[j].name, ent->len))\n> > \n> > Oops... that is not what I meant.  You'd have to check if \n> > !all_strategy[j].name[ent->len], too...\n> \n> Hmm. So let's say ent->name is \"ours.exe\", ent->len is set to 4.\n> \n> Then !strncmp(ent->name, all_strategy[j].name, ent->len) will be true,\n> and the command will not be added to the exclude list.\n\nWhat I meant is: if you change the strcmp to strncmp because one of the \nboth strings is not supposed to be NUL terminated, you still want to make \nsure that one is not a strict prefix of the other.\n\nCiao,\nDscho\n"},{"id":"85096","messageId":"1217092367-29114-1-git-send-email-vmiklos@frugalware.org","threadId":"14690","inReplyTo":"alpine.DEB.1.00.0807261900180.26810@eeepc-johanness","subject":"[PATCH] builtin-merge: avoid non-strategy git-merge commands in error message","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-26T17:12:47Z","receivedAt":"2008-07-26T17:12:47Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"If an invalid strategy is supplied, like -s foobar, then git-merge\nlisted all git-merge-* commands. This is not perfect, since for example\ngit-merge-index is not a valid strategy.\n\nThese are now removed from the output by scanning the list of main\ncommands; if the git-merge-foo command is listed in the all_strategy\nlist, then it's shown, otherwise excluded. This does not exclude\ncommands somewhere else in the PATH, where custom strategies are\nexpected.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n\nOn Sat, Jul 26, 2008 at 07:01:16PM +0200, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> > Hmm. So let's say ent->name is \"ours.exe\", ent->len is set to 4.\n> >\n> > Then !strncmp(ent->name, all_strategy[j].name, ent->len) will be\n> > true,\n> > and the command will not be added to the exclude list.\n>\n> What I meant is: if you change the strcmp to strncmp because one of\n> the\n> both strings is not supposed to be NUL terminated, you still want to\n> make\n> sure that one is not a strict prefix of the other.\n\nAah, I forgot about all_strategy[j].name is NUL terminated.\n\nUpdated patch below.\n\n builtin-merge.c |   15 ++++++++++++++-\n 1 files changed, 14 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin-merge.c b/builtin-merge.c\nindex cdbc692..29826b1 100644\n--- a/builtin-merge.c\n+++ b/builtin-merge.c\n@@ -88,8 +88,21 @@ static struct strategy *get_strategy(const char *name)\n \t\t\treturn &all_strategy[i];\n \n \tif (!is_git_command(name, \"git-merge-\")) {\n+\t\tstruct cmdnames not_strategies;\n+\n+\t\tmemset(&not_strategies, 0, sizeof(struct cmdnames));\n+\t\tfor (i = 0; i < main_cmds.cnt; i++) {\n+\t\t\tint j, found = 0;\n+\t\t\tstruct cmdname *ent = main_cmds.names[i];\n+\t\t\tfor (j = 0; j < ARRAY_SIZE(all_strategy); j++)\n+\t\t\t\tif (!strncmp(ent->name, all_strategy[j].name, ent->len)\n+\t\t\t\t\t\t&& !all_strategy[j].name[ent->len])\n+\t\t\t\t\tfound = 1;\n+\t\t\tif (!found)\n+\t\t\t\tadd_cmdname(&not_strategies, ent->name, ent->len);\n+\t\t}\n \t\tfprintf(stderr, \"Could not find merge strategy '%s'.\\n\\n\", name);\n-\t\tlist_commands(\"git-merge-\", \"strategies\");\n+\t\tlist_commands(\"git-merge-\", \"strategies\", &not_strategies);\n \t\texit(1);\n \t}\n \n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85100","messageId":"Pine.GSO.4.62.0807261301300.15728@harper.uchicago.edu","threadId":"14690","inReplyTo":"f311372167c02868ccf5aa4dc03c97b7f956d855.1217037178.git.vmiklos@frugalware.org","subject":"Re: [PATCH 1/7] Make is_git_command() usable outside builtin-help","fromName":"Jonathan Nieder","fromEmail":"jrnieder@uchicago.edu","sentAt":"2008-07-26T18:12:36Z","receivedAt":"2008-07-26T18:12:36Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"On Sat, 26 Jul 2008, Miklos Vajna wrote:\n\n> +\tif (!prefix)\n> +\t\tprefix = \"git-\";\n> +       \tprefix_len = strlen(prefix);\n\nThe whitespace gave me a start: the diff markup moved the prefix_len\nline to the next tab stop, so at first glance it seems there are missing\nbraces here.  But it is an illusion.  (I mention this so others might\navoid wasting time worrying about it.)\n\nI like the patch so far.  Thanks for the pleasant reading.\n"},{"id":"85102","messageId":"Pine.GSO.4.62.0807261319310.16184@harper.uchicago.edu","threadId":"14690","inReplyTo":"68749731fe8de8b2a9ffc53963291aeab9256b82.1217037178.git.vmiklos@frugalware.org","subject":"Re: [PATCH 3/7] builtin-help: make list_commands() a bit more generic","fromName":"Jonathan Nieder","fromEmail":"jrnieder@uchicago.edu","sentAt":"2008-07-26T18:28:39Z","receivedAt":"2008-07-26T18:28:39Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"On Sat, 26 Jul 2008, Miklos Vajna wrote:\n\n> -static void list_commands(void)\n> +void list_commands(const char *prefix, const char *title)\n>  {\n> -\tunsigned int longest = load_command_list(NULL);\n> +\tunsigned int longest = load_command_list(prefix);\n>  \tconst char *exec_path = git_exec_path();\n>  \n>  \tif (main_cmds.cnt) {\n> -\t\tprintf(\"available git commands in '%s'\\n\", exec_path);\n> +\t\tprintf(\"available %s in '%s'\\n\", title, exec_path);\n>  \t\tprintf(\"----------------------------\");\n>  \t\tmput_char('-', strlen(exec_path));\n>  \t\tputchar('\\n');\n\nShould this be\n\n\tprintf(\"available %s in '%s'\\n\", title, exec_path);\n\tprintf(\"----------------\");\n\tmput_char('-', strlen(exec_path) + strlen(title));\n\tputchar('\\n');\n\n?\n\n(same question goes for the if(other_cmds.cnt) block, too)\n"},{"id":"85119","messageId":"3db8fbf82ab865b9dab5899f9a7e867ef005ecb6.1217108282.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"Pine.GSO.4.62.0807261319310.16184@harper.uchicago.edu","subject":"[PATCH 3/7] builtin-help: make list_commands() a bit more generic","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-26T21:40:25Z","receivedAt":"2008-07-26T21:40:25Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"That function now takes two paramters to control the prefix of the\nlisted commands, and a second parameter to specify the title of the\ntable. This can be useful for listing not only all git commands, but\nspecific ones, like merge strategies.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n\nOn Sat, Jul 26, 2008 at 01:28:39PM -0500, Jonathan Nieder <jrnieder@uchicago.edu> wrote:\n> >     if (main_cmds.cnt) {\n> > -           printf(\"available git commands in '%s'\\n\", exec_path);\n> > +           printf(\"available %s in '%s'\\n\", title, exec_path);\n> >             printf(\"----------------------------\");\n> >             mput_char('-', strlen(exec_path));\n> >             putchar('\\n');\n>\n> Should this be\n>\n>       printf(\"available %s in '%s'\\n\", title, exec_path);\n>       printf(\"----------------\");\n>       mput_char('-', strlen(exec_path) + strlen(title));\n>       putchar('\\n');\n>\n> ?\n>\n> (same question goes for the if(other_cmds.cnt) block, too)\n\nRight. Here is an updated patch.\n\nAlso available at git://repo.or.cz/git/vmiklos.git, branch 'merge-custom'.\n\n help.c |   18 ++++++++++--------\n help.h |    1 +\n 2 files changed, 11 insertions(+), 8 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex d71937e..ec7999d 100644\n--- a/help.c\n+++ b/help.c\n@@ -501,23 +501,25 @@ static unsigned int load_command_list(const char *prefix)\n \treturn longest;\n }\n \n-static void list_commands(void)\n+void list_commands(const char *prefix, const char *title)\n {\n-\tunsigned int longest = load_command_list(NULL);\n+\tunsigned int longest = load_command_list(prefix);\n \tconst char *exec_path = git_exec_path();\n \n \tif (main_cmds.cnt) {\n-\t\tprintf(\"available git commands in '%s'\\n\", exec_path);\n-\t\tprintf(\"----------------------------\");\n-\t\tmput_char('-', strlen(exec_path));\n+\t\tprintf(\"available %s in '%s'\\n\", title, exec_path);\n+\t\tprintf(\"----------------\");\n+\t\tmput_char('-', strlen(title) + strlen(exec_path));\n \t\tputchar('\\n');\n \t\tpretty_print_string_list(&main_cmds, longest);\n \t\tputchar('\\n');\n \t}\n \n \tif (other_cmds.cnt) {\n-\t\tprintf(\"git commands available from elsewhere on your $PATH\\n\");\n-\t\tprintf(\"---------------------------------------------------\\n\");\n+\t\tprintf(\"%s available from elsewhere on your $PATH\\n\", title);\n+\t\tprintf(\"---------------------------------------\");\n+\t\tmput_char('-', strlen(title));\n+\t\tputchar('\\n');\n \t\tpretty_print_string_list(&other_cmds, longest);\n \t\tputchar('\\n');\n \t}\n@@ -697,7 +699,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \tif (show_all) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n-\t\tlist_commands();\n+\t\tlist_commands(\"git-\", \"git commands\");\n \t\tprintf(\"%s\\n\", git_more_info_string);\n \t\treturn 0;\n \t}\ndiff --git a/help.h b/help.h\nindex 73da8d6..0741662 100644\n--- a/help.h\n+++ b/help.h\n@@ -2,5 +2,6 @@\n #define HELP_H\n \n int is_git_command(const char *s, const char *prefix);\n+void list_commands(const char *prefix, const char *title);\n \n #endif /* HELP_H */\n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85196","messageId":"7vwsj7yu1q.fsf@gitster.siamese.dyndns.org","threadId":"14690","inReplyTo":"4f2b03391e3f85cf2224f97a2a7765d08707bd73.1217037178.git.vmiklos@frugalware.org","subject":"Re: [PATCH 2/7] builtin-help: change the current directory back in list_commands_in_dir()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-07-27T20:02:41Z","receivedAt":"2008-07-27T20:02:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Miklos Vajna <vmiklos@frugalware.org> writes:\n\n> That function used to do a chdir() without switching back to the\n> original directory. That was not a problem till this function was used\n> only inside builtin-help, but once other builtins use it as well, this\n> is a problem, for example when the object database path is relative.\n\nWhy does it even need to chdir() around to begin with?  Doesn't opendir()\nwork just fine with relative path as an input?\n"},{"id":"85199","messageId":"alpine.DEB.1.00.0807272219350.5526@eeepc-johanness","threadId":"14690","inReplyTo":"7vwsj7yu1q.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 2/7] builtin-help: change the current directory back in list_commands_in_dir()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-27T20:21:04Z","receivedAt":"2008-07-27T20:21:04Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 27 Jul 2008, Junio C Hamano wrote:\n\n> Miklos Vajna <vmiklos@frugalware.org> writes:\n> \n> > That function used to do a chdir() without switching back to the \n> > original directory. That was not a problem till this function was used \n> > only inside builtin-help, but once other builtins use it as well, this \n> > is a problem, for example when the object database path is relative.\n> \n> Why does it even need to chdir() around to begin with?  Doesn't \n> opendir() work just fine with relative path as an input?\n\nIt is a consequence of list_commands_in_dir() trying to be cute, and not \nhaving to construct the full path for the is_executable() check.\n\nWill post a fix in a few minutes.\n\nCiao,\nDscho\n"},{"id":"85200","messageId":"alpine.DEB.1.00.0807272233160.5526@eeepc-johanness","threadId":"14690","inReplyTo":"alpine.DEB.1.00.0807272219350.5526@eeepc-johanness","subject":"[PATCH] Avoid chdir() in list_commands_in_dir()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-27T20:34:14Z","receivedAt":"2008-07-27T20:34:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThe function list_commands_in_dir() tried to be lazy and just chdir()\nto the directory which entries it listed, so that the check if the\nfile is executable could be done on dir->d_name.\n\nHowever, there is no good reason to jump around wildly just to find\nall Git commands.\n\nInstead, have a strbuf and construct the full path dynamically.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n help.c |   12 ++++++++++--\n 1 files changed, 10 insertions(+), 2 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex 480befe..7af6582 100644\n--- a/help.c\n+++ b/help.c\n@@ -426,17 +426,24 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,\n \tint prefix_len = strlen(prefix);\n \tDIR *dir = opendir(path);\n \tstruct dirent *de;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint len;\n \n-\tif (!dir || chdir(path))\n+\tif (!dir)\n \t\treturn 0;\n \n+\tstrbuf_addf(&buf, \"%s/\", path);\n+\tlen = buf.len;\n+\n \twhile ((de = readdir(dir)) != NULL) {\n \t\tint entlen;\n \n \t\tif (prefixcmp(de->d_name, prefix))\n \t\t\tcontinue;\n \n-\t\tif (!is_executable(de->d_name))\n+\t\tstrbuf_setlen(&buf, len);\n+\t\tstrbuf_addstr(&buf, de->d_name);\n+\t\tif (!is_executable(buf.buf))\n \t\t\tcontinue;\n \n \t\tentlen = strlen(de->d_name) - prefix_len;\n@@ -449,6 +456,7 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,\n \t\tadd_cmdname(cmds, de->d_name + prefix_len, entlen);\n \t}\n \tclosedir(dir);\n+\tstrbuf_release(&buf);\n \n \treturn longest;\n }\n-- \n1.6.0.rc0.97.ge2309\n"},{"id":"85217","messageId":"20080728011828.GI32057@genesis.frugalware.org","threadId":"14690","inReplyTo":"Pine.GSO.4.62.0807261301300.15728@harper.uchicago.edu","subject":"Re: [PATCH 1/7] Make is_git_command() usable outside builtin-help","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-28T01:18:28Z","receivedAt":"2008-07-28T01:18:28Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Sat, Jul 26, 2008 at 01:12:36PM -0500, Jonathan Nieder <jrnieder@uchicago.edu> wrote:\n> On Sat, 26 Jul 2008, Miklos Vajna wrote:\n> \n> > +\tif (!prefix)\n> > +\t\tprefix = \"git-\";\n> > +       \tprefix_len = strlen(prefix);\n> \n> The whitespace gave me a start: the diff markup moved the prefix_len\n> line to the next tab stop, so at first glance it seems there are missing\n> braces here.  But it is an illusion.  (I mention this so others might\n> avoid wasting time worrying about it.)\n\nIn fact it was a whitespace problem: somehow I used spaces there instead\nof a tab. I fixed it locally. (Will send an updated series soon.)\n\n> I like the patch so far.  Thanks for the pleasant reading.\n\n:-)\n"},{"id":"85218","messageId":"cover.1217207602.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"cover.1217037178.git.vmiklos@frugalware.org","subject":"[PATCH 0/6] Allow custom merge strategies, take 2","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-28T01:21:04Z","receivedAt":"2008-07-28T01:21:04Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"Hi,\n\nThis is just a resend of my series, on top of Dscho's \"Avoid chdir() in\nlist_commands_in_dir()\" (f5d600e), including the suggestions I received\nfrom Jonathan Nieder and Dscho.\n\nMiklos Vajna (6):\n  builtin-help: make is_git_command() usable outside builtin-help\n  builtin-help: make list_commands() a bit more generic\n  builtin-help: make it possible to exclude some commands in\n    list_commands()\n  builtin-merge: allow using a custom strategy\n  builtin-merge: avoid non-strategy git-merge commands in error message\n  Add a new test for using a custom merge strategy\n\n Makefile                |    1 +\n builtin-merge.c         |   32 +++++++++++++++++++++------\n help.c                  |   55 ++++++++++++++++++++++++-----------------------\n help.h                  |   19 ++++++++++++++++\n t/t7606-merge-custom.sh |   45 ++++++++++++++++++++++++++++++++++++++\n 5 files changed, 118 insertions(+), 34 deletions(-)\n create mode 100644 help.h\n create mode 100755 t/t7606-merge-custom.sh\n"},{"id":"85222","messageId":"fd19583955e9cea5b78a465d23bc127a51940048.1217207602.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"cover.1217207602.git.vmiklos@frugalware.org","subject":"[PATCH 1/6] builtin-help: make is_git_command() usable outside builtin-help","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-28T01:21:05Z","receivedAt":"2008-07-28T01:21:05Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"Other builtins may want to check if a given command is a valid git\ncommand or not as well. Additionally add a new parameter that specifies\na custom prefix, so that the \"git-\" prefix is no longer hardwired.\nUseful for example to limit the search for \"git-merge-*\".\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n Makefile |    1 +\n help.c   |   25 ++++++++++++++-----------\n help.h   |    6 ++++++\n 3 files changed, 21 insertions(+), 11 deletions(-)\n create mode 100644 help.h\n\ndiff --git a/Makefile b/Makefile\nindex 798a2f2..351afd7 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -355,6 +355,7 @@ LIB_H += git-compat-util.h\n LIB_H += graph.h\n LIB_H += grep.h\n LIB_H += hash.h\n+LIB_H += help.h\n LIB_H += list-objects.h\n LIB_H += ll-merge.h\n LIB_H += log-tree.h\ndiff --git a/help.c b/help.c\nindex 3cb1962..08188f5 100644\n--- a/help.c\n+++ b/help.c\n@@ -418,11 +418,11 @@ static int is_executable(const char *name)\n }\n \n static unsigned int list_commands_in_dir(struct cmdnames *cmds,\n-\t\t\t\t\t const char *path)\n+\t\t\t\t\t const char *path,\n+\t\t\t\t\t const char *prefix)\n {\n \tunsigned int longest = 0;\n-\tconst char *prefix = \"git-\";\n-\tint prefix_len = strlen(prefix);\n+\tint prefix_len;\n \tDIR *dir = opendir(path);\n \tstruct dirent *de;\n \tstruct strbuf buf = STRBUF_INIT;\n@@ -430,6 +430,9 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,\n \n \tif (!dir)\n \t\treturn 0;\n+\tif (!prefix)\n+\t\tprefix = \"git-\";\n+\tprefix_len = strlen(prefix);\n \n \tstrbuf_addf(&buf, \"%s/\", path);\n \tlen = buf.len;\n@@ -460,7 +463,7 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,\n \treturn longest;\n }\n \n-static unsigned int load_command_list(void)\n+static unsigned int load_command_list(const char *prefix)\n {\n \tunsigned int longest = 0;\n \tunsigned int len;\n@@ -469,7 +472,7 @@ static unsigned int load_command_list(void)\n \tconst char *exec_path = git_exec_path();\n \n \tif (exec_path)\n-\t\tlongest = list_commands_in_dir(&main_cmds, exec_path);\n+\t\tlongest = list_commands_in_dir(&main_cmds, exec_path, prefix);\n \n \tif (!env_path) {\n \t\tfprintf(stderr, \"PATH not set\\n\");\n@@ -481,7 +484,7 @@ static unsigned int load_command_list(void)\n \t\tif ((colon = strchr(path, PATH_SEP)))\n \t\t\t*colon = 0;\n \n-\t\tlen = list_commands_in_dir(&other_cmds, path);\n+\t\tlen = list_commands_in_dir(&other_cmds, path, prefix);\n \t\tif (len > longest)\n \t\t\tlongest = len;\n \n@@ -505,7 +508,7 @@ static unsigned int load_command_list(void)\n \n static void list_commands(void)\n {\n-\tunsigned int longest = load_command_list();\n+\tunsigned int longest = load_command_list(NULL);\n \tconst char *exec_path = git_exec_path();\n \n \tif (main_cmds.cnt) {\n@@ -551,9 +554,9 @@ static int is_in_cmdlist(struct cmdnames *c, const char *s)\n \treturn 0;\n }\n \n-static int is_git_command(const char *s)\n+int is_git_command(const char *s, const char *prefix)\n {\n-\tload_command_list();\n+\tload_command_list(prefix);\n \treturn is_in_cmdlist(&main_cmds, s) ||\n \t\tis_in_cmdlist(&other_cmds, s);\n }\n@@ -574,7 +577,7 @@ static const char *cmd_to_page(const char *git_cmd)\n \t\treturn \"git\";\n \telse if (!prefixcmp(git_cmd, \"git\"))\n \t\treturn git_cmd;\n-\telse if (is_git_command(git_cmd))\n+\telse if (is_git_command(git_cmd, NULL))\n \t\treturn prepend(\"git-\", git_cmd);\n \telse\n \t\treturn prepend(\"git\", git_cmd);\n@@ -712,7 +715,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \t}\n \n \talias = alias_lookup(argv[0]);\n-\tif (alias && !is_git_command(argv[0])) {\n+\tif (alias && !is_git_command(argv[0], NULL)) {\n \t\tprintf(\"`git %s' is aliased to `%s'\\n\", argv[0], alias);\n \t\treturn 0;\n \t}\ndiff --git a/help.h b/help.h\nnew file mode 100644\nindex 0000000..73da8d6\n--- /dev/null\n+++ b/help.h\n@@ -0,0 +1,6 @@\n+#ifndef HELP_H\n+#define HELP_H\n+\n+int is_git_command(const char *s, const char *prefix);\n+\n+#endif /* HELP_H */\n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85221","messageId":"5a003a0e20d0942c946680e4eade8e9d19f0036b.1217207602.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"fd19583955e9cea5b78a465d23bc127a51940048.1217207602.git.vmiklos@frugalware.org","subject":"[PATCH 2/6] builtin-help: make list_commands() a bit more generic","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-28T01:21:06Z","receivedAt":"2008-07-28T01:21:06Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"That function now takes two paramters to control the prefix of the\nlisted commands, and a second parameter to specify the title of the\ntable. This can be useful for listing not only all git commands, but\nspecific ones, like merge strategies.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n help.c |   18 ++++++++++--------\n help.h |    1 +\n 2 files changed, 11 insertions(+), 8 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex 08188f5..7a42517 100644\n--- a/help.c\n+++ b/help.c\n@@ -506,23 +506,25 @@ static unsigned int load_command_list(const char *prefix)\n \treturn longest;\n }\n \n-static void list_commands(void)\n+void list_commands(const char *prefix, const char *title)\n {\n-\tunsigned int longest = load_command_list(NULL);\n+\tunsigned int longest = load_command_list(prefix);\n \tconst char *exec_path = git_exec_path();\n \n \tif (main_cmds.cnt) {\n-\t\tprintf(\"available git commands in '%s'\\n\", exec_path);\n-\t\tprintf(\"----------------------------\");\n-\t\tmput_char('-', strlen(exec_path));\n+\t\tprintf(\"available %s in '%s'\\n\", title, exec_path);\n+\t\tprintf(\"----------------\");\n+\t\tmput_char('-', strlen(title) + strlen(exec_path));\n \t\tputchar('\\n');\n \t\tpretty_print_string_list(&main_cmds, longest);\n \t\tputchar('\\n');\n \t}\n \n \tif (other_cmds.cnt) {\n-\t\tprintf(\"git commands available from elsewhere on your $PATH\\n\");\n-\t\tprintf(\"---------------------------------------------------\\n\");\n+\t\tprintf(\"%s available from elsewhere on your $PATH\\n\", title);\n+\t\tprintf(\"---------------------------------------\");\n+\t\tmput_char('-', strlen(title));\n+\t\tputchar('\\n');\n \t\tpretty_print_string_list(&other_cmds, longest);\n \t\tputchar('\\n');\n \t}\n@@ -702,7 +704,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \tif (show_all) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n-\t\tlist_commands();\n+\t\tlist_commands(\"git-\", \"git commands\");\n \t\tprintf(\"%s\\n\", git_more_info_string);\n \t\treturn 0;\n \t}\ndiff --git a/help.h b/help.h\nindex 73da8d6..0741662 100644\n--- a/help.h\n+++ b/help.h\n@@ -2,5 +2,6 @@\n #define HELP_H\n \n int is_git_command(const char *s, const char *prefix);\n+void list_commands(const char *prefix, const char *title);\n \n #endif /* HELP_H */\n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85220","messageId":"9cc2813166c8b20ffb411c3a28ad86665e60033b.1217207602.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"5a003a0e20d0942c946680e4eade8e9d19f0036b.1217207602.git.vmiklos@frugalware.org","subject":"[PATCH 3/6] builtin-help: make it possible to exclude some commands in list_commands()","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-28T01:21:07Z","receivedAt":"2008-07-28T01:21:07Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"The supposed method is to build a list of commands to be excluded using\nadd_cmdname(), then pass the list as the new exclude parameter. If no\nexclude is needed, NULL should be used.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n help.c |   24 ++++++++++--------------\n help.h |   14 +++++++++++++-\n 2 files changed, 23 insertions(+), 15 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex 7a42517..318d6d6 100644\n--- a/help.c\n+++ b/help.c\n@@ -9,6 +9,7 @@\n #include \"common-cmds.h\"\n #include \"parse-options.h\"\n #include \"run-command.h\"\n+#include \"help.h\"\n \n static struct man_viewer_list {\n \tstruct man_viewer_list *next;\n@@ -300,16 +301,9 @@ static inline void mput_char(char c, unsigned int num)\n \t\tputchar(c);\n }\n \n-static struct cmdnames {\n-\tint alloc;\n-\tint cnt;\n-\tstruct cmdname {\n-\t\tsize_t len;\n-\t\tchar name[1];\n-\t} **names;\n-} main_cmds, other_cmds;\n+struct cmdnames main_cmds, other_cmds;\n \n-static void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n+void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n {\n \tstruct cmdname *ent = xmalloc(sizeof(*ent) + len);\n \n@@ -463,7 +457,7 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,\n \treturn longest;\n }\n \n-static unsigned int load_command_list(const char *prefix)\n+static unsigned int load_command_list(const char *prefix, struct cmdnames *exclude)\n {\n \tunsigned int longest = 0;\n \tunsigned int len;\n@@ -502,13 +496,15 @@ static unsigned int load_command_list(const char *prefix)\n \t      sizeof(*other_cmds.names), cmdname_compare);\n \tuniq(&other_cmds);\n \texclude_cmds(&other_cmds, &main_cmds);\n+\tif (exclude)\n+\t\texclude_cmds(&main_cmds, exclude);\n \n \treturn longest;\n }\n \n-void list_commands(const char *prefix, const char *title)\n+void list_commands(const char *prefix, const char *title, struct cmdnames *exclude)\n {\n-\tunsigned int longest = load_command_list(prefix);\n+\tunsigned int longest = load_command_list(prefix, exclude);\n \tconst char *exec_path = git_exec_path();\n \n \tif (main_cmds.cnt) {\n@@ -558,7 +554,7 @@ static int is_in_cmdlist(struct cmdnames *c, const char *s)\n \n int is_git_command(const char *s, const char *prefix)\n {\n-\tload_command_list(prefix);\n+\tload_command_list(prefix, NULL);\n \treturn is_in_cmdlist(&main_cmds, s) ||\n \t\tis_in_cmdlist(&other_cmds, s);\n }\n@@ -704,7 +700,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \tif (show_all) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n-\t\tlist_commands(\"git-\", \"git commands\");\n+\t\tlist_commands(\"git-\", \"git commands\", NULL);\n \t\tprintf(\"%s\\n\", git_more_info_string);\n \t\treturn 0;\n \t}\ndiff --git a/help.h b/help.h\nindex 0741662..85d3b74 100644\n--- a/help.h\n+++ b/help.h\n@@ -1,7 +1,19 @@\n #ifndef HELP_H\n #define HELP_H\n \n+struct cmdnames {\n+\tint alloc;\n+\tint cnt;\n+\tstruct cmdname {\n+\t\tsize_t len;\n+\t\tchar name[1];\n+\t} **names;\n+};\n+\n int is_git_command(const char *s, const char *prefix);\n-void list_commands(const char *prefix, const char *title);\n+void list_commands(const char *prefix, const char *title, struct cmdnames *exclude);\n+void add_cmdname(struct cmdnames *cmds, const char *name, int len);\n+\n+extern struct cmdnames main_cmds, other_cmds;\n \n #endif /* HELP_H */\n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85223","messageId":"10c4292de30b5868bd9fb54b557e8dae827f1241.1217207602.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"9cc2813166c8b20ffb411c3a28ad86665e60033b.1217207602.git.vmiklos@frugalware.org","subject":"[PATCH 4/6] builtin-merge: allow using a custom strategy","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-28T01:21:08Z","receivedAt":"2008-07-28T01:21:08Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"Allow using a custom strategy, as long as it's named git-merge-foo. The\nerror handling is now done using is_git_command(). The list of available\nstrategies is now shown by list_commands().\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n builtin-merge.c |   19 ++++++++++++-------\n 1 files changed, 12 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin-merge.c b/builtin-merge.c\nindex e78fa18..cdbc692 100644\n--- a/builtin-merge.c\n+++ b/builtin-merge.c\n@@ -22,6 +22,7 @@\n #include \"log-tree.h\"\n #include \"color.h\"\n #include \"rerere.h\"\n+#include \"help.h\"\n \n #define DEFAULT_TWOHEAD (1<<0)\n #define DEFAULT_OCTOPUS (1<<1)\n@@ -77,7 +78,7 @@ static int option_parse_message(const struct option *opt,\n static struct strategy *get_strategy(const char *name)\n {\n \tint i;\n-\tstruct strbuf err;\n+\tstruct strategy *ret;\n \n \tif (!name)\n \t\treturn NULL;\n@@ -86,12 +87,16 @@ static struct strategy *get_strategy(const char *name)\n \t\tif (!strcmp(name, all_strategy[i].name))\n \t\t\treturn &all_strategy[i];\n \n-\tstrbuf_init(&err, 0);\n-\tfor (i = 0; i < ARRAY_SIZE(all_strategy); i++)\n-\t\tstrbuf_addf(&err, \" %s\", all_strategy[i].name);\n-\tfprintf(stderr, \"Could not find merge strategy '%s'.\\n\", name);\n-\tfprintf(stderr, \"Available strategies are:%s.\\n\", err.buf);\n-\texit(1);\n+\tif (!is_git_command(name, \"git-merge-\")) {\n+\t\tfprintf(stderr, \"Could not find merge strategy '%s'.\\n\\n\", name);\n+\t\tlist_commands(\"git-merge-\", \"strategies\");\n+\t\texit(1);\n+\t}\n+\n+\tret = xmalloc(sizeof(struct strategy));\n+\tmemset(ret, 0, sizeof(struct strategy));\n+\tret->name = xstrdup(name);\n+\treturn ret;\n }\n \n static void append_strategy(struct strategy *s)\n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85219","messageId":"42e8615f6cbd236e40b19f2a754807f08e4b85a6.1217207602.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"10c4292de30b5868bd9fb54b557e8dae827f1241.1217207602.git.vmiklos@frugalware.org","subject":"[PATCH 5/6] builtin-merge: avoid non-strategy git-merge commands in error message","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-28T01:21:09Z","receivedAt":"2008-07-28T01:21:09Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"If an invalid strategy is supplied, like -s foobar, then git-merge\nlisted all git-merge-* commands. This is not perfect, since for example\ngit-merge-index is not a valid strategy.\n\nThese are now removed from the output by scanning the list of main\ncommands; if the git-merge-foo command is listed in the all_strategy\nlist, then it's shown, otherwise excluded. This does not exclude\ncommands somewhere else in the PATH, where custom strategies are\nexpected.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n builtin-merge.c |   15 ++++++++++++++-\n 1 files changed, 14 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin-merge.c b/builtin-merge.c\nindex cdbc692..29826b1 100644\n--- a/builtin-merge.c\n+++ b/builtin-merge.c\n@@ -88,8 +88,21 @@ static struct strategy *get_strategy(const char *name)\n \t\t\treturn &all_strategy[i];\n \n \tif (!is_git_command(name, \"git-merge-\")) {\n+\t\tstruct cmdnames not_strategies;\n+\n+\t\tmemset(&not_strategies, 0, sizeof(struct cmdnames));\n+\t\tfor (i = 0; i < main_cmds.cnt; i++) {\n+\t\t\tint j, found = 0;\n+\t\t\tstruct cmdname *ent = main_cmds.names[i];\n+\t\t\tfor (j = 0; j < ARRAY_SIZE(all_strategy); j++)\n+\t\t\t\tif (!strncmp(ent->name, all_strategy[j].name, ent->len)\n+\t\t\t\t\t\t&& !all_strategy[j].name[ent->len])\n+\t\t\t\t\tfound = 1;\n+\t\t\tif (!found)\n+\t\t\t\tadd_cmdname(&not_strategies, ent->name, ent->len);\n+\t\t}\n \t\tfprintf(stderr, \"Could not find merge strategy '%s'.\\n\\n\", name);\n-\t\tlist_commands(\"git-merge-\", \"strategies\");\n+\t\tlist_commands(\"git-merge-\", \"strategies\", &not_strategies);\n \t\texit(1);\n \t}\n \n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85224","messageId":"03fa2187a72957d98d63ab899b39e9adc2edfe99.1217207602.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"42e8615f6cbd236e40b19f2a754807f08e4b85a6.1217207602.git.vmiklos@frugalware.org","subject":"[PATCH 6/6] Add a new test for using a custom merge strategy","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-28T01:21:10Z","receivedAt":"2008-07-28T01:21:10Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"Testing is done by creating a simple git-merge-theirs strategy which is\nthe opposite of ours. Using this in real merges is not recommended but\nit's perfect for our testing needs.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n t/t7606-merge-custom.sh |   45 +++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 45 insertions(+), 0 deletions(-)\n create mode 100755 t/t7606-merge-custom.sh\n\ndiff --git a/t/t7606-merge-custom.sh b/t/t7606-merge-custom.sh\nnew file mode 100755\nindex 0000000..f295e56\n--- /dev/null\n+++ b/t/t7606-merge-custom.sh\n@@ -0,0 +1,45 @@\n+#!/bin/sh\n+\n+test_description='git-merge\n+\n+Testing a custom strategy.'\n+\n+. ./test-lib.sh\n+\n+cat > git-merge-theirs << EOF\n+#!/bin/sh\n+eval git read-tree --reset -u \\\\\\$\\$#\n+EOF\n+chmod +x git-merge-theirs\n+PATH=.:$PATH\n+export PATH\n+\n+test_expect_success 'setup' '\n+\techo c0 > c0.c &&\n+\tgit add c0.c &&\n+\tgit commit -m c0 &&\n+\tgit tag c0 &&\n+\techo c1 > c1.c &&\n+\tgit add c1.c &&\n+\tgit commit -m c1 &&\n+\tgit tag c1 &&\n+\tgit reset --hard c0 &&\n+\techo c2 > c2.c &&\n+\tgit add c2.c &&\n+\tgit commit -m c2 &&\n+\tgit tag c2\n+'\n+\n+test_expect_success 'merge c2 with a custom strategy' '\n+\tgit reset --hard c1 &&\n+\tgit merge -s theirs c2 &&\n+\ttest \"$(git rev-parse c1)\" != \"$(git rev-parse HEAD)\" &&\n+\ttest \"$(git rev-parse c1)\" = \"$(git rev-parse HEAD^1)\" &&\n+\ttest \"$(git rev-parse c2)\" = \"$(git rev-parse HEAD^2)\" &&\n+\tgit diff --exit-code &&\n+\ttest -f c0.c &&\n+\ttest ! -f c1.c &&\n+\ttest -f c2.c\n+'\n+\n+test_done\n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85228","messageId":"7vr69ex00x.fsf@gitster.siamese.dyndns.org","threadId":"14690","inReplyTo":"9cc2813166c8b20ffb411c3a28ad86665e60033b.1217207602.git.vmiklos@frugalware.org","subject":"Re: [PATCH 3/6] builtin-help: make it possible to exclude some commands in list_commands()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-07-28T01:36:30Z","receivedAt":"2008-07-28T01:36:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Miklos Vajna <vmiklos@frugalware.org> writes:\n\n> diff --git a/help.h b/help.h\n> index 0741662..85d3b74 100644\n> --- a/help.h\n> +++ b/help.h\n> @@ -1,7 +1,19 @@\n>  #ifndef HELP_H\n>  #define HELP_H\n>  \n> +struct cmdnames {\n> +\tint alloc;\n> +\tint cnt;\n> +\tstruct cmdname {\n> +\t\tsize_t len;\n> +\t\tchar name[1];\n> +\t} **names;\n> +};\n\nI thought we do this kind of thing using FLEX_ARRAY macro.  Is there any\nreason its use is not appropriate here?\n"},{"id":"85229","messageId":"alpine.DEB.1.00.0807280442330.5526@eeepc-johanness","threadId":"14690","inReplyTo":"7vr69ex00x.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 3/6] builtin-help: make it possible to exclude some commands in list_commands()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-28T02:43:53Z","receivedAt":"2008-07-28T02:43:53Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 27 Jul 2008, Junio C Hamano wrote:\n\n> Miklos Vajna <vmiklos@frugalware.org> writes:\n> \n> > diff --git a/help.h b/help.h\n> > index 0741662..85d3b74 100644\n> > --- a/help.h\n> > +++ b/help.h\n> > @@ -1,7 +1,19 @@\n> >  #ifndef HELP_H\n> >  #define HELP_H\n> >  \n> > +struct cmdnames {\n> > +\tint alloc;\n> > +\tint cnt;\n> > +\tstruct cmdname {\n> > +\t\tsize_t len;\n> > +\t\tchar name[1];\n> > +\t} **names;\n> > +};\n> \n> I thought we do this kind of thing using FLEX_ARRAY macro.  Is there any\n> reason its use is not appropriate here?\n\nI think that came up in the previous review round: the \"name\" member _is_ \nNUL-terminated, but could have a \".exe\" suffix.  The \"len\" member has the \nlength excluding \".exe\".\n\nCiao,\nDscho\n"},{"id":"85230","messageId":"7vljzmwvww.fsf@gitster.siamese.dyndns.org","threadId":"14690","inReplyTo":"alpine.DEB.1.00.0807280442330.5526@eeepc-johanness","subject":"Re: [PATCH 3/6] builtin-help: make it possible to exclude some commands in list_commands()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-07-28T03:05:19Z","receivedAt":"2008-07-28T03:05:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> > +struct cmdnames {\n>> > +\tint alloc;\n>> > +\tint cnt;\n>> > +\tstruct cmdname {\n>> > +\t\tsize_t len;\n>> > +\t\tchar name[1];\n>> > +\t} **names;\n>> > +};\n>> \n>> I thought we do this kind of thing using FLEX_ARRAY macro.  Is there any\n>> reason its use is not appropriate here?\n>\n> I think that came up in the previous review round: the \"name\" member _is_ \n> NUL-terminated, but could have a \".exe\" suffix.  The \"len\" member has the \n> length excluding \".exe\".\n\nSorry, but I do understand what you are trying to explain.\n\nMarking the flexible member at the end as \"last_member[FLEX_ARRAY]\" is\nabout a tiny bit of abstracting out how the exact decl syntax should look\nlike depending on the compiler.\n\nFor example, we have:\n\n        struct git_attr {\n                struct git_attr *next;\n                unsigned h;\n                int attr_nr;\n                char name[FLEX_ARRAY];\n        };\n\nAnd h is _not_ the length of the name[] (it is a hash to help us find the\nentry quickly).  Jjust like \"len\" is not the length of the name[] in your\nstructure.  In other words, marking as \"last_member[FLEX_ARRAY]\" does not\nhave anything to do with what other fields you have in the same structure.\n\nHmm, am I missing a bigger picture somewhere else?\n"},{"id":"85232","messageId":"7vhcaaws18.fsf@gitster.siamese.dyndns.org","threadId":"14690","inReplyTo":"7vljzmwvww.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 3/6] builtin-help: make it possible to exclude some commands in list_commands()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-07-28T04:29:07Z","receivedAt":"2008-07-28T04:29:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>\n>>> > +struct cmdnames {\n>>> > +\tint alloc;\n>>> > +\tint cnt;\n>>> > +\tstruct cmdname {\n>>> > +\t\tsize_t len;\n>>> > +\t\tchar name[1];\n>>> > +\t} **names;\n>>> > +};\n>>> \n>>> I thought we do this kind of thing using FLEX_ARRAY macro.  Is there any\n>>> reason its use is not appropriate here?\n>>\n>> I think that came up in the previous review round: the \"name\" member _is_ \n>> NUL-terminated, but could have a \".exe\" suffix.  The \"len\" member has the \n>> length excluding \".exe\".\n>\n> Sorry, but I do understand what you are trying to explain.\n\nYuck, stupid typo; s/do/do not/.\n"},{"id":"85264","messageId":"alpine.DEB.1.00.0807281157220.2725@eeepc-johanness","threadId":"14690","inReplyTo":"7vljzmwvww.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 3/6] builtin-help: make it possible to exclude some commands in list_commands()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-28T09:58:52Z","receivedAt":"2008-07-28T09:58:52Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 27 Jul 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> > +struct cmdnames {\n> >> > +\tint alloc;\n> >> > +\tint cnt;\n> >> > +\tstruct cmdname {\n> >> > +\t\tsize_t len;\n> >> > +\t\tchar name[1];\n> >> > +\t} **names;\n> >> > +};\n> >> \n> >> I thought we do this kind of thing using FLEX_ARRAY macro.  Is there any\n> >> reason its use is not appropriate here?\n> >\n> > I think that came up in the previous review round: the \"name\" member _is_ \n> > NUL-terminated, but could have a \".exe\" suffix.  The \"len\" member has the \n> > length excluding \".exe\".\n> \n> Sorry, but I do understand what you are trying to explain.\n> \n> Marking the flexible member at the end as \"last_member[FLEX_ARRAY]\" is\n> about a tiny bit of abstracting out how the exact decl syntax should look\n> like depending on the compiler.\n\nAh, sorry, I misunderstood.  I thought your complaint was about something \nelse.\n\nCiao,\nDscho\n"},{"id":"85289","messageId":"alpine.DEB.1.00.0807281505010.2725@eeepc-johanness","threadId":"14690","inReplyTo":"42e8615f6cbd236e40b19f2a754807f08e4b85a6.1217207602.git.vmiklos@frugalware.org","subject":"Re: [PATCH 5/6] builtin-merge: avoid non-strategy git-merge commands in error message","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-28T13:06:09Z","receivedAt":"2008-07-28T13:06:09Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 28 Jul 2008, Miklos Vajna wrote:\n\n> -\t\tlist_commands(\"git-merge-\", \"strategies\");\n> +\t\tlist_commands(\"git-merge-\", \"strategies\", &not_strategies);\n\nThe change in the signature of list_commands() is not part of this patch.  \nSo at least one of your commits should result in an uncompileable \nrevision...\n\nCiao,\nDscho\n"},{"id":"85290","messageId":"alpine.DEB.1.00.0807281506510.2725@eeepc-johanness","threadId":"14690","inReplyTo":"03fa2187a72957d98d63ab899b39e9adc2edfe99.1217207602.git.vmiklos@frugalware.org","subject":"Re: [PATCH 6/6] Add a new test for using a custom merge strategy","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-28T13:12:59Z","receivedAt":"2008-07-28T13:12:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 28 Jul 2008, Miklos Vajna wrote:\n\n> Testing is done by creating a simple git-merge-theirs strategy which is \n> the opposite of ours. Using this in real merges is not recommended but \n> it's perfect for our testing needs.\n\nNote that what was asked for, and what Junio implemented before deciding \nthat it would do more harm than good in git.git, is not the same as what \nyou provide.\n\nYour -theirs is a strict opposite of -ours, i.e. the tree after the \nmerge will be identical to the \"merged\" branch's tip's.\n\nThe -theirs which was asked for (and which I truly think is insane) wanted \nto do a merge, and in case of merge conflicts take the \"upstream\" version \n_only of the conflicting hunks_.\n\nJust to make sure everyone grasps why this is bad:\n\n- there is not only a real chance, but a high probability that a merge \n  conflict means that some related, unconflicting change relies on _one_ \n  version of the conflicting hunk which might very well be \"ours\", and\n\n- since we have a _recursive_ merge, the notion of \"upstream\" is \n  completely bogus when working on any merge that has more than one merge \n  base.  This merge would succeed, but actively be wrong.\n\nJust to make sure people do not have to ask for that version of \n\"-theirs\" again,\nDscho\n"},{"id":"85354","messageId":"5ad105819efb1c905bd01db3d08eb3422d283b3b.1217287269.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"7vr69ex00x.fsf@gitster.siamese.dyndns.org","subject":"[PATCH 3/6] builtin-help: make it possible to exclude some commands in list_commands()","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-28T23:24:52Z","receivedAt":"2008-07-28T23:24:52Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"The supposed method is to build a list of commands to be excluded using\nadd_cmdname(), then pass the list as the new exclude parameter. If no\nexclude is needed, NULL should be used.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n\nOn Sun, Jul 27, 2008 at 06:36:30PM -0700, Junio C Hamano <gitster@pobox.com> wrote:\n> > +   struct cmdname {\n> > +           size_t len;\n> > +           char name[1];\n> > +   } **names;\n> > +};\n>\n> I thought we do this kind of thing using FLEX_ARRAY macro.  Is there\n> any\n> reason its use is not appropriate here?\n\nNow I'm using it. :-)\n\nNote that FLEX_ARRAY would be a drop-in replacement only in case it\nwould be name[0], so I needed\n\n-       struct cmdname *ent = xmalloc(sizeof(*ent) + len);\n+       struct cmdname *ent = xmalloc(sizeof(*ent) + len + 1);\n\nlater in add_cmdname().\n\n help.c |   26 +++++++++++---------------\n help.h |   14 +++++++++++++-\n 2 files changed, 24 insertions(+), 16 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex 7a42517..858f76a 100644\n--- a/help.c\n+++ b/help.c\n@@ -9,6 +9,7 @@\n #include \"common-cmds.h\"\n #include \"parse-options.h\"\n #include \"run-command.h\"\n+#include \"help.h\"\n \n static struct man_viewer_list {\n \tstruct man_viewer_list *next;\n@@ -300,18 +301,11 @@ static inline void mput_char(char c, unsigned int num)\n \t\tputchar(c);\n }\n \n-static struct cmdnames {\n-\tint alloc;\n-\tint cnt;\n-\tstruct cmdname {\n-\t\tsize_t len;\n-\t\tchar name[1];\n-\t} **names;\n-} main_cmds, other_cmds;\n+struct cmdnames main_cmds, other_cmds;\n \n-static void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n+void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n {\n-\tstruct cmdname *ent = xmalloc(sizeof(*ent) + len);\n+\tstruct cmdname *ent = xmalloc(sizeof(*ent) + len + 1);\n \n \tent->len = len;\n \tmemcpy(ent->name, name, len);\n@@ -463,7 +457,7 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,\n \treturn longest;\n }\n \n-static unsigned int load_command_list(const char *prefix)\n+static unsigned int load_command_list(const char *prefix, struct cmdnames *exclude)\n {\n \tunsigned int longest = 0;\n \tunsigned int len;\n@@ -502,13 +496,15 @@ static unsigned int load_command_list(const char *prefix)\n \t      sizeof(*other_cmds.names), cmdname_compare);\n \tuniq(&other_cmds);\n \texclude_cmds(&other_cmds, &main_cmds);\n+\tif (exclude)\n+\t\texclude_cmds(&main_cmds, exclude);\n \n \treturn longest;\n }\n \n-void list_commands(const char *prefix, const char *title)\n+void list_commands(const char *prefix, const char *title, struct cmdnames *exclude)\n {\n-\tunsigned int longest = load_command_list(prefix);\n+\tunsigned int longest = load_command_list(prefix, exclude);\n \tconst char *exec_path = git_exec_path();\n \n \tif (main_cmds.cnt) {\n@@ -558,7 +554,7 @@ static int is_in_cmdlist(struct cmdnames *c, const char *s)\n \n int is_git_command(const char *s, const char *prefix)\n {\n-\tload_command_list(prefix);\n+\tload_command_list(prefix, NULL);\n \treturn is_in_cmdlist(&main_cmds, s) ||\n \t\tis_in_cmdlist(&other_cmds, s);\n }\n@@ -704,7 +700,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \tif (show_all) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n-\t\tlist_commands(\"git-\", \"git commands\");\n+\t\tlist_commands(\"git-\", \"git commands\", NULL);\n \t\tprintf(\"%s\\n\", git_more_info_string);\n \t\treturn 0;\n \t}\ndiff --git a/help.h b/help.h\nindex 0741662..3eb8cfb 100644\n--- a/help.h\n+++ b/help.h\n@@ -1,7 +1,19 @@\n #ifndef HELP_H\n #define HELP_H\n \n+struct cmdnames {\n+\tint alloc;\n+\tint cnt;\n+\tstruct cmdname {\n+\t\tsize_t len;\n+\t\tchar name[FLEX_ARRAY];\n+\t} **names;\n+};\n+\n int is_git_command(const char *s, const char *prefix);\n-void list_commands(const char *prefix, const char *title);\n+void list_commands(const char *prefix, const char *title, struct cmdnames *exclude);\n+void add_cmdname(struct cmdnames *cmds, const char *name, int len);\n+\n+extern struct cmdnames main_cmds, other_cmds;\n \n #endif /* HELP_H */\n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85356","messageId":"f3af7df2dda2dcb7801314cc993470264259f970.1217288180.git.vmiklos@frugalware.org","threadId":"14690","inReplyTo":"alpine.DEB.1.00.0807281506510.2725@eeepc-johanness","subject":"[PATCH 6/6] Add a new test for using a custom merge strategy","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-28T23:39:24Z","receivedAt":"2008-07-28T23:39:24Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"Testing is done by creating a simple git-merge-theirs strategy which\njust picks the upstream tree. (In other words, this is not the opposite\nof -s ours.)\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n\nOn Mon, Jul 28, 2008 at 03:12:59PM +0200, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> Note that what was asked for, and what Junio implemented before\n> deciding\n> that it would do more harm than good in git.git, is not the same as\n> what\n> you provide.\n\nThanks, now I see the difference. The updated commit message is\nhopefully better.\n\nAlso I added a check to make sure the upstream and the result tree is\nthe same as well.\n\n t/t7606-merge-custom.sh |   46 ++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 46 insertions(+), 0 deletions(-)\n create mode 100755 t/t7606-merge-custom.sh\n\ndiff --git a/t/t7606-merge-custom.sh b/t/t7606-merge-custom.sh\nnew file mode 100755\nindex 0000000..13e8ff5\n--- /dev/null\n+++ b/t/t7606-merge-custom.sh\n@@ -0,0 +1,46 @@\n+#!/bin/sh\n+\n+test_description='git-merge\n+\n+Testing a custom strategy.'\n+\n+. ./test-lib.sh\n+\n+cat > git-merge-theirs << EOF\n+#!/bin/sh\n+eval git read-tree --reset -u \\\\\\$\\$#\n+EOF\n+chmod +x git-merge-theirs\n+PATH=.:$PATH\n+export PATH\n+\n+test_expect_success 'setup' '\n+\techo c0 > c0.c &&\n+\tgit add c0.c &&\n+\tgit commit -m c0 &&\n+\tgit tag c0 &&\n+\techo c1 > c1.c &&\n+\tgit add c1.c &&\n+\tgit commit -m c1 &&\n+\tgit tag c1 &&\n+\tgit reset --hard c0 &&\n+\techo c2 > c2.c &&\n+\tgit add c2.c &&\n+\tgit commit -m c2 &&\n+\tgit tag c2\n+'\n+\n+test_expect_success 'merge c2 with a custom strategy' '\n+\tgit reset --hard c1 &&\n+\tgit merge -s theirs c2 &&\n+\ttest \"$(git rev-parse c1)\" != \"$(git rev-parse HEAD)\" &&\n+\ttest \"$(git rev-parse c1)\" = \"$(git rev-parse HEAD^1)\" &&\n+\ttest \"$(git rev-parse c2)\" = \"$(git rev-parse HEAD^2)\" &&\n+\ttest \"$(git rev-parse c2^{tree})\" = \"$(git rev-parse HEAD^{tree})\" &&\n+\tgit diff --exit-code &&\n+\ttest -f c0.c &&\n+\ttest ! -f c1.c &&\n+\ttest -f c2.c\n+'\n+\n+test_done\n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85358","messageId":"1217288908-21124-1-git-send-email-vmiklos@frugalware.org","threadId":"14690","inReplyTo":"alpine.DEB.1.00.0807281505010.2725@eeepc-johanness","subject":"[PATCH] builtin-merge: allow using a custom strategy","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-28T23:48:28Z","receivedAt":"2008-07-28T23:48:28Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"Allow using a custom strategy, as long as it's named git-merge-foo. The\nerror handling is now done using is_git_command(). The list of available\nstrategies is now shown by list_commands().\n\nIf an invalid strategy is supplied, like -s foobar, then git-merge would\nlist all git-merge-* commands. This is not perfect, since for example\ngit-merge-index is not a valid strategy.\n\nThese are removed from the output by scanning the list of main commands;\nif the git-merge-foo command is listed in the all_strategy list, then\nit's shown, otherwise excluded. This does not exclude commands somewhere\nelse in the PATH, where custom strategies are expected.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n\nOn Mon, Jul 28, 2008 at 03:06:09PM +0200, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> The change in the signature of list_commands() is not part of this\n> patch.  So at least one of your commits should result in an\n> uncompileable revision...\n\nRight. I just squashed patch 4 and 5, and this solves the problem: patch\n3 changes the signature and fixes all usage (in help.c, it's not used\noutside help.c), then the squashed patch introduces the usage of the new\nlist_commands() in builtin-merge.c.\n\n(Also in the 'merge-custom' branch of vmiklos.git on repo.or.cz.)\n\n builtin-merge.c |   32 +++++++++++++++++++++++++-------\n 1 files changed, 25 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin-merge.c b/builtin-merge.c\nindex e78fa18..29826b1 100644\n--- a/builtin-merge.c\n+++ b/builtin-merge.c\n@@ -22,6 +22,7 @@\n #include \"log-tree.h\"\n #include \"color.h\"\n #include \"rerere.h\"\n+#include \"help.h\"\n \n #define DEFAULT_TWOHEAD (1<<0)\n #define DEFAULT_OCTOPUS (1<<1)\n@@ -77,7 +78,7 @@ static int option_parse_message(const struct option *opt,\n static struct strategy *get_strategy(const char *name)\n {\n \tint i;\n-\tstruct strbuf err;\n+\tstruct strategy *ret;\n \n \tif (!name)\n \t\treturn NULL;\n@@ -86,12 +87,29 @@ static struct strategy *get_strategy(const char *name)\n \t\tif (!strcmp(name, all_strategy[i].name))\n \t\t\treturn &all_strategy[i];\n \n-\tstrbuf_init(&err, 0);\n-\tfor (i = 0; i < ARRAY_SIZE(all_strategy); i++)\n-\t\tstrbuf_addf(&err, \" %s\", all_strategy[i].name);\n-\tfprintf(stderr, \"Could not find merge strategy '%s'.\\n\", name);\n-\tfprintf(stderr, \"Available strategies are:%s.\\n\", err.buf);\n-\texit(1);\n+\tif (!is_git_command(name, \"git-merge-\")) {\n+\t\tstruct cmdnames not_strategies;\n+\n+\t\tmemset(&not_strategies, 0, sizeof(struct cmdnames));\n+\t\tfor (i = 0; i < main_cmds.cnt; i++) {\n+\t\t\tint j, found = 0;\n+\t\t\tstruct cmdname *ent = main_cmds.names[i];\n+\t\t\tfor (j = 0; j < ARRAY_SIZE(all_strategy); j++)\n+\t\t\t\tif (!strncmp(ent->name, all_strategy[j].name, ent->len)\n+\t\t\t\t\t\t&& !all_strategy[j].name[ent->len])\n+\t\t\t\t\tfound = 1;\n+\t\t\tif (!found)\n+\t\t\t\tadd_cmdname(&not_strategies, ent->name, ent->len);\n+\t\t}\n+\t\tfprintf(stderr, \"Could not find merge strategy '%s'.\\n\\n\", name);\n+\t\tlist_commands(\"git-merge-\", \"strategies\", &not_strategies);\n+\t\texit(1);\n+\t}\n+\n+\tret = xmalloc(sizeof(struct strategy));\n+\tmemset(ret, 0, sizeof(struct strategy));\n+\tret->name = xstrdup(name);\n+\treturn ret;\n }\n \n static void append_strategy(struct strategy *s)\n-- \n1.6.0.rc0.14.g95f8.dirty\n"},{"id":"85359","messageId":"alpine.DEB.1.00.0807290153300.2725@eeepc-johanness","threadId":"14690","inReplyTo":"f3af7df2dda2dcb7801314cc993470264259f970.1217288180.git.vmiklos@frugalware.org","subject":"Re: [PATCH 6/6] Add a new test for using a custom merge strategy","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-28T23:54:17Z","receivedAt":"2008-07-28T23:54:17Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 29 Jul 2008, Miklos Vajna wrote:\n\n> Testing is done by creating a simple git-merge-theirs strategy which\n> just picks the upstream tree. (In other words, this is not the opposite\n> of -s ours.)\n\nActually, this _is_ the opposite of -s ours, no?  -s ours just takes our \ntree, your -s theirs just takes their tree.\n\nSorry for the confusion I caused,\nDscho\n"},{"id":"85363","messageId":"20080728235847.GR32057@genesis.frugalware.org","threadId":"14690","inReplyTo":"alpine.DEB.1.00.0807290153300.2725@eeepc-johanness","subject":"Re: [PATCH 6/6] Add a new test for using a custom merge strategy","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-28T23:58:47Z","receivedAt":"2008-07-28T23:58:47Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Tue, Jul 29, 2008 at 01:54:17AM +0200, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> Actually, this _is_ the opposite of -s ours, no?  -s ours just takes our \n> tree, your -s theirs just takes their tree.\n> \n> Sorry for the confusion I caused,\n\nAah. :-)\n\nI did not read the source of git-merge-ours and based on your\ndescription I thought my knowledge / the doc about -s ours was not\ncorrect.\n\nSo I guess my original patch was right, then.\n\nNote to self: \"take 2\" gets messy, time to send a \"take 3\" soon. ;-)\n"},{"id":"85362","messageId":"alpine.DEB.1.00.0807290158470.2725@eeepc-johanness","threadId":"14690","inReplyTo":"1217288908-21124-1-git-send-email-vmiklos@frugalware.org","subject":"Re: [PATCH] builtin-merge: allow using a custom strategy","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-28T23:59:12Z","receivedAt":"2008-07-28T23:59:12Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 29 Jul 2008, Miklos Vajna wrote:\n\n> On Mon, Jul 28, 2008 at 03:06:09PM +0200, Johannes Schindelin \n> <Johannes.Schindelin@gmx.de> wrote:\n>\n> > The change in the signature of list_commands() is not part of this \n> > patch.  So at least one of your commits should result in an \n> > uncompileable revision...\n> \n> Right. I just squashed patch 4 and 5, and this solves the problem: patch \n> 3 changes the signature and fixes all usage (in help.c, it's not used \n> outside help.c), then the squashed patch introduces the usage of the new \n> list_commands() in builtin-merge.c.\n\nThanks,\nDscho\n"},{"id":"85365","messageId":"20080729000104.GS32057@genesis.frugalware.org","threadId":"14690","inReplyTo":"20080728235847.GR32057@genesis.frugalware.org","subject":"Re: [PATCH 6/6] Add a new test for using a custom merge strategy","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-29T00:01:04Z","receivedAt":"2008-07-29T00:01:04Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Tue, Jul 29, 2008 at 01:58:47AM +0200, Miklos Vajna <vmiklos@frugalware.org> wrote:\n> So I guess my original patch was right, then.\n\ns/patch/description/. The check for the same trees are still valid.\n"}]}