{"thread":{"id":"24442","subject":"[PATCH 3/4] git-shell-commands: Add a help command","startedAt":"2010-07-20T05:16:08Z","lastAt":"2010-07-26T23:28:41Z","messageCount":9,"participants":["Greg Brockman","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"145839","messageId":"1279602972-1264-1-git-send-email-gdb@mit.edu","threadId":"24442","inReplyTo":null,"subject":"Updated patch series for providing mechanism to list available repositories","fromName":"Greg Brockman","fromEmail":"gdb@mit.edu","sentAt":"2010-07-20T05:16:08Z","receivedAt":"2010-07-20T05:16:08Z","isPatch":false,"sender":{"key":"gdb@mit.edu","avatar":"https://gravatar.com/avatar/3b907cf60d0cadf6d0659d5429d971b16965fb6b1e3f5acd26a6ba2974b45da4?d=mp&s=160"},"body":"I have updated the patch series sent to this list on July 13th.  Based\nlargely on feedback from this list, I have made the following changes:\n\n- sample commands now live in contrib/git-shell-commands\n- blank lines have been added to patch 1's commit message for readability\n- commands are run with cwd of the user's $HOME directory\n- run_command is used rather than writing a new function with the same functionality\n- the shell's loop resides in its own function\n- commands are now parsed with split_cmdline, so helper functions can be passed arguments\n\nThanks to those who provided feedback.  I look forward to further\ncomments!\n\nGreg\n"},{"id":"145841","messageId":"1279602972-1264-2-git-send-email-gdb@mit.edu","threadId":"24442","inReplyTo":"1279602972-1264-1-git-send-email-gdb@mit.edu","subject":"[PATCH 1/4] Allow creation of arbitrary git-shell commands","fromName":"Greg Brockman","fromEmail":"gdb@mit.edu","sentAt":"2010-07-20T05:16:09Z","receivedAt":"2010-07-20T05:16:09Z","isPatch":true,"sender":{"key":"gdb@mit.edu","avatar":"https://gravatar.com/avatar/3b907cf60d0cadf6d0659d5429d971b16965fb6b1e3f5acd26a6ba2974b45da4?d=mp&s=160"},"body":"This provides a mechanism for the server to expose custom\nfunctionality to clients.  My particular use case is that I would like\na way of discovering all repositories available for cloning.  A\nclient that clones via\n\n  git clone user@example.com\n\ncan invoke a command by\n\n  ssh user@example.com $command\n\nSigned-off-by: Greg Brockman <gdb@mit.edu>\n---\n shell.c |   41 ++++++++++++++++++++++++++++++++++++++++-\n 1 files changed, 40 insertions(+), 1 deletions(-)\n\ndiff --git a/shell.c b/shell.c\nindex e4864e0..fe1fe73 100644\n--- a/shell.c\n+++ b/shell.c\n@@ -3,6 +3,8 @@\n #include \"exec_cmd.h\"\n #include \"strbuf.h\"\n \n+#define COMMAND_DIR \"git-shell-commands\"\n+\n static int do_generic_cmd(const char *me, char *arg)\n {\n \tconst char *my_argv[4];\n@@ -33,6 +35,20 @@ static int do_cvs_cmd(const char *me, char *arg)\n \treturn execv_git_cmd(cvsserver_argv);\n }\n \n+static int is_valid_cmd_name(const char *cmd)\n+{\n+\t/* Test command contains no . or / characters */\n+\treturn cmd[strcspn(cmd, \"./\")] == '\\0';\n+}\n+\n+static char *make_cmd(const char *prog)\n+{\n+\tchar *prefix = xmalloc((strlen(prog) + strlen(COMMAND_DIR) + 2) * sizeof(char));\n+\tstrcpy(prefix, COMMAND_DIR);\n+\tstrcat(prefix, \"/\");\n+\tstrcat(prefix, prog);\n+\treturn prefix;\n+}\n \n static struct commands {\n \tconst char *name;\n@@ -48,6 +64,8 @@ static struct commands {\n int main(int argc, char **argv)\n {\n \tchar *prog;\n+\tchar *prog_cpy;\n+\tconst char **user_argv;\n \tstruct commands *cmd;\n \tint devnull_fd;\n \n@@ -77,6 +95,7 @@ int main(int argc, char **argv)\n \t\tdie(\"What do you think I am? A shell?\");\n \n \tprog = argv[2];\n+\tprog_cpy = xstrdup(prog);\n \tif (!strncmp(prog, \"git\", 3) && isspace(prog[3]))\n \t\t/* Accept \"git foo\" as if the caller said \"git-foo\". */\n \t\tprog[3] = '-';\n@@ -99,5 +118,25 @@ int main(int argc, char **argv)\n \t\t}\n \t\texit(cmd->exec(cmd->name, arg));\n \t}\n-\tdie(\"unrecognized command '%s'\", prog);\n+\n+\tif (split_cmdline(prog, &user_argv) != -1) {\n+\t\tif (is_valid_cmd_name(user_argv[0])) {\n+\t\t\tprog  = make_cmd(user_argv[0]);\n+\t\t\tuser_argv[0] = prog;\n+\t\t\texecv(user_argv[0], (char *const *) user_argv);\n+\t\t\tfree(prog);\n+\t\t}\n+\t\tfree(user_argv);\n+\t\t/*\n+\t\t * split_cmdline modifies its argument in-place, so 'prog' now\n+\t\t * holds the actual command name\n+\t\t */\n+\t\tdie(\"unrecognized command '%s'\", prog_cpy);\n+\t} else {\n+\t\t/*\n+\t\t * split_cmdline has clobbered prog and printed an\n+\t\t * error message, so print the original\n+\t\t */\n+\t\tdie(\"invalid command format '%s'\", prog_cpy);\n+\t}\n }\n-- \n1.7.0.4\n"},{"id":"145838","messageId":"1279602972-1264-3-git-send-email-gdb@mit.edu","threadId":"24442","inReplyTo":"1279602972-1264-1-git-send-email-gdb@mit.edu","subject":"[PATCH 2/4] git-shell-commands: Add a command to list bare repos","fromName":"Greg Brockman","fromEmail":"gdb@mit.edu","sentAt":"2010-07-20T05:16:10Z","receivedAt":"2010-07-20T05:16:10Z","isPatch":true,"sender":{"key":"gdb@mit.edu","avatar":"https://gravatar.com/avatar/3b907cf60d0cadf6d0659d5429d971b16965fb6b1e3f5acd26a6ba2974b45da4?d=mp&s=160"},"body":"Signed-off-by: Greg Brockman <gdb@mit.edu>\n---\n contrib/git-shell-commands/list |    5 +++++\n 1 files changed, 5 insertions(+), 0 deletions(-)\n create mode 100755 contrib/git-shell-commands/list\n\ndiff --git a/contrib/git-shell-commands/list b/contrib/git-shell-commands/list\nnew file mode 100755\nindex 0000000..cd8b15a\n--- /dev/null\n+++ b/contrib/git-shell-commands/list\n@@ -0,0 +1,5 @@\n+#!/bin/sh\n+set -eu\n+\n+print_if_bare_repo='[ \"$(git --git-dir=\"$1\" rev-parse --is-bare-repository)\" = true ] && echo \"${1#./}\"'\n+find -type d -name \"*.git\" -exec sh -c \"$print_if_bare_repo\" -- \\{} \\; -prune\n-- \n1.7.0.4\n"},{"id":"145837","messageId":"1279602972-1264-4-git-send-email-gdb@mit.edu","threadId":"24442","inReplyTo":"1279602972-1264-1-git-send-email-gdb@mit.edu","subject":"[PATCH 3/4] git-shell-commands: Add a help command","fromName":"Greg Brockman","fromEmail":"gdb@mit.edu","sentAt":"2010-07-20T05:16:11Z","receivedAt":"2010-07-20T05:16:11Z","isPatch":true,"sender":{"key":"gdb@mit.edu","avatar":"https://gravatar.com/avatar/3b907cf60d0cadf6d0659d5429d971b16965fb6b1e3f5acd26a6ba2974b45da4?d=mp&s=160"},"body":"Signed-off-by: Greg Brockman <gdb@mit.edu>\n---\n contrib/git-shell-commands/help |   18 ++++++++++++++++++\n 1 files changed, 18 insertions(+), 0 deletions(-)\n create mode 100755 contrib/git-shell-commands/help\n\ndiff --git a/contrib/git-shell-commands/help b/contrib/git-shell-commands/help\nnew file mode 100755\nindex 0000000..19d5277\n--- /dev/null\n+++ b/contrib/git-shell-commands/help\n@@ -0,0 +1,18 @@\n+#!/bin/sh\n+\n+set -eu\n+\n+if tty -s; then\n+    echo \"Run 'help' for help, or 'exit' to leave.  Available commands:\"\n+else\n+    echo \"Run 'help' for help.  Available commands:\"\n+fi\n+\n+cd \"$(dirname \"$0\")\"\n+\n+for cmd in *; do\n+    case \"$cmd\" in\n+\thelp) ;;\n+\t*) [ -f \"$cmd\" ] && [ -x \"$cmd\" ] && echo \"$cmd\" ;;\n+    esac\n+done\n-- \n1.7.0.4\n"},{"id":"145840","messageId":"1279602972-1264-5-git-send-email-gdb@mit.edu","threadId":"24442","inReplyTo":"1279602972-1264-1-git-send-email-gdb@mit.edu","subject":"[PATCH 4/4] Add interactive mode to git-shell for user-friendliness","fromName":"Greg Brockman","fromEmail":"gdb@mit.edu","sentAt":"2010-07-20T05:16:12Z","receivedAt":"2010-07-20T05:16:12Z","isPatch":true,"sender":{"key":"gdb@mit.edu","avatar":"https://gravatar.com/avatar/3b907cf60d0cadf6d0659d5429d971b16965fb6b1e3f5acd26a6ba2974b45da4?d=mp&s=160"},"body":"Signed-off-by: Greg Brockman <gdb@mit.edu>\n---\n shell.c |   75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----\n 1 files changed, 69 insertions(+), 6 deletions(-)\n\ndiff --git a/shell.c b/shell.c\nindex fe1fe73..142d201 100644\n--- a/shell.c\n+++ b/shell.c\n@@ -2,8 +2,10 @@\n #include \"quote.h\"\n #include \"exec_cmd.h\"\n #include \"strbuf.h\"\n+#include \"run-command.h\"\n \n #define COMMAND_DIR \"git-shell-commands\"\n+#define HELP_COMMAND COMMAND_DIR \"/help\"\n \n static int do_generic_cmd(const char *me, char *arg)\n {\n@@ -50,6 +52,56 @@ static char *make_cmd(const char *prog)\n \treturn prefix;\n }\n \n+static void run_shell(void)\n+{\n+\tint done = 0;\n+\tstatic const char *help_argv[] = { HELP_COMMAND, NULL };\n+\t/* Print help if enabled */\n+\trun_command_v_opt(help_argv, RUN_SILENT_EXEC_FAILURE);\n+\n+\tdo {\n+\t\tstruct strbuf line = STRBUF_INIT;\n+\t\tconst char *prog;\n+\t\tchar *full_cmd;\n+\t\tchar *rawargs;\n+\t\tconst char **argv;\n+\t\tint code;\n+\n+\t\tfprintf(stderr, \"git> \");\n+\t\tif (strbuf_getline(&line, stdin, '\\n') == EOF) {\n+\t\t\tfprintf(stderr, \"\\n\");\n+\t\t\tstrbuf_release(&line);\n+\t\t\tbreak;\n+\t\t}\n+\t\tstrbuf_trim(&line);\n+\t\trawargs = strbuf_detach(&line, NULL);\n+\t\tif (split_cmdline(rawargs, &argv) == -1) {\n+\t\t\tfree(rawargs);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tprog = argv[0];\n+\t\tif (!strcmp(prog, \"\")) {\n+\t\t} else if (!strcmp(prog, \"quit\") || !strcmp(prog, \"logout\") ||\n+\t\t\t   !strcmp(prog, \"exit\") || !strcmp(prog, \"bye\")) {\n+\t\t\tdone = 1;\n+\t\t} else if (is_valid_cmd_name(prog)) {\n+\t\t\tfull_cmd = make_cmd(prog);\n+\t\t\targv[0] = full_cmd;\n+\t\t\tcode = run_command_v_opt(argv, RUN_SILENT_EXEC_FAILURE);\n+\t\t\tif (code == -1 && errno == ENOENT) {\n+\t\t\t\tfprintf(stderr, \"unrecognized command '%s'\\n\", prog);\n+\t\t\t}\n+\t\t\tfree(full_cmd);\n+\t\t} else {\n+\t\t\tfprintf(stderr, \"invalid command format '%s'\\n\", prog);\n+\t\t}\n+\n+\t\tfree(argv);\n+\t\tfree(rawargs);\n+\t} while (!done);\n+}\n+\n static struct commands {\n \tconst char *name;\n \tint (*exec)(const char *me, char *arg);\n@@ -84,15 +136,26 @@ int main(int argc, char **argv)\n \t/*\n \t * Special hack to pretend to be a CVS server\n \t */\n-\tif (argc == 2 && !strcmp(argv[1], \"cvs server\"))\n+\tif (argc == 2 && !strcmp(argv[1], \"cvs server\")) {\n \t\targv--;\n-\n+\t}\n \t/*\n-\t * We do not accept anything but \"-c\" followed by \"cmd arg\",\n-\t * where \"cmd\" is a very limited subset of git commands.\n+\t * Allow the user to run an interactive shell\n \t */\n-\telse if (argc != 3 || strcmp(argv[1], \"-c\"))\n-\t\tdie(\"What do you think I am? A shell?\");\n+\telse if (argc == 1) {\n+\t\tif (access(COMMAND_DIR, R_OK | X_OK) == -1)\n+\t\t\tdie(\"Sorry, the interactive git-shell is not enabled\");\n+\t\trun_shell();\n+\t\texit(0);\n+\t}\n+\t/*\n+\t * We do not accept any other modes except \"-c\" followed by\n+\t * \"cmd arg\", where \"cmd\" is a very limited subset of git\n+\t * commands or a command in the COMMAND_DIR\n+\t */\n+\telse if (argc != 3 || strcmp(argv[1], \"-c\")) {\n+\t\tdie(\"Run with no arguments or with -c cmd\");\n+\t}\n \n \tprog = argv[2];\n \tprog_cpy = xstrdup(prog);\n-- \n1.7.0.4\n"},{"id":"145868","messageId":"7vr5iym6jj.fsf@alter.siamese.dyndns.org","threadId":"24442","inReplyTo":"1279602972-1264-2-git-send-email-gdb@mit.edu","subject":"Re: [PATCH 1/4] Allow creation of arbitrary git-shell commands","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-07-20T17:01:20Z","receivedAt":"2010-07-20T17:01:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Greg Brockman <gdb@MIT.EDU> writes:\n\n> This provides a mechanism for the server to expose custom\n> functionality to clients.  My particular use case is that I would like\n> a way of discovering all repositories available for cloning.  A\n> client that clones via\n>\n>   git clone user@example.com\n>\n> can invoke a command by\n>\n>   ssh user@example.com $command\n>\n> Signed-off-by: Greg Brockman <gdb@mit.edu>\n> ---\n\nJust a few minor nits...\n\n> +static char *make_cmd(const char *prog)\n> +{\n> +\tchar *prefix = xmalloc((strlen(prog) + strlen(COMMAND_DIR) + 2) * sizeof(char));\n\nSince sizeof(char) by defintion is 1, I'd rather not to see the above\nobfuscation.\n\n> @@ -48,6 +64,8 @@ static struct commands {\n>  int main(int argc, char **argv)\n>  {\n>  \tchar *prog;\n> +\tchar *prog_cpy;\n> +\tconst char **user_argv;\n>  \tstruct commands *cmd;\n>  \tint devnull_fd;\n>  \n> @@ -77,6 +95,7 @@ int main(int argc, char **argv)\n>  \t\tdie(\"What do you think I am? A shell?\");\n>  \n>  \tprog = argv[2];\n> +\tprog_cpy = xstrdup(prog);\n\nWouldn't changing \"prog = argv[2]\" to \"prog = xstrdup(argv[2])\" easier to\nread?  Or name this new variable \"prog_orig\", have one comment here to say\n\"keep the original for reporting purposes, as prog will be munged\", and\ndrop the two 4-line comment blocks below.\n\n>  \tif (!strncmp(prog, \"git\", 3) && isspace(prog[3]))\n>  \t\t/* Accept \"git foo\" as if the caller said \"git-foo\". */\n>  \t\tprog[3] = '-';\n> @@ -99,5 +118,25 @@ int main(int argc, char **argv)\n>  \t\t}\n>  \t\texit(cmd->exec(cmd->name, arg));\n>  \t}\n> -\tdie(\"unrecognized command '%s'\", prog);\n> +\n> +\tif (split_cmdline(prog, &user_argv) != -1) {\n> +\t\tif (is_valid_cmd_name(user_argv[0])) {\n> +\t\t\tprog  = make_cmd(user_argv[0]);\n\nExtra SP before \"=\"?\n\n> +\t\t\tuser_argv[0] = prog;\n> +\t\t\texecv(user_argv[0], (char *const *) user_argv);\n> +\t\t\tfree(prog);\n> +\t\t}\n> +\t\tfree(user_argv);\n> +\t\t/*\n> +\t\t * split_cmdline modifies its argument in-place, so 'prog' now\n> +\t\t * holds the actual command name\n> +\t\t */\n> +\t\tdie(\"unrecognized command '%s'\", prog_cpy);\n> +\t} else {\n> +\t\t/*\n> +\t\t * split_cmdline has clobbered prog and printed an\n> +\t\t * error message, so print the original\n> +\t\t */\n> +\t\tdie(\"invalid command format '%s'\", prog_cpy);\n\nHmm, we might want to fix split_cmdline to report the breakage better\nthen (perhaps not as part of this patch series).  Instead of seeing\n\n    error: cmdline ends with \\.\n    fatal: invalid command format 'foo bar \\'.\n\nwouldn't it be nicer to see a single error message:\n\n    fatal: invalid command 'foo bar\\': cmdline ends with \\.\n"},{"id":"145874","messageId":"7vlj96m4mc.fsf@alter.siamese.dyndns.org","threadId":"24442","inReplyTo":"1279602972-1264-3-git-send-email-gdb@mit.edu","subject":"Re: [PATCH 2/4] git-shell-commands: Add a command to list bare repos","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-07-20T17:42:51Z","receivedAt":"2010-07-20T17:42:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Greg Brockman <gdb@MIT.EDU> writes:\n\n> Signed-off-by: Greg Brockman <gdb@mit.edu>\n> ---\n>  contrib/git-shell-commands/list |    5 +++++\n>  1 files changed, 5 insertions(+), 0 deletions(-)\n>  create mode 100755 contrib/git-shell-commands/list\n>\n> diff --git a/contrib/git-shell-commands/list b/contrib/git-shell-commands/list\n> new file mode 100755\n> index 0000000..cd8b15a\n> --- /dev/null\n> +++ b/contrib/git-shell-commands/list\n> @@ -0,0 +1,5 @@\n> +#!/bin/sh\n> +set -eu\n> +\n> +print_if_bare_repo='[ \"$(git --git-dir=\"$1\" rev-parse --is-bare-repository)\" = true ] && echo \"${1#./}\"'\n\nThat's a very long line you have here.  It might be better to do split the\nline perhaps like this for readability:\n\nprint_if_bare_repo='\n\tif \"$(git --git-dir=\"$1\" rev-parse --is-bare-repository)\" = true\n        then\n\t        printf \"%s\\n\" \"${1#./}\"\n\tfi\n'\n\nIt is unclear why it limits its listing only to bare repositories.  \"It's\nmy design decision\" is a perfectly acceptable answer, but no matter what\nthe reasoning is, it needs to be documented as a part of \"How to use this\"\ninsn to the users.  A separate file README in contrib/git-shell-commands\nthat reads like:\n\n\tAny bare repository whose name ends with \".git\" under your home\n\tdirectory is visible by \"list\" extended command (no other git\n\trepositories are visible).\n\nwould probably be a good start.\n\n> +find -type d -name \"*.git\" -exec sh -c \"$print_if_bare_repo\" -- \\{} \\; -prune\n\nAlso do you need \"set -eu\" at the beginning?  I don't see it serving a\nuseful purpose (other than being a development aid, that is).\n"},{"id":"145935","messageId":"AANLkTiktvRmx-2iSVCTvrDYrAAw0kGCtsBhb1mg1ULbx@mail.gmail.com","threadId":"24442","inReplyTo":"7vr5iym6jj.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 1/4] Allow creation of arbitrary git-shell commands","fromName":"Greg Brockman","fromEmail":"gdb@mit.edu","sentAt":"2010-07-21T15:11:10Z","receivedAt":"2010-07-21T15:11:10Z","isPatch":true,"sender":{"key":"gdb@mit.edu","avatar":"https://gravatar.com/avatar/3b907cf60d0cadf6d0659d5429d971b16965fb6b1e3f5acd26a6ba2974b45da4?d=mp&s=160"},"body":">> +                     user_argv[0] = prog;\n>> +                     execv(user_argv[0], (char *const *) user_argv);\n>> +                     free(prog);\n>> +             }\n>> +             free(user_argv);\n>> +             /*\n>> +              * split_cmdline modifies its argument in-place, so 'prog' now\n>> +              * holds the actual command name\n>> +              */\n>> +             die(\"unrecognized command '%s'\", prog_cpy);\n>> +     } else {\n>> +             /*\n>> +              * split_cmdline has clobbered prog and printed an\n>> +              * error message, so print the original\n>> +              */\n>> +             die(\"invalid command format '%s'\", prog_cpy);\n>\n> Hmm, we might want to fix split_cmdline to report the breakage better\n> then (perhaps not as part of this patch series).  Instead of seeing\n>\n>    error: cmdline ends with \\.\n>    fatal: invalid command format 'foo bar \\'.\n>\n> wouldn't it be nicer to see a single error message:\n>\n>    fatal: invalid command 'foo bar\\': cmdline ends with \\.\n>\nThat would definitely be preferable.  If possible, I would rather not\ndo it as part of this patch series, but would be happy to work on\nfixing split_cmdline afterwards.\n"},{"id":"146440","messageId":"AANLkTi=WNQ1=dx3hssgs_8Vkj6gEmrn7Z+KKdELnq+Ad@mail.gmail.com","threadId":"24442","inReplyTo":"7vlj96m4mc.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 2/4] git-shell-commands: Add a command to list bare repos","fromName":"Greg Brockman","fromEmail":"gdb@mit.edu","sentAt":"2010-07-26T23:28:41Z","receivedAt":"2010-07-26T23:28:41Z","isPatch":true,"sender":{"key":"gdb@mit.edu","avatar":"https://gravatar.com/avatar/3b907cf60d0cadf6d0659d5429d971b16965fb6b1e3f5acd26a6ba2974b45da4?d=mp&s=160"},"body":">> @@ -0,0 +1,5 @@\n>> +#!/bin/sh\n>> +set -eu\n>> +\n>> +print_if_bare_repo='[ \"$(git --git-dir=\"$1\" rev-parse --is-bare-repository)\" = true ] && echo \"${1#./}\"'\n>\n> That's a very long line you have here.  It might be better to do split the\n> line perhaps like this for readability:\n>\n> print_if_bare_repo='\n>        if \"$(git --git-dir=\"$1\" rev-parse --is-bare-repository)\" = true\n>        then\n>                printf \"%s\\n\" \"${1#./}\"\n>        fi\n> '\nSure, this seems reasonable.  Done in the latest version of my patch\nseries.  I also added a 2>/dev/null to the 'find' to discard\nunnecessary error output.\n\n> It is unclear why it limits its listing only to bare repositories.  \"It's\n> my design decision\" is a perfectly acceptable answer, but no matter what\n> the reasoning is, it needs to be documented as a part of \"How to use this\"\n> insn to the users.  A separate file README in contrib/git-shell-commands\n> that reads like:\n>\n>        Any bare repository whose name ends with \".git\" under your home\n>        directory is visible by \"list\" extended command (no other git\n>        repositories are visible).\n>\n> would probably be a good start.\nYes, basically \"it's my design decision\" is the answer here.  I now\ninclude a contrib/git-shell-commands/README, which contains the\nfollowing text regarding 'list':\n\"\"\"\nlist: Displays any bare repository whose name ends with \".git\" under\nuser's home directory.  No other git repositories are visible,\nalthough they might be clonable through git-shell.  'list' is designed\nto minimize the number of calls to git that must be made in finding\navailable repositories; if your setup has additional repositories that\nshould be user-discoverable, you may wish to modify 'list'\naccordingly.\n\"\"\"\n\n>> +find -type d -name \"*.git\" -exec sh -c \"$print_if_bare_repo\" -- \\{} \\; -prune\n>\n> Also do you need \"set -eu\" at the beginning?  I don't see it serving a\n> useful purpose (other than being a development aid, that is).\nYeah, it's was just a development aid.  I've removed the \"set -eu\" line.\n"}]}