{"thread":{"id":"21132","subject":"[PATCH] Speedup bash completion loading","startedAt":"2009-10-05T10:03:59Z","lastAt":"2009-10-10T00:57:44Z","messageCount":14,"participants":["Kirill Smelkov","Shawn O. Pearce","Ted Pavlic","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"124239","messageId":"1254737039-10404-1-git-send-email-kirr@mns.spb.ru","threadId":"21132","inReplyTo":null,"subject":"[PATCH] Speedup bash completion loading","fromName":"Kirill Smelkov","fromEmail":"kirr@mns.spb.ru","sentAt":"2009-10-05T10:03:59Z","receivedAt":"2009-10-05T10:03:59Z","isPatch":true,"sender":{"key":"kirr@navytux.spb.ru","avatar":"https://gravatar.com/avatar/cf3445fdad1849941e17ab25bf1ee7c5ea1be2deb444be25ff5f36b0e50a985f?d=mp&s=160"},"body":"On my slow laptop (P3 700MHz), system-wide bash completions take too\nmuch time to load (> 1s), and significant fraction of this time is spent\nloading git-completion.bash:\n\n    $ time bash -c '. git-completion.bash'  # before this patch\n\n    real    0m0.317s\n    user    0m0.250s\n    sys     0m0.060s\n\nI've tracked down that the most time is spent warming up merge_strategy,\nall_command & porcelain_command caches.\n\nSince git is not used in each and every interactive xterm, I think it\nwould be perfectly ok to load completion support with cold caches, and\nthen load needed thing lazily.\n\nAs __git_merge_stratiegies(), __git_all_commands() &\n__git_porcelain_command() already cache their results, we can safely\nremove associated cache initialization code and be done with it:\n\n    $ time bash -c '. git-completion.bash'  # after this patch\n\n    real    0m0.069s\n    user    0m0.050s\n    sys     0m0.020s\n\nSigned-off-by: Kirill Smelkov <kirr@mns.spb.ru>\n---\n contrib/completion/git-completion.bash |    3 ---\n 1 files changed, 0 insertions(+), 3 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 2c2a0d4..4c09d41 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -340,7 +340,6 @@ __git_merge_strategies ()\n \t}'\n }\n __git_merge_strategylist=\n-__git_merge_strategylist=$(__git_merge_strategies 2>/dev/null)\n \n __git_complete_file ()\n {\n@@ -505,7 +504,6 @@ __git_all_commands ()\n \tdone\n }\n __git_all_commandlist=\n-__git_all_commandlist=\"$(__git_all_commands 2>/dev/null)\"\n \n __git_porcelain_commands ()\n {\n@@ -596,7 +594,6 @@ __git_porcelain_commands ()\n \tdone\n }\n __git_porcelain_commandlist=\n-__git_porcelain_commandlist=\"$(__git_porcelain_commands 2>/dev/null)\"\n \n __git_aliases ()\n {\n-- \n1.6.5.rc2.17.gdbc1b\n"},{"id":"124255","messageId":"20091005152504.GE9261@spearce.org","threadId":"21132","inReplyTo":"1254737039-10404-1-git-send-email-kirr@mns.spb.ru","subject":"Re: [PATCH] Speedup bash completion loading","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-10-05T15:25:04Z","receivedAt":"2009-10-05T15:25:04Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Kirill Smelkov <kirr@mns.spb.ru> wrote:\n> I've tracked down that the most time is spent warming up merge_strategy,\n> all_command & porcelain_command caches.\n\nNak.\n\nThe problem is, during completion when we modify the value the\nchange doesn't persist beyond the current completion invocation.\nThus there is no value in the cache, so every completion attempt\nwhich needs the list has to rerun the command to compute it.\n\n \n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> index 2c2a0d4..4c09d41 100755\n> --- a/contrib/completion/git-completion.bash\n> +++ b/contrib/completion/git-completion.bash\n> @@ -340,7 +340,6 @@ __git_merge_strategies ()\n>  \t}'\n>  }\n>  __git_merge_strategylist=\n> -__git_merge_strategylist=$(__git_merge_strategies 2>/dev/null)\n>  \n>  __git_complete_file ()\n>  {\n> @@ -505,7 +504,6 @@ __git_all_commands ()\n>  \tdone\n>  }\n>  __git_all_commandlist=\n> -__git_all_commandlist=\"$(__git_all_commands 2>/dev/null)\"\n>  \n>  __git_porcelain_commands ()\n>  {\n> @@ -596,7 +594,6 @@ __git_porcelain_commands ()\n>  \tdone\n>  }\n>  __git_porcelain_commandlist=\n> -__git_porcelain_commandlist=\"$(__git_porcelain_commands 2>/dev/null)\"\n>  \n>  __git_aliases ()\n>  {\n> -- \n> 1.6.5.rc2.17.gdbc1b\n> \n\n-- \nShawn.\n"},{"id":"124261","messageId":"20091005165802.GA24402@tugrik.mns.mnsspb.ru","threadId":"21132","inReplyTo":"20091005152504.GE9261@spearce.org","subject":"Re: [PATCH] Speedup bash completion loading","fromName":"Kirill Smelkov","fromEmail":"kirr@mns.spb.ru","sentAt":"2009-10-05T16:58:02Z","receivedAt":"2009-10-05T16:58:02Z","isPatch":true,"sender":{"key":"kirr@navytux.spb.ru","avatar":"https://gravatar.com/avatar/cf3445fdad1849941e17ab25bf1ee7c5ea1be2deb444be25ff5f36b0e50a985f?d=mp&s=160"},"body":"On Mon, Oct 05, 2009 at 08:25:04AM -0700, Shawn O. Pearce wrote:\n> Kirill Smelkov <kirr@mns.spb.ru> wrote:\n> > I've tracked down that the most time is spent warming up merge_strategy,\n> > all_command & porcelain_command caches.\n> \n> Nak.\n> \n> The problem is, during completion when we modify the value the\n> change doesn't persist beyond the current completion invocation.\n> Thus there is no value in the cache, so every completion attempt\n> which needs the list has to rerun the command to compute it.\n\nYes, my mistake.\n\nTo avoid spawning subshell on $(__git_porcelain_commands) I could come up\nwith \"caching\" at the upper level, as e.g.\n\n@@ -2107,7 +2111,10 @@ _git ()\n                        --help\n                        \"\n                        ;;\n-               *)     __gitcomp \"$(__git_porcelain_commands) $(__git_aliases)\" ;;\n+               *)     __gitcomp \"\n+                       ${__git_porcelain_commandlist:=$(__git_porcelain_commands)}\n+                       $(__git_aliases)\n+                       \" ;;\n\n\nbut that's ugly and not maintainable since e.g. __git_all_commands() is used in\nseveral places.\n\n\nThe other possibility is to pregenerate all these lists at git build time, but\nare we going to do it for things under contrib/ ?\n\n\nThis could have easy solution if bash provided analog of $() to call a function\nand obtain either its stdout or return value without spawning subshell, but up\nto now I could not find such a construct in bash's man.\n\nI have to go, but I'll try to come up with something practical in several days.\n\n\nThanks for spotting it,\nKirill\n"},{"id":"124268","messageId":"4e0a90ed0910051218oaa64b94jd12a6678934523ac@mail.gmail.com","threadId":"21132","inReplyTo":"20091005165802.GA24402@tugrik.mns.mnsspb.ru","subject":"Re: [PATCH] Speedup bash completion loading","fromName":"Ted Pavlic","fromEmail":"ted@tedpavlic.com","sentAt":"2009-10-05T19:18:48Z","receivedAt":"2009-10-05T19:18:48Z","isPatch":true,"sender":{"key":"ted@tedpavlic.com","avatar":"https://gravatar.com/avatar/d085392370ff4c028cf17a0e81e0647744c9682fbcb36b499f31d08ef80ef569?d=mp&s=160"},"body":"> The other possibility is to pregenerate all these lists at git build time, but\n> are we going to do it for things under contrib/ ?\n\nIIRC, that's what StGIT does with its completion script. As a\nconsequence, StGIT completion is substantially faster than git\ncompletion.\n\n--Ted\n\n-- \nTed Pavlic <ted@tedpavlic.com>\n"},{"id":"124378","messageId":"20091008132718.GA12161@tugrik.mns.mnsspb.ru","threadId":"21132","inReplyTo":"4e0a90ed0910051218oaa64b94jd12a6678934523ac@mail.gmail.com","subject":"Re: [PATCH] Speedup bash completion loading","fromName":"Kirill Smelkov","fromEmail":"kirr@mns.spb.ru","sentAt":"2009-10-08T13:27:18Z","receivedAt":"2009-10-08T13:27:18Z","isPatch":true,"sender":{"key":"kirr@navytux.spb.ru","avatar":"https://gravatar.com/avatar/cf3445fdad1849941e17ab25bf1ee7c5ea1be2deb444be25ff5f36b0e50a985f?d=mp&s=160"},"body":"On Mon, Oct 05, 2009 at 08:25:04AM -0700, Shawn O. Pearce wrote:\n> Kirill Smelkov <kirr@mns.spb.ru> wrote:\n> > I've tracked down that the most time is spent warming up merge_strategy,\n> > all_command & porcelain_command caches.\n> \n> Nak.\n> \n> The problem is, during completion when we modify the value the\n> change doesn't persist beyond the current completion invocation.\n> Thus there is no value in the cache, so every completion attempt\n> which needs the list has to rerun the command to compute it.\n\n> > Yes, my mistake.\n> > \n> > To avoid spawning subshell on $(__git_porcelain_commands) I could come up\n> > with \"caching\" at the upper level, as e.g.\n> > \n> > @@ -2107,7 +2111,10 @@ _git ()\n> >                         --help\n> >                         \"\n> >                         ;;\n> > -               *)     __gitcomp \"$(__git_porcelain_commands) $(__git_aliases)\" ;;\n> > +               *)     __gitcomp \"\n> > +                       ${__git_porcelain_commandlist:=$(__git_porcelain_commands)}\n> > +                       $(__git_aliases)\n> > +                       \" ;;\n> > \n> > \n> > but that's ugly and not maintainable since e.g. __git_all_commands() is used in\n> > several places.\n\nOn Mon, Oct 05, 2009 at 03:18:48PM -0400, Ted Pavlic wrote:\n> > The other possibility is to pregenerate all these lists at git build time, but\n> > are we going to do it for things under contrib/ ?\n> \n> IIRC, that's what StGIT does with its completion script. As a\n> consequence, StGIT completion is substantially faster than git\n> completion.\n\nOk, it turned out that in bash, functions can't return values except\nthrough their stdout, but then we are forever with spawning\nsubprocesses. So I've decided to go the pregenerate-it way.\n\n\n[ While at it, I've also done chmod -x to git-completion.bash -- this\n  script is never executed, only sourced, so it does not need to be\n  executable. If needed I could split it in separate patch ]\n\n\n\n---- 8< ----\n\n>From 4178dcc2bd1005e26e069fe32a88b9a5b164ced6 Mon Sep 17 00:00:00 2001\nFrom: Kirill Smelkov <kirr@mns.spb.ru>\nDate: Mon, 5 Oct 2009 13:36:15 +0400\nSubject: [PATCH v2] Speedup bash completion loading\n\nOn my slow laptop (P3 700MHz), system-wide bash completions take too\nmuch time to load (> 1s), and significant fraction of this time is spent\nloading git-completion.bash:\n\n    $ time bash -c '. git-completion.bash'  # before this patch\n\n    real    0m0.317s\n    user    0m0.250s\n    sys     0m0.060s\n\nI've tracked down that the most time is spent warming up merge_strategy,\nall_command & porcelain_command caches.\n\nInitially I thought that since git is not used in each and every\ninteractive xterm, it would be perfectly ok to load completion support\nwith cold caches, and then load needed thing lazily.\n\nBut for me this strategy turned out to be difficult to implement in\nsimple and maintainable way -- bash does not provide a way to return values\nfrom inside functions, so one will have to use e.g.\n\n    ${__git_all_commandlist:=$(__git_all_commands)}\n\neverywhere in place where $(__git_all_commands) we used before, so as\nalso Ted Pavlic suggested let's pregenerate everything at build time so\nthat we have nothing to compute at runtime when git-completion.bash\nscript is loaded.\n\nThe result is that loading completion is significantly faster now:\n\n    $ time bash -c '. git-completion.bash'  # after this patch\n\n    real    0m0.068s\n    user    0m0.060s\n    sys     0m0.010s\n\nCc: Ted Pavlic <ted@tedpavlic.com>\nSigned-off-by: Kirill Smelkov <kirr@mns.spb.ru>\n---\n contrib/completion/.gitignore                      |    1 +\n contrib/completion/Makefile                        |   11 ++\n contrib/completion/git-completion.bash.generate    |  128 ++++++++++++++++\n ...{git-completion.bash => git-completion.bash.in} |  154 ++------------------\n 4 files changed, 155 insertions(+), 139 deletions(-)\n create mode 100644 contrib/completion/.gitignore\n create mode 100644 contrib/completion/Makefile\n create mode 100755 contrib/completion/git-completion.bash.generate\n rename contrib/completion/{git-completion.bash => git-completion.bash.in} (90%)\n mode change 100755 => 100644\n\ndiff --git a/contrib/completion/.gitignore b/contrib/completion/.gitignore\nnew file mode 100644\nindex 0000000..578e6a8\n--- /dev/null\n+++ b/contrib/completion/.gitignore\n@@ -0,0 +1 @@\n+git-completion.bash\ndiff --git a/contrib/completion/Makefile b/contrib/completion/Makefile\nnew file mode 100644\nindex 0000000..a0fbb66\n--- /dev/null\n+++ b/contrib/completion/Makefile\n@@ -0,0 +1,11 @@\n+all\t: git-completion.bash\n+\n+\n+git-completion.bash: git-completion.bash.in git-completion.bash.generate\n+\t# Generate completions for binaries we have just built\n+\tPATH=\"$(shell pwd)/..:$$PATH\" ./git-completion.bash.generate\n+\n+\n+clean:\n+\trm -f git-completion.bash\n+\ndiff --git a/contrib/completion/git-completion.bash.generate b/contrib/completion/git-completion.bash.generate\nnew file mode 100755\nindex 0000000..fa998dc\n--- /dev/null\n+++ b/contrib/completion/git-completion.bash.generate\n@@ -0,0 +1,128 @@\n+#!/bin/bash\n+#\n+# Generate bash completion for git.\n+#\n+# Precompute everything that can be known in advance at build time, so that\n+# actual bash completion script is loaded faster.\n+\n+__git_merge_strategies ()\n+{\n+\tgit merge -s help 2>&1 |\n+\tsed -n -e '/[Aa]vailable strategies are: /,/^$/{\n+\t\ts/\\.$//\n+\t\ts/.*://\n+\t\ts/^[ \t]*//\n+\t\ts/[ \t]*$//\n+\t\tp\n+\t}'\n+}\n+\n+__git_all_commands ()\n+{\n+\tlocal i IFS=\" \"$'\\n'\n+\tfor i in $(git help -a|egrep '^ ')\n+\tdo\n+\t\tcase $i in\n+\t\t*--*)             : helper pattern;;\n+\t\t*) echo $i;;\n+\t\tesac\n+\tdone\n+}\n+\n+\n+__git_porcelain_commands ()\n+{\n+\tlocal i IFS=\" \"$'\\n'\n+\tfor i in \"help\" $(__git_all_commands)\n+\tdo\n+\t\tcase $i in\n+\t\t*--*)             : helper pattern;;\n+\t\tapplymbox)        : ask gittus;;\n+\t\tapplypatch)       : ask gittus;;\n+\t\tarchimport)       : import;;\n+\t\tcat-file)         : plumbing;;\n+\t\tcheck-attr)       : plumbing;;\n+\t\tcheck-ref-format) : plumbing;;\n+\t\tcheckout-index)   : plumbing;;\n+\t\tcommit-tree)      : plumbing;;\n+\t\tcount-objects)    : infrequent;;\n+\t\tcvsexportcommit)  : export;;\n+\t\tcvsimport)        : import;;\n+\t\tcvsserver)        : daemon;;\n+\t\tdaemon)           : daemon;;\n+\t\tdiff-files)       : plumbing;;\n+\t\tdiff-index)       : plumbing;;\n+\t\tdiff-tree)        : plumbing;;\n+\t\tfast-import)      : import;;\n+\t\tfast-export)      : export;;\n+\t\tfsck-objects)     : plumbing;;\n+\t\tfetch-pack)       : plumbing;;\n+\t\tfmt-merge-msg)    : plumbing;;\n+\t\tfor-each-ref)     : plumbing;;\n+\t\thash-object)      : plumbing;;\n+\t\thttp-*)           : transport;;\n+\t\tindex-pack)       : plumbing;;\n+\t\tinit-db)          : deprecated;;\n+\t\tlocal-fetch)      : plumbing;;\n+\t\tlost-found)       : infrequent;;\n+\t\tls-files)         : plumbing;;\n+\t\tls-remote)        : plumbing;;\n+\t\tls-tree)          : plumbing;;\n+\t\tmailinfo)         : plumbing;;\n+\t\tmailsplit)        : plumbing;;\n+\t\tmerge-*)          : plumbing;;\n+\t\tmktree)           : plumbing;;\n+\t\tmktag)            : plumbing;;\n+\t\tpack-objects)     : plumbing;;\n+\t\tpack-redundant)   : plumbing;;\n+\t\tpack-refs)        : plumbing;;\n+\t\tparse-remote)     : plumbing;;\n+\t\tpatch-id)         : plumbing;;\n+\t\tpeek-remote)      : plumbing;;\n+\t\tprune)            : plumbing;;\n+\t\tprune-packed)     : plumbing;;\n+\t\tquiltimport)      : import;;\n+\t\tread-tree)        : plumbing;;\n+\t\treceive-pack)     : plumbing;;\n+\t\treflog)           : plumbing;;\n+\t\trepo-config)      : deprecated;;\n+\t\trerere)           : plumbing;;\n+\t\trev-list)         : plumbing;;\n+\t\trev-parse)        : plumbing;;\n+\t\trunstatus)        : plumbing;;\n+\t\tsh-setup)         : internal;;\n+\t\tshell)            : daemon;;\n+\t\tshow-ref)         : plumbing;;\n+\t\tsend-pack)        : plumbing;;\n+\t\tshow-index)       : plumbing;;\n+\t\tssh-*)            : transport;;\n+\t\tstripspace)       : plumbing;;\n+\t\tsymbolic-ref)     : plumbing;;\n+\t\ttar-tree)         : deprecated;;\n+\t\tunpack-file)      : plumbing;;\n+\t\tunpack-objects)   : plumbing;;\n+\t\tupdate-index)     : plumbing;;\n+\t\tupdate-ref)       : plumbing;;\n+\t\tupdate-server-info) : daemon;;\n+\t\tupload-archive)   : plumbing;;\n+\t\tupload-pack)      : plumbing;;\n+\t\twrite-tree)       : plumbing;;\n+\t\tvar)              : infrequent;;\n+\t\tverify-pack)      : infrequent;;\n+\t\tverify-tag)       : plumbing;;\n+\t\t*) echo $i;;\n+\t\tesac\n+\tdone\n+}\n+\n+\n+__git_merge_strategylist=$(__git_merge_strategies | tr '\\n' ' ')\n+__git_all_commandlist=\"$(__git_all_commands | tr '\\n' ' ')\"\n+__git_porcelain_commandlist=\"$(__git_porcelain_commands | tr '\\n' ' ')\"\n+\n+\n+sed -e \"s/__GIT_MERGE_STRATEGYLIST/\\\"$__git_merge_strategylist\\\"/\"\t\\\n+    -e \"s/__GIT_ALL_COMMANDLIST/\\\"$__git_all_commandlist\\\"/\"\t\\\n+    -e \"s/__GIT_PORCELAIN_COMMANDLIST/\\\"$__git_porcelain_commandlist\\\"/\"\t\\\n+    git-completion.bash.in > git-completion.bash\n+\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash.in\nold mode 100755\nnew mode 100644\nsimilarity index 90%\nrename from contrib/completion/git-completion.bash\nrename to contrib/completion/git-completion.bash.in\nindex 88b1b3c..cf1b5fd\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash.in\n@@ -21,13 +21,7 @@\n #    2) Added the following line to your .bashrc:\n #        source ~/.git-completion.sh\n #\n-#    3) You may want to make sure the git executable is available\n-#       in your PATH before this script is sourced, as some caching\n-#       is performed while the script loads.  If git isn't found\n-#       at source time then all lookups will be done on demand,\n-#       which may be slightly slower.\n-#\n-#    4) Consider changing your PS1 to also show the current branch:\n+#    3) Consider changing your PS1 to also show the current branch:\n #        PS1='[\\u@\\h \\W$(__git_ps1 \" (%s)\")]\\$ '\n #\n #       The argument to __git_ps1 will be displayed only if you\n@@ -84,6 +78,14 @@ __gitdir ()\n \tfi\n }\n \n+\n+# pregenerated stuff (to save load time)\n+__git_merge_strategylist=__GIT_MERGE_STRATEGYLIST\n+__git_all_commandlist=__GIT_ALL_COMMANDLIST\n+__git_porcelain_commandlist=__GIT_PORCELAIN_COMMANDLIST\n+\n+\n+\n # __git_ps1 accepts 0 or 1 arguments (i.e., format string)\n # returns text to add to bash PS1 prompt (includes branch name)\n __git_ps1 ()\n@@ -324,23 +326,6 @@ __git_remotes ()\n \tdone\n }\n \n-__git_merge_strategies ()\n-{\n-\tif [ -n \"${__git_merge_strategylist-}\" ]; then\n-\t\techo \"$__git_merge_strategylist\"\n-\t\treturn\n-\tfi\n-\tgit merge -s help 2>&1 |\n-\tsed -n -e '/[Aa]vailable strategies are: /,/^$/{\n-\t\ts/\\.$//\n-\t\ts/.*://\n-\t\ts/^[ \t]*//\n-\t\ts/[ \t]*$//\n-\t\tp\n-\t}'\n-}\n-__git_merge_strategylist=\n-__git_merge_strategylist=$(__git_merge_strategies 2>/dev/null)\n \n __git_complete_file ()\n {\n@@ -476,128 +461,19 @@ __git_complete_strategy ()\n {\n \tcase \"${COMP_WORDS[COMP_CWORD-1]}\" in\n \t-s|--strategy)\n-\t\t__gitcomp \"$(__git_merge_strategies)\"\n+\t\t__gitcomp \"$__git_merge_strategylist\"\n \t\treturn 0\n \tesac\n \tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n \tcase \"$cur\" in\n \t--strategy=*)\n-\t\t__gitcomp \"$(__git_merge_strategies)\" \"\" \"${cur##--strategy=}\"\n+\t\t__gitcomp \"$__git_merge_strategylist\" \"\" \"${cur##--strategy=}\"\n \t\treturn 0\n \t\t;;\n \tesac\n \treturn 1\n }\n \n-__git_all_commands ()\n-{\n-\tif [ -n \"${__git_all_commandlist-}\" ]; then\n-\t\techo \"$__git_all_commandlist\"\n-\t\treturn\n-\tfi\n-\tlocal i IFS=\" \"$'\\n'\n-\tfor i in $(git help -a|egrep '^ ')\n-\tdo\n-\t\tcase $i in\n-\t\t*--*)             : helper pattern;;\n-\t\t*) echo $i;;\n-\t\tesac\n-\tdone\n-}\n-__git_all_commandlist=\n-__git_all_commandlist=\"$(__git_all_commands 2>/dev/null)\"\n-\n-__git_porcelain_commands ()\n-{\n-\tif [ -n \"${__git_porcelain_commandlist-}\" ]; then\n-\t\techo \"$__git_porcelain_commandlist\"\n-\t\treturn\n-\tfi\n-\tlocal i IFS=\" \"$'\\n'\n-\tfor i in \"help\" $(__git_all_commands)\n-\tdo\n-\t\tcase $i in\n-\t\t*--*)             : helper pattern;;\n-\t\tapplymbox)        : ask gittus;;\n-\t\tapplypatch)       : ask gittus;;\n-\t\tarchimport)       : import;;\n-\t\tcat-file)         : plumbing;;\n-\t\tcheck-attr)       : plumbing;;\n-\t\tcheck-ref-format) : plumbing;;\n-\t\tcheckout-index)   : plumbing;;\n-\t\tcommit-tree)      : plumbing;;\n-\t\tcount-objects)    : infrequent;;\n-\t\tcvsexportcommit)  : export;;\n-\t\tcvsimport)        : import;;\n-\t\tcvsserver)        : daemon;;\n-\t\tdaemon)           : daemon;;\n-\t\tdiff-files)       : plumbing;;\n-\t\tdiff-index)       : plumbing;;\n-\t\tdiff-tree)        : plumbing;;\n-\t\tfast-import)      : import;;\n-\t\tfast-export)      : export;;\n-\t\tfsck-objects)     : plumbing;;\n-\t\tfetch-pack)       : plumbing;;\n-\t\tfmt-merge-msg)    : plumbing;;\n-\t\tfor-each-ref)     : plumbing;;\n-\t\thash-object)      : plumbing;;\n-\t\thttp-*)           : transport;;\n-\t\tindex-pack)       : plumbing;;\n-\t\tinit-db)          : deprecated;;\n-\t\tlocal-fetch)      : plumbing;;\n-\t\tlost-found)       : infrequent;;\n-\t\tls-files)         : plumbing;;\n-\t\tls-remote)        : plumbing;;\n-\t\tls-tree)          : plumbing;;\n-\t\tmailinfo)         : plumbing;;\n-\t\tmailsplit)        : plumbing;;\n-\t\tmerge-*)          : plumbing;;\n-\t\tmktree)           : plumbing;;\n-\t\tmktag)            : plumbing;;\n-\t\tpack-objects)     : plumbing;;\n-\t\tpack-redundant)   : plumbing;;\n-\t\tpack-refs)        : plumbing;;\n-\t\tparse-remote)     : plumbing;;\n-\t\tpatch-id)         : plumbing;;\n-\t\tpeek-remote)      : plumbing;;\n-\t\tprune)            : plumbing;;\n-\t\tprune-packed)     : plumbing;;\n-\t\tquiltimport)      : import;;\n-\t\tread-tree)        : plumbing;;\n-\t\treceive-pack)     : plumbing;;\n-\t\treflog)           : plumbing;;\n-\t\trepo-config)      : deprecated;;\n-\t\trerere)           : plumbing;;\n-\t\trev-list)         : plumbing;;\n-\t\trev-parse)        : plumbing;;\n-\t\trunstatus)        : plumbing;;\n-\t\tsh-setup)         : internal;;\n-\t\tshell)            : daemon;;\n-\t\tshow-ref)         : plumbing;;\n-\t\tsend-pack)        : plumbing;;\n-\t\tshow-index)       : plumbing;;\n-\t\tssh-*)            : transport;;\n-\t\tstripspace)       : plumbing;;\n-\t\tsymbolic-ref)     : plumbing;;\n-\t\ttar-tree)         : deprecated;;\n-\t\tunpack-file)      : plumbing;;\n-\t\tunpack-objects)   : plumbing;;\n-\t\tupdate-index)     : plumbing;;\n-\t\tupdate-ref)       : plumbing;;\n-\t\tupdate-server-info) : daemon;;\n-\t\tupload-archive)   : plumbing;;\n-\t\tupload-pack)      : plumbing;;\n-\t\twrite-tree)       : plumbing;;\n-\t\tvar)              : infrequent;;\n-\t\tverify-pack)      : infrequent;;\n-\t\tverify-tag)       : plumbing;;\n-\t\t*) echo $i;;\n-\t\tesac\n-\tdone\n-}\n-__git_porcelain_commandlist=\n-__git_porcelain_commandlist=\"$(__git_porcelain_commands 2>/dev/null)\"\n-\n __git_aliases ()\n {\n \tlocal i IFS=$'\\n'\n@@ -1077,7 +953,7 @@ _git_help ()\n \t\treturn\n \t\t;;\n \tesac\n-\t__gitcomp \"$(__git_all_commands)\n+\t__gitcomp \"$__git_all_commandlist\n \t\tattributes cli core-tutorial cvs-migration\n \t\tdiffcore gitk glossary hooks ignore modules\n \t\trepository-layout tutorial tutorial-2\n@@ -1423,7 +1299,7 @@ _git_config ()\n \t\treturn\n \t\t;;\n \tpull.twohead|pull.octopus)\n-\t\t__gitcomp \"$(__git_merge_strategies)\"\n+\t\t__gitcomp \"$__git_merge_strategylist\"\n \t\treturn\n \t\t;;\n \tcolor.branch|color.diff|color.interactive|\\\n@@ -1524,7 +1400,7 @@ _git_config ()\n \tpager.*)\n \t\tlocal pfx=\"${cur%.*}.\"\n \t\tcur=\"${cur#*.}\"\n-\t\t__gitcomp \"$(__git_all_commands)\" \"$pfx\" \"$cur\"\n+\t\t__gitcomp \"$__git_all_commandlist\" \"$pfx\" \"$cur\"\n \t\treturn\n \t\t;;\n \tremote.*.*)\n@@ -2116,7 +1992,7 @@ _git ()\n \t\t\t--help\n \t\t\t\"\n \t\t\t;;\n-\t\t*)     __gitcomp \"$(__git_porcelain_commands) $(__git_aliases)\" ;;\n+\t\t*)     __gitcomp \"$__git_porcelain_commandlist $(__git_aliases)\" ;;\n \t\tesac\n \t\treturn\n \tfi\n-- \n1.6.5.rc2.18.g84f98.dirty\n"},{"id":"124381","messageId":"20091008150206.GD9261@spearce.org","threadId":"21132","inReplyTo":"20091008132718.GA12161@tugrik.mns.mnsspb.ru","subject":"Re: [PATCH] Speedup bash completion loading","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-10-08T15:02:06Z","receivedAt":"2009-10-08T15:02:06Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Kirill Smelkov <kirr@mns.spb.ru> wrote:\n> diff --git a/contrib/completion/Makefile b/contrib/completion/Makefile\n> new file mode 100644\n> index 0000000..a0fbb66\n> --- /dev/null\n> +++ b/contrib/completion/Makefile\n> @@ -0,0 +1,11 @@\n> +all\t: git-completion.bash\n> +\n> +\n> +git-completion.bash: git-completion.bash.in git-completion.bash.generate\n> +\t# Generate completions for binaries we have just built\n> +\tPATH=\"$(shell pwd)/..:$$PATH\" ./git-completion.bash.generate\n\nIs only one .. enough?  Isn't that putting us into the contrib\ndirectory, and therefore not finding the 'git' we just compiled?\n\nI'm also concerned that git-completion.bash.generate requires\nbash to compile the completion for bash.  IMHO, if we are building\nthis code at compile time we shouldn't assume bash is available.\nWhat if this is a sandboxed build environment using another shell\nand /bin/bash isn't installed?\n\nI think the git-completion.bash.generate code needs to be a bit\nmore sh agnostic than the completion routines themselves are.\n\n> +# pregenerated stuff (to save load time)\n> +__git_merge_strategylist=__GIT_MERGE_STRATEGYLIST\n> +__git_all_commandlist=__GIT_ALL_COMMANDLIST\n> +__git_porcelain_commandlist=__GIT_PORCELAIN_COMMANDLIST\n\nThis also makes testing the completion a bit more difficult, now\nwe have to build it before we can load it, making the testing cycle\nactually be:\n\n  make && . git-completion.bash\n\nWe probably should place a quick comment here to remind folks that\nthey need to build the script in order to test it properly.\n\n-- \nShawn.\n"},{"id":"124382","messageId":"20091008151007.GA15098@tugrik.mns.mnsspb.ru","threadId":"21132","inReplyTo":"20091008150206.GD9261@spearce.org","subject":"Re: [PATCH] Speedup bash completion loading","fromName":"Kirill Smelkov","fromEmail":"kirr@mns.spb.ru","sentAt":"2009-10-08T15:10:07Z","receivedAt":"2009-10-08T15:10:07Z","isPatch":true,"sender":{"key":"kirr@navytux.spb.ru","avatar":"https://gravatar.com/avatar/cf3445fdad1849941e17ab25bf1ee7c5ea1be2deb444be25ff5f36b0e50a985f?d=mp&s=160"},"body":"On Thu, Oct 08, 2009 at 08:02:06AM -0700, Shawn O. Pearce wrote:\n> Kirill Smelkov <kirr@mns.spb.ru> wrote:\n> > diff --git a/contrib/completion/Makefile b/contrib/completion/Makefile\n> > new file mode 100644\n> > index 0000000..a0fbb66\n> > --- /dev/null\n> > +++ b/contrib/completion/Makefile\n> > @@ -0,0 +1,11 @@\n> > +all\t: git-completion.bash\n> > +\n> > +\n> > +git-completion.bash: git-completion.bash.in git-completion.bash.generate\n> > +\t# Generate completions for binaries we have just built\n> > +\tPATH=\"$(shell pwd)/..:$$PATH\" ./git-completion.bash.generate\n> \n> Is only one .. enough?  Isn't that putting us into the contrib\n> directory, and therefore not finding the 'git' we just compiled?\n> \n> I'm also concerned that git-completion.bash.generate requires\n> bash to compile the completion for bash.  IMHO, if we are building\n> this code at compile time we shouldn't assume bash is available.\n> What if this is a sandboxed build environment using another shell\n> and /bin/bash isn't installed?\n> \n> I think the git-completion.bash.generate code needs to be a bit\n> more sh agnostic than the completion routines themselves are.\n> \n> > +# pregenerated stuff (to save load time)\n> > +__git_merge_strategylist=__GIT_MERGE_STRATEGYLIST\n> > +__git_all_commandlist=__GIT_ALL_COMMANDLIST\n> > +__git_porcelain_commandlist=__GIT_PORCELAIN_COMMANDLIST\n> \n> This also makes testing the completion a bit more difficult, now\n> we have to build it before we can load it, making the testing cycle\n> actually be:\n> \n>   make && . git-completion.bash\n> \n> We probably should place a quick comment here to remind folks that\n> they need to build the script in order to test it properly.\n\nAgree with everything and thanks. Will reroll tommorow.\n\nКирилл\n"},{"id":"124443","messageId":"20091009090958.GA4758@tugrik.mns.mnsspb.ru","threadId":"21132","inReplyTo":"20091008150206.GD9261@spearce.org","subject":"Re: [PATCH] Speedup bash completion loading","fromName":"Kirill Smelkov","fromEmail":"kirr@mns.spb.ru","sentAt":"2009-10-09T09:09:58Z","receivedAt":"2009-10-09T09:09:58Z","isPatch":true,"sender":{"key":"kirr@navytux.spb.ru","avatar":"https://gravatar.com/avatar/cf3445fdad1849941e17ab25bf1ee7c5ea1be2deb444be25ff5f36b0e50a985f?d=mp&s=160"},"body":"On Thu, Oct 08, 2009 at 08:02:06AM -0700, Shawn O. Pearce wrote:\n> Kirill Smelkov <kirr@mns.spb.ru> wrote:\n> > diff --git a/contrib/completion/Makefile b/contrib/completion/Makefile\n> > new file mode 100644\n> > index 0000000..a0fbb66\n> > --- /dev/null\n> > +++ b/contrib/completion/Makefile\n> > @@ -0,0 +1,11 @@\n> > +all\t: git-completion.bash\n> > +\n> > +\n> > +git-completion.bash: git-completion.bash.in git-completion.bash.generate\n> > +\t# Generate completions for binaries we have just built\n> > +\tPATH=\"$(shell pwd)/..:$$PATH\" ./git-completion.bash.generate\n> \n> Is only one .. enough?  Isn't that putting us into the contrib\n> directory, and therefore not finding the 'git' we just compiled?\n\nFixed, thanks.\n\n> I'm also concerned that git-completion.bash.generate requires\n> bash to compile the completion for bash.  IMHO, if we are building\n> this code at compile time we shouldn't assume bash is available.\n> What if this is a sandboxed build environment using another shell\n> and /bin/bash isn't installed?\n> \n> I think the git-completion.bash.generate code needs to be a bit\n> more sh agnostic than the completion routines themselves are.\n\nI've reworked it not to depend on bash in 2nd patch.\n\n> > +# pregenerated stuff (to save load time)\n> > +__git_merge_strategylist=__GIT_MERGE_STRATEGYLIST\n> > +__git_all_commandlist=__GIT_ALL_COMMANDLIST\n> > +__git_porcelain_commandlist=__GIT_PORCELAIN_COMMANDLIST\n> \n> This also makes testing the completion a bit more difficult, now\n> we have to build it before we can load it, making the testing cycle\n> actually be:\n> \n>   make && . git-completion.bash\n> \n> We probably should place a quick comment here to remind folks that\n> they need to build the script in order to test it properly.\n\nI've added some sort of protection, so that git-completion.bash.in can't\nbe sourced at all. Is it ok?\n\n(interdiff for patch 1)\n\ndiff --git a/contrib/completion/Makefile b/contrib/completion/Makefile\nindex a0fbb66..90aa225 100644\n--- a/contrib/completion/Makefile\n+++ b/contrib/completion/Makefile\n@@ -3,7 +3,7 @@ all\t: git-completion.bash\n \n git-completion.bash: git-completion.bash.in git-completion.bash.generate\n \t# Generate completions for binaries we have just built\n-\tPATH=\"$(shell pwd)/..:$$PATH\" ./git-completion.bash.generate\n+\tPATH=\"$(shell pwd)/../..:$$PATH\" ./git-completion.bash.generate\n \n \n clean:\ndiff --git a/contrib/completion/git-completion.bash.in b/contrib/completion/git-completion.bash.in\nindex cf1b5fd..e1ab612 100644\n--- a/contrib/completion/git-completion.bash.in\n+++ b/contrib/completion/git-completion.bash.in\n@@ -54,6 +54,21 @@\n #       git@vger.kernel.org\n #\n \n+\n+# pregenerated stuff (to save load time)\n+__git_merge_strategylist=__GIT_MERGE_STRATEGYLIST\n+__git_all_commandlist=__GIT_ALL_COMMANDLIST\n+__git_porcelain_commandlist=__GIT_PORCELAIN_COMMANDLIST\n+\n+# remind folks that git-completion.bash.in can't be sourced\n+case \"$__git_merge_strategylist\" in\n+__GIT*)\n+\techo \"E: git-completion.bash.in can't be sourced\"\n+\treturn 1 ;;\n+esac\n+\n+\n+\n case \"$COMP_WORDBREAKS\" in\n *:*) : great ;;\n *)   COMP_WORDBREAKS=\"$COMP_WORDBREAKS:\"\n@@ -79,12 +94,6 @@ __gitdir ()\n }\n \n \n-# pregenerated stuff (to save load time)\n-__git_merge_strategylist=__GIT_MERGE_STRATEGYLIST\n-__git_all_commandlist=__GIT_ALL_COMMANDLIST\n-__git_porcelain_commandlist=__GIT_PORCELAIN_COMMANDLIST\n-\n-\n \n # __git_ps1 accepts 0 or 1 arguments (i.e., format string)\n # returns text to add to bash PS1 prompt (includes branch name)\n\n\n\nHere are new patches themselves:\n\n\n---- 8< ----\n\nFrom: Kirill Smelkov <kirr@mns.spb.ru>\nDate: Mon, 5 Oct 2009 13:36:15 +0400\nSubject: [PATCH v3 1/2] Speedup bash completion loading\n\nOn my slow laptop (P3 700MHz), system-wide bash completions take too\nmuch time to load (> 1s), and significant fraction of this time is spent\nloading git-completion.bash:\n\n    $ time bash -c '. git-completion.bash'  # before this patch\n\n    real    0m0.317s\n    user    0m0.250s\n    sys     0m0.060s\n\nI've tracked down that the most time is spent warming up merge_strategy,\nall_command & porcelain_command caches.\n\nInitially I thought that since git is not used in each and every\ninteractive xterm, it would be perfectly ok to load completion support\nwith cold caches, and then load needed thing lazily.\n\nBut for me this strategy turned out to be difficult to implement in\nsimple and maintainable way -- bash does not provide a way to return values\nfrom inside functions, so one will have to use e.g.\n\n    ${__git_all_commandlist:=$(__git_all_commands)}\n\neverywhere in place where $(__git_all_commands) we used before, so as\nalso Ted Pavlic suggested let's pregenerate everything at build time so\nthat we have nothing to compute at runtime when git-completion.bash\nscript is loaded.\n\nThe result is that loading completion is significantly faster now:\n\n    $ time bash -c '. git-completion.bash'  # after this patch\n\n    real    0m0.068s\n    user    0m0.060s\n    sys     0m0.010s\n\nCc: Ted Pavlic <ted@tedpavlic.com>\nSigned-off-by: Kirill Smelkov <kirr@mns.spb.ru>\n---\n contrib/completion/.gitignore                      |    1 +\n contrib/completion/Makefile                        |   11 ++\n contrib/completion/git-completion.bash.generate    |  128 ++++++++++++++++\n ...{git-completion.bash => git-completion.bash.in} |  161 +++-----------------\n 4 files changed, 162 insertions(+), 139 deletions(-)\n create mode 100644 contrib/completion/.gitignore\n create mode 100644 contrib/completion/Makefile\n create mode 100755 contrib/completion/git-completion.bash.generate\n rename contrib/completion/{git-completion.bash => git-completion.bash.in} (90%)\n mode change 100755 => 100644\n\ndiff --git a/contrib/completion/.gitignore b/contrib/completion/.gitignore\nnew file mode 100644\nindex 0000000..578e6a8\n--- /dev/null\n+++ b/contrib/completion/.gitignore\n@@ -0,0 +1 @@\n+git-completion.bash\ndiff --git a/contrib/completion/Makefile b/contrib/completion/Makefile\nnew file mode 100644\nindex 0000000..90aa225\n--- /dev/null\n+++ b/contrib/completion/Makefile\n@@ -0,0 +1,11 @@\n+all\t: git-completion.bash\n+\n+\n+git-completion.bash: git-completion.bash.in git-completion.bash.generate\n+\t# Generate completions for binaries we have just built\n+\tPATH=\"$(shell pwd)/../..:$$PATH\" ./git-completion.bash.generate\n+\n+\n+clean:\n+\trm -f git-completion.bash\n+\ndiff --git a/contrib/completion/git-completion.bash.generate b/contrib/completion/git-completion.bash.generate\nnew file mode 100755\nindex 0000000..fa998dc\n--- /dev/null\n+++ b/contrib/completion/git-completion.bash.generate\n@@ -0,0 +1,128 @@\n+#!/bin/bash\n+#\n+# Generate bash completion for git.\n+#\n+# Precompute everything that can be known in advance at build time, so that\n+# actual bash completion script is loaded faster.\n+\n+__git_merge_strategies ()\n+{\n+\tgit merge -s help 2>&1 |\n+\tsed -n -e '/[Aa]vailable strategies are: /,/^$/{\n+\t\ts/\\.$//\n+\t\ts/.*://\n+\t\ts/^[ \t]*//\n+\t\ts/[ \t]*$//\n+\t\tp\n+\t}'\n+}\n+\n+__git_all_commands ()\n+{\n+\tlocal i IFS=\" \"$'\\n'\n+\tfor i in $(git help -a|egrep '^ ')\n+\tdo\n+\t\tcase $i in\n+\t\t*--*)             : helper pattern;;\n+\t\t*) echo $i;;\n+\t\tesac\n+\tdone\n+}\n+\n+\n+__git_porcelain_commands ()\n+{\n+\tlocal i IFS=\" \"$'\\n'\n+\tfor i in \"help\" $(__git_all_commands)\n+\tdo\n+\t\tcase $i in\n+\t\t*--*)             : helper pattern;;\n+\t\tapplymbox)        : ask gittus;;\n+\t\tapplypatch)       : ask gittus;;\n+\t\tarchimport)       : import;;\n+\t\tcat-file)         : plumbing;;\n+\t\tcheck-attr)       : plumbing;;\n+\t\tcheck-ref-format) : plumbing;;\n+\t\tcheckout-index)   : plumbing;;\n+\t\tcommit-tree)      : plumbing;;\n+\t\tcount-objects)    : infrequent;;\n+\t\tcvsexportcommit)  : export;;\n+\t\tcvsimport)        : import;;\n+\t\tcvsserver)        : daemon;;\n+\t\tdaemon)           : daemon;;\n+\t\tdiff-files)       : plumbing;;\n+\t\tdiff-index)       : plumbing;;\n+\t\tdiff-tree)        : plumbing;;\n+\t\tfast-import)      : import;;\n+\t\tfast-export)      : export;;\n+\t\tfsck-objects)     : plumbing;;\n+\t\tfetch-pack)       : plumbing;;\n+\t\tfmt-merge-msg)    : plumbing;;\n+\t\tfor-each-ref)     : plumbing;;\n+\t\thash-object)      : plumbing;;\n+\t\thttp-*)           : transport;;\n+\t\tindex-pack)       : plumbing;;\n+\t\tinit-db)          : deprecated;;\n+\t\tlocal-fetch)      : plumbing;;\n+\t\tlost-found)       : infrequent;;\n+\t\tls-files)         : plumbing;;\n+\t\tls-remote)        : plumbing;;\n+\t\tls-tree)          : plumbing;;\n+\t\tmailinfo)         : plumbing;;\n+\t\tmailsplit)        : plumbing;;\n+\t\tmerge-*)          : plumbing;;\n+\t\tmktree)           : plumbing;;\n+\t\tmktag)            : plumbing;;\n+\t\tpack-objects)     : plumbing;;\n+\t\tpack-redundant)   : plumbing;;\n+\t\tpack-refs)        : plumbing;;\n+\t\tparse-remote)     : plumbing;;\n+\t\tpatch-id)         : plumbing;;\n+\t\tpeek-remote)      : plumbing;;\n+\t\tprune)            : plumbing;;\n+\t\tprune-packed)     : plumbing;;\n+\t\tquiltimport)      : import;;\n+\t\tread-tree)        : plumbing;;\n+\t\treceive-pack)     : plumbing;;\n+\t\treflog)           : plumbing;;\n+\t\trepo-config)      : deprecated;;\n+\t\trerere)           : plumbing;;\n+\t\trev-list)         : plumbing;;\n+\t\trev-parse)        : plumbing;;\n+\t\trunstatus)        : plumbing;;\n+\t\tsh-setup)         : internal;;\n+\t\tshell)            : daemon;;\n+\t\tshow-ref)         : plumbing;;\n+\t\tsend-pack)        : plumbing;;\n+\t\tshow-index)       : plumbing;;\n+\t\tssh-*)            : transport;;\n+\t\tstripspace)       : plumbing;;\n+\t\tsymbolic-ref)     : plumbing;;\n+\t\ttar-tree)         : deprecated;;\n+\t\tunpack-file)      : plumbing;;\n+\t\tunpack-objects)   : plumbing;;\n+\t\tupdate-index)     : plumbing;;\n+\t\tupdate-ref)       : plumbing;;\n+\t\tupdate-server-info) : daemon;;\n+\t\tupload-archive)   : plumbing;;\n+\t\tupload-pack)      : plumbing;;\n+\t\twrite-tree)       : plumbing;;\n+\t\tvar)              : infrequent;;\n+\t\tverify-pack)      : infrequent;;\n+\t\tverify-tag)       : plumbing;;\n+\t\t*) echo $i;;\n+\t\tesac\n+\tdone\n+}\n+\n+\n+__git_merge_strategylist=$(__git_merge_strategies | tr '\\n' ' ')\n+__git_all_commandlist=\"$(__git_all_commands | tr '\\n' ' ')\"\n+__git_porcelain_commandlist=\"$(__git_porcelain_commands | tr '\\n' ' ')\"\n+\n+\n+sed -e \"s/__GIT_MERGE_STRATEGYLIST/\\\"$__git_merge_strategylist\\\"/\"\t\\\n+    -e \"s/__GIT_ALL_COMMANDLIST/\\\"$__git_all_commandlist\\\"/\"\t\\\n+    -e \"s/__GIT_PORCELAIN_COMMANDLIST/\\\"$__git_porcelain_commandlist\\\"/\"\t\\\n+    git-completion.bash.in > git-completion.bash\n+\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash.in\nold mode 100755\nnew mode 100644\nsimilarity index 90%\nrename from contrib/completion/git-completion.bash\nrename to contrib/completion/git-completion.bash.in\nindex 88b1b3c..67d03c3\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash.in\n@@ -21,13 +21,7 @@\n #    2) Added the following line to your .bashrc:\n #        source ~/.git-completion.sh\n #\n-#    3) You may want to make sure the git executable is available\n-#       in your PATH before this script is sourced, as some caching\n-#       is performed while the script loads.  If git isn't found\n-#       at source time then all lookups will be done on demand,\n-#       which may be slightly slower.\n-#\n-#    4) Consider changing your PS1 to also show the current branch:\n+#    3) Consider changing your PS1 to also show the current branch:\n #        PS1='[\\u@\\h \\W$(__git_ps1 \" (%s)\")]\\$ '\n #\n #       The argument to __git_ps1 will be displayed only if you\n@@ -60,6 +54,21 @@\n #       git@vger.kernel.org\n #\n \n+\n+# pregenerated stuff (to save load time)\n+__git_merge_strategylist=__GIT_MERGE_STRATEGYLIST\n+__git_all_commandlist=__GIT_ALL_COMMANDLIST\n+__git_porcelain_commandlist=__GIT_PORCELAIN_COMMANDLIST\n+\n+# remind folks that git-completion.bash.in can't be sourced\n+case \"$__git_merge_strategylist\" in\n+__GIT*)\n+\techo \"E: git-completion.bash.in can't be sourced\"\n+\treturn 1 ;;\n+esac\n+\n+\n+\n case \"$COMP_WORDBREAKS\" in\n *:*) : great ;;\n *)   COMP_WORDBREAKS=\"$COMP_WORDBREAKS:\"\n@@ -324,23 +333,6 @@ __git_remotes ()\n \tdone\n }\n \n-__git_merge_strategies ()\n-{\n-\tif [ -n \"${__git_merge_strategylist-}\" ]; then\n-\t\techo \"$__git_merge_strategylist\"\n-\t\treturn\n-\tfi\n-\tgit merge -s help 2>&1 |\n-\tsed -n -e '/[Aa]vailable strategies are: /,/^$/{\n-\t\ts/\\.$//\n-\t\ts/.*://\n-\t\ts/^[ \t]*//\n-\t\ts/[ \t]*$//\n-\t\tp\n-\t}'\n-}\n-__git_merge_strategylist=\n-__git_merge_strategylist=$(__git_merge_strategies 2>/dev/null)\n \n __git_complete_file ()\n {\n@@ -476,128 +468,19 @@ __git_complete_strategy ()\n {\n \tcase \"${COMP_WORDS[COMP_CWORD-1]}\" in\n \t-s|--strategy)\n-\t\t__gitcomp \"$(__git_merge_strategies)\"\n+\t\t__gitcomp \"$__git_merge_strategylist\"\n \t\treturn 0\n \tesac\n \tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n \tcase \"$cur\" in\n \t--strategy=*)\n-\t\t__gitcomp \"$(__git_merge_strategies)\" \"\" \"${cur##--strategy=}\"\n+\t\t__gitcomp \"$__git_merge_strategylist\" \"\" \"${cur##--strategy=}\"\n \t\treturn 0\n \t\t;;\n \tesac\n \treturn 1\n }\n \n-__git_all_commands ()\n-{\n-\tif [ -n \"${__git_all_commandlist-}\" ]; then\n-\t\techo \"$__git_all_commandlist\"\n-\t\treturn\n-\tfi\n-\tlocal i IFS=\" \"$'\\n'\n-\tfor i in $(git help -a|egrep '^ ')\n-\tdo\n-\t\tcase $i in\n-\t\t*--*)             : helper pattern;;\n-\t\t*) echo $i;;\n-\t\tesac\n-\tdone\n-}\n-__git_all_commandlist=\n-__git_all_commandlist=\"$(__git_all_commands 2>/dev/null)\"\n-\n-__git_porcelain_commands ()\n-{\n-\tif [ -n \"${__git_porcelain_commandlist-}\" ]; then\n-\t\techo \"$__git_porcelain_commandlist\"\n-\t\treturn\n-\tfi\n-\tlocal i IFS=\" \"$'\\n'\n-\tfor i in \"help\" $(__git_all_commands)\n-\tdo\n-\t\tcase $i in\n-\t\t*--*)             : helper pattern;;\n-\t\tapplymbox)        : ask gittus;;\n-\t\tapplypatch)       : ask gittus;;\n-\t\tarchimport)       : import;;\n-\t\tcat-file)         : plumbing;;\n-\t\tcheck-attr)       : plumbing;;\n-\t\tcheck-ref-format) : plumbing;;\n-\t\tcheckout-index)   : plumbing;;\n-\t\tcommit-tree)      : plumbing;;\n-\t\tcount-objects)    : infrequent;;\n-\t\tcvsexportcommit)  : export;;\n-\t\tcvsimport)        : import;;\n-\t\tcvsserver)        : daemon;;\n-\t\tdaemon)           : daemon;;\n-\t\tdiff-files)       : plumbing;;\n-\t\tdiff-index)       : plumbing;;\n-\t\tdiff-tree)        : plumbing;;\n-\t\tfast-import)      : import;;\n-\t\tfast-export)      : export;;\n-\t\tfsck-objects)     : plumbing;;\n-\t\tfetch-pack)       : plumbing;;\n-\t\tfmt-merge-msg)    : plumbing;;\n-\t\tfor-each-ref)     : plumbing;;\n-\t\thash-object)      : plumbing;;\n-\t\thttp-*)           : transport;;\n-\t\tindex-pack)       : plumbing;;\n-\t\tinit-db)          : deprecated;;\n-\t\tlocal-fetch)      : plumbing;;\n-\t\tlost-found)       : infrequent;;\n-\t\tls-files)         : plumbing;;\n-\t\tls-remote)        : plumbing;;\n-\t\tls-tree)          : plumbing;;\n-\t\tmailinfo)         : plumbing;;\n-\t\tmailsplit)        : plumbing;;\n-\t\tmerge-*)          : plumbing;;\n-\t\tmktree)           : plumbing;;\n-\t\tmktag)            : plumbing;;\n-\t\tpack-objects)     : plumbing;;\n-\t\tpack-redundant)   : plumbing;;\n-\t\tpack-refs)        : plumbing;;\n-\t\tparse-remote)     : plumbing;;\n-\t\tpatch-id)         : plumbing;;\n-\t\tpeek-remote)      : plumbing;;\n-\t\tprune)            : plumbing;;\n-\t\tprune-packed)     : plumbing;;\n-\t\tquiltimport)      : import;;\n-\t\tread-tree)        : plumbing;;\n-\t\treceive-pack)     : plumbing;;\n-\t\treflog)           : plumbing;;\n-\t\trepo-config)      : deprecated;;\n-\t\trerere)           : plumbing;;\n-\t\trev-list)         : plumbing;;\n-\t\trev-parse)        : plumbing;;\n-\t\trunstatus)        : plumbing;;\n-\t\tsh-setup)         : internal;;\n-\t\tshell)            : daemon;;\n-\t\tshow-ref)         : plumbing;;\n-\t\tsend-pack)        : plumbing;;\n-\t\tshow-index)       : plumbing;;\n-\t\tssh-*)            : transport;;\n-\t\tstripspace)       : plumbing;;\n-\t\tsymbolic-ref)     : plumbing;;\n-\t\ttar-tree)         : deprecated;;\n-\t\tunpack-file)      : plumbing;;\n-\t\tunpack-objects)   : plumbing;;\n-\t\tupdate-index)     : plumbing;;\n-\t\tupdate-ref)       : plumbing;;\n-\t\tupdate-server-info) : daemon;;\n-\t\tupload-archive)   : plumbing;;\n-\t\tupload-pack)      : plumbing;;\n-\t\twrite-tree)       : plumbing;;\n-\t\tvar)              : infrequent;;\n-\t\tverify-pack)      : infrequent;;\n-\t\tverify-tag)       : plumbing;;\n-\t\t*) echo $i;;\n-\t\tesac\n-\tdone\n-}\n-__git_porcelain_commandlist=\n-__git_porcelain_commandlist=\"$(__git_porcelain_commands 2>/dev/null)\"\n-\n __git_aliases ()\n {\n \tlocal i IFS=$'\\n'\n@@ -1077,7 +960,7 @@ _git_help ()\n \t\treturn\n \t\t;;\n \tesac\n-\t__gitcomp \"$(__git_all_commands)\n+\t__gitcomp \"$__git_all_commandlist\n \t\tattributes cli core-tutorial cvs-migration\n \t\tdiffcore gitk glossary hooks ignore modules\n \t\trepository-layout tutorial tutorial-2\n@@ -1423,7 +1306,7 @@ _git_config ()\n \t\treturn\n \t\t;;\n \tpull.twohead|pull.octopus)\n-\t\t__gitcomp \"$(__git_merge_strategies)\"\n+\t\t__gitcomp \"$__git_merge_strategylist\"\n \t\treturn\n \t\t;;\n \tcolor.branch|color.diff|color.interactive|\\\n@@ -1524,7 +1407,7 @@ _git_config ()\n \tpager.*)\n \t\tlocal pfx=\"${cur%.*}.\"\n \t\tcur=\"${cur#*.}\"\n-\t\t__gitcomp \"$(__git_all_commands)\" \"$pfx\" \"$cur\"\n+\t\t__gitcomp \"$__git_all_commandlist\" \"$pfx\" \"$cur\"\n \t\treturn\n \t\t;;\n \tremote.*.*)\n@@ -2116,7 +1999,7 @@ _git ()\n \t\t\t--help\n \t\t\t\"\n \t\t\t;;\n-\t\t*)     __gitcomp \"$(__git_porcelain_commands) $(__git_aliases)\" ;;\n+\t\t*)     __gitcomp \"$__git_porcelain_commandlist $(__git_aliases)\" ;;\n \t\tesac\n \t\treturn\n \tfi\n-- \n1.6.5.rc2.18.g84f98.dirty\n\n\n\nFrom: Kirill Smelkov <kirr@mns.spb.ru>\nDate: Fri, 9 Oct 2009 12:45:30 +0400\nSubject: [PATCH 2/2] bash: make git-completion.bash.generate bash agnostic\n\nWe've just moved some code from git-completion.bash into\ngit-completion.bash.generate, but as Shawn O. Pearce notes, this code is\nnow used at compile time, so we shouldn't assume bash is avalable.\n\nIn more details: we used IFS=\" \"$'\\n' which works in bash, but not e.g.\nin dash, but it turns out that we can avoid setting IFS at all, look:\n\n    $ ./git help -a | egrep '^ '\n               [-p|--paginate|--no-pager]\n               [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]\n               [--help] COMMAND [ARGS]\n      add                    get-tar-commit-id      rebase\n      add--interactive       grep                   rebase--interactive\n      am                     gui                    receive-pack\n      ...\n\nFirst, there are some unneedded lines, with e.g. [--bare], and this does\nproduce noise, since e.g. in bash\n\n    $ for i in \"[--bare]\"; do echo $i ; done\n    a b\n\nso we kill it though grepping more explicitely:\n\n    $ ./git help -a | egrep '^  [^ ]'\n      add                    get-tar-commit-id      rebase\n      add--interactive       grep                   rebase--interactive\n      am                     gui                    receive-pack\n      ...\n\nAnd then, plain \"for in in $(git help -a|egrep '^ [^ ]')\" works in both\nbash and dash, which was the goal.\n\nSigned-off-by: Kirill Smelkov <kirr@mns.spb.ru>\n---\n contrib/completion/git-completion.bash.generate |    8 ++++----\n 1 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash.generate b/contrib/completion/git-completion.bash.generate\nindex fa998dc..04460eb 100755\n--- a/contrib/completion/git-completion.bash.generate\n+++ b/contrib/completion/git-completion.bash.generate\n@@ -1,4 +1,4 @@\n-#!/bin/bash\n+#!/bin/sh\n #\n # Generate bash completion for git.\n #\n@@ -19,8 +19,8 @@ __git_merge_strategies ()\n \n __git_all_commands ()\n {\n-\tlocal i IFS=\" \"$'\\n'\n-\tfor i in $(git help -a|egrep '^ ')\n+\tlocal i\n+\tfor i in $(git help -a|egrep '^  [^ ]')\n \tdo\n \t\tcase $i in\n \t\t*--*)             : helper pattern;;\n@@ -32,7 +32,7 @@ __git_all_commands ()\n \n __git_porcelain_commands ()\n {\n-\tlocal i IFS=\" \"$'\\n'\n+\tlocal i\n \tfor i in \"help\" $(__git_all_commands)\n \tdo\n \t\tcase $i in\n-- \n1.6.5.rc2.18.g84f98.dirty\n"},{"id":"124494","messageId":"20091009144606.GT9261@spearce.org","threadId":"21132","inReplyTo":"20091009090958.GA4758@tugrik.mns.mnsspb.ru","subject":"Re: [PATCH] Speedup bash completion loading","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-10-09T14:46:06Z","receivedAt":"2009-10-09T14:46:06Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Kirill Smelkov <kirr@mns.spb.ru> wrote:\n> On Thu, Oct 08, 2009 at 08:02:06AM -0700, Shawn O. Pearce wrote:\n> > We probably should place a quick comment here to remind folks that\n> > they need to build the script in order to test it properly.\n> \n> I've added some sort of protection, so that git-completion.bash.in can't\n> be sourced at all. Is it ok?\n\nYes, looks fine.\n\n> Subject: [PATCH 2/2] bash: make git-completion.bash.generate bash agnostic\n\nSquash this into the first patch and add the egrep change made by\nStephen Boyd \"[PATCH 1/2] completion: fix completion of git <TAB><TAB>\".\n \n-- \nShawn.\n"},{"id":"124504","messageId":"20091009152149.GA26171@tugrik.mns.mnsspb.ru","threadId":"21132","inReplyTo":"20091009144606.GT9261@spearce.org","subject":"Re: [PATCH] Speedup bash completion loading","fromName":"Kirill Smelkov","fromEmail":"kirr@mns.spb.ru","sentAt":"2009-10-09T15:21:49Z","receivedAt":"2009-10-09T15:21:49Z","isPatch":true,"sender":{"key":"kirr@navytux.spb.ru","avatar":"https://gravatar.com/avatar/cf3445fdad1849941e17ab25bf1ee7c5ea1be2deb444be25ff5f36b0e50a985f?d=mp&s=160"},"body":"On Fri, Oct 09, 2009 at 07:46:06AM -0700, Shawn O. Pearce wrote:\n> Kirill Smelkov <kirr@mns.spb.ru> wrote:\n> > On Thu, Oct 08, 2009 at 08:02:06AM -0700, Shawn O. Pearce wrote:\n> > > We probably should place a quick comment here to remind folks that\n> > > they need to build the script in order to test it properly.\n> > \n> > I've added some sort of protection, so that git-completion.bash.in can't\n> > be sourced at all. Is it ok?\n> \n> Yes, looks fine.\n\nThanks.\n\n> > Subject: [PATCH 2/2] bash: make git-completion.bash.generate bash agnostic\n> \n> Squash this into the first patch and add the egrep change made by\n> Stephen Boyd \"[PATCH 1/2] completion: fix completion of git <TAB><TAB>\".\n\nWhile it is technically easy to do so, isn't this a bad idea to squash\nsemantic changes and fixes into something which should be as close as\ncode movement? Especially Stephen's fix?\n\nSure you are the maintainer, but maybe let's apply this 3 patches as\nseparate ones? I don't insist - this is just my 1коп.\n\nKirill\n"},{"id":"124505","messageId":"20091009153936.GV9261@spearce.org","threadId":"21132","inReplyTo":"20091009152149.GA26171@tugrik.mns.mnsspb.ru","subject":"Re: [PATCH] Speedup bash completion loading","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-10-09T15:39:36Z","receivedAt":"2009-10-09T15:39:36Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Kirill Smelkov <kirr@mns.spb.ru> wrote:\n> On Fri, Oct 09, 2009 at 07:46:06AM -0700, Shawn O. Pearce wrote:\n> > \n> > Squash this into the first patch and add the egrep change made by\n> > Stephen Boyd \"[PATCH 1/2] completion: fix completion of git <TAB><TAB>\".\n> \n> While it is technically easy to do so, isn't this a bad idea to squash\n> semantic changes and fixes into something which should be as close as\n> code movement?\n\nThe ejection forces the code to build with /bin/bash, unless you\napply the trivial fixes related to IFS to make it work with dash.\nAs they are trivial the tiny semantic change during the code move\nis just cleaner.\n\n> Especially Stephen's fix?\n\nI expect Junio to apply his patch first, and then yours.  Since he\nis changing a region you are moving, you need to account for it in\nyour patch, otherwise we have a conflict and/or a regression.\n \n-- \nShawn.\n"},{"id":"124508","messageId":"20091009160856.GA26833@tugrik.mns.mnsspb.ru","threadId":"21132","inReplyTo":"20091009153936.GV9261@spearce.org","subject":"Re: [PATCH] Speedup bash completion loading","fromName":"Kirill Smelkov","fromEmail":"kirr@mns.spb.ru","sentAt":"2009-10-09T16:08:56Z","receivedAt":"2009-10-09T16:08:56Z","isPatch":true,"sender":{"key":"kirr@navytux.spb.ru","avatar":"https://gravatar.com/avatar/cf3445fdad1849941e17ab25bf1ee7c5ea1be2deb444be25ff5f36b0e50a985f?d=mp&s=160"},"body":"On Fri, Oct 09, 2009 at 08:39:36AM -0700, Shawn O. Pearce wrote:\n> Kirill Smelkov <kirr@mns.spb.ru> wrote:\n> > On Fri, Oct 09, 2009 at 07:46:06AM -0700, Shawn O. Pearce wrote:\n> > > \n> > > Squash this into the first patch and add the egrep change made by\n> > > Stephen Boyd \"[PATCH 1/2] completion: fix completion of git <TAB><TAB>\".\n> > \n> > While it is technically easy to do so, isn't this a bad idea to squash\n> > semantic changes and fixes into something which should be as close as\n> > code movement?\n> \n> The ejection forces the code to build with /bin/bash, unless you\n> apply the trivial fixes related to IFS to make it work with dash.\n> As they are trivial the tiny semantic change during the code move\n> is just cleaner.\n> \n> > Especially Stephen's fix?\n> \n> I expect Junio to apply his patch first, and then yours.  Since he\n> is changing a region you are moving, you need to account for it in\n> your patch, otherwise we have a conflict and/or a regression.\n\nNow I see, OK. Here is the patch which should be applied on top of\nStephen's 1/2:\n\n---- 8< ----\n\nFrom: Kirill Smelkov <kirr@mns.spb.ru>\nDate: Mon, 5 Oct 2009 13:36:15 +0400\nSubject: [PATCH v4] Speedup bash completion loading\n\nOn my slow laptop (P3 700MHz), system-wide bash completions take too\nmuch time to load (> 1s), and significant fraction of this time is spent\nloading git-completion.bash:\n\n    $ time bash -c '. git-completion.bash'  # before this patch\n\n    real    0m0.317s\n    user    0m0.250s\n    sys     0m0.060s\n\nI've tracked down that the most time is spent warming up merge_strategy,\nall_command & porcelain_command caches.\n\nInitially I thought that since git is not used in each and every\ninteractive xterm, it would be perfectly ok to load completion support\nwith cold caches, and then load needed thing lazily.\n\nBut for me this strategy turned out to be difficult to implement in\nsimple and maintainable way -- bash does not provide a way to return values\nfrom inside functions, so one will have to use e.g.\n\n    ${__git_all_commandlist:=$(__git_all_commands)}\n\neverywhere in place where $(__git_all_commands) we used before, so as\nalso Ted Pavlic suggested let's pregenerate everything at build time so\nthat we have nothing to compute at runtime when git-completion.bash\nscript is loaded.\n\nThe result is that loading completion is significantly faster now:\n\n    $ time bash -c '. git-completion.bash'  # after this patch\n\n    real    0m0.068s\n    user    0m0.060s\n    sys     0m0.010s\n\nNOTE\n----\n\nAs Shawn O. Pearce suggested, git-completion.bash.generate code is now\nused at compile time, so we shouldn't assume bash is avalable there.\n\nHence, IFS tweak (not needed in the first place) in __git_all_commands()\nwas removed, for compile-time code to be bashism free.\n\nCc: Ted Pavlic <ted@tedpavlic.com>\nSigned-off-by: Kirill Smelkov <kirr@mns.spb.ru>\n---\n contrib/completion/.gitignore                      |    1 +\n contrib/completion/Makefile                        |   11 ++\n contrib/completion/git-completion.bash.generate    |  128 ++++++++++++++++\n ...{git-completion.bash => git-completion.bash.in} |  161 +++-----------------\n 4 files changed, 162 insertions(+), 139 deletions(-)\n create mode 100644 contrib/completion/.gitignore\n create mode 100644 contrib/completion/Makefile\n create mode 100755 contrib/completion/git-completion.bash.generate\n rename contrib/completion/{git-completion.bash => git-completion.bash.in} (90%)\n mode change 100755 => 100644\n\ndiff --git a/contrib/completion/.gitignore b/contrib/completion/.gitignore\nnew file mode 100644\nindex 0000000..578e6a8\n--- /dev/null\n+++ b/contrib/completion/.gitignore\n@@ -0,0 +1 @@\n+git-completion.bash\ndiff --git a/contrib/completion/Makefile b/contrib/completion/Makefile\nnew file mode 100644\nindex 0000000..90aa225\n--- /dev/null\n+++ b/contrib/completion/Makefile\n@@ -0,0 +1,11 @@\n+all\t: git-completion.bash\n+\n+\n+git-completion.bash: git-completion.bash.in git-completion.bash.generate\n+\t# Generate completions for binaries we have just built\n+\tPATH=\"$(shell pwd)/../..:$$PATH\" ./git-completion.bash.generate\n+\n+\n+clean:\n+\trm -f git-completion.bash\n+\ndiff --git a/contrib/completion/git-completion.bash.generate b/contrib/completion/git-completion.bash.generate\nnew file mode 100755\nindex 0000000..ff64202\n--- /dev/null\n+++ b/contrib/completion/git-completion.bash.generate\n@@ -0,0 +1,128 @@\n+#!/bin/sh\n+#\n+# Generate bash completion for git.\n+#\n+# Precompute everything that can be known in advance at build time, so that\n+# actual bash completion script is loaded faster.\n+\n+__git_merge_strategies ()\n+{\n+\tgit merge -s help 2>&1 |\n+\tsed -n -e '/[Aa]vailable strategies are: /,/^$/{\n+\t\ts/\\.$//\n+\t\ts/.*://\n+\t\ts/^[ \t]*//\n+\t\ts/[ \t]*$//\n+\t\tp\n+\t}'\n+}\n+\n+__git_all_commands ()\n+{\n+\tlocal i\n+\tfor i in $(git help -a|egrep '^  [a-zA-Z0-9]')\n+\tdo\n+\t\tcase $i in\n+\t\t*--*)             : helper pattern;;\n+\t\t*) echo $i;;\n+\t\tesac\n+\tdone\n+}\n+\n+\n+__git_porcelain_commands ()\n+{\n+\tlocal i\n+\tfor i in \"help\" $(__git_all_commands)\n+\tdo\n+\t\tcase $i in\n+\t\t*--*)             : helper pattern;;\n+\t\tapplymbox)        : ask gittus;;\n+\t\tapplypatch)       : ask gittus;;\n+\t\tarchimport)       : import;;\n+\t\tcat-file)         : plumbing;;\n+\t\tcheck-attr)       : plumbing;;\n+\t\tcheck-ref-format) : plumbing;;\n+\t\tcheckout-index)   : plumbing;;\n+\t\tcommit-tree)      : plumbing;;\n+\t\tcount-objects)    : infrequent;;\n+\t\tcvsexportcommit)  : export;;\n+\t\tcvsimport)        : import;;\n+\t\tcvsserver)        : daemon;;\n+\t\tdaemon)           : daemon;;\n+\t\tdiff-files)       : plumbing;;\n+\t\tdiff-index)       : plumbing;;\n+\t\tdiff-tree)        : plumbing;;\n+\t\tfast-import)      : import;;\n+\t\tfast-export)      : export;;\n+\t\tfsck-objects)     : plumbing;;\n+\t\tfetch-pack)       : plumbing;;\n+\t\tfmt-merge-msg)    : plumbing;;\n+\t\tfor-each-ref)     : plumbing;;\n+\t\thash-object)      : plumbing;;\n+\t\thttp-*)           : transport;;\n+\t\tindex-pack)       : plumbing;;\n+\t\tinit-db)          : deprecated;;\n+\t\tlocal-fetch)      : plumbing;;\n+\t\tlost-found)       : infrequent;;\n+\t\tls-files)         : plumbing;;\n+\t\tls-remote)        : plumbing;;\n+\t\tls-tree)          : plumbing;;\n+\t\tmailinfo)         : plumbing;;\n+\t\tmailsplit)        : plumbing;;\n+\t\tmerge-*)          : plumbing;;\n+\t\tmktree)           : plumbing;;\n+\t\tmktag)            : plumbing;;\n+\t\tpack-objects)     : plumbing;;\n+\t\tpack-redundant)   : plumbing;;\n+\t\tpack-refs)        : plumbing;;\n+\t\tparse-remote)     : plumbing;;\n+\t\tpatch-id)         : plumbing;;\n+\t\tpeek-remote)      : plumbing;;\n+\t\tprune)            : plumbing;;\n+\t\tprune-packed)     : plumbing;;\n+\t\tquiltimport)      : import;;\n+\t\tread-tree)        : plumbing;;\n+\t\treceive-pack)     : plumbing;;\n+\t\treflog)           : plumbing;;\n+\t\trepo-config)      : deprecated;;\n+\t\trerere)           : plumbing;;\n+\t\trev-list)         : plumbing;;\n+\t\trev-parse)        : plumbing;;\n+\t\trunstatus)        : plumbing;;\n+\t\tsh-setup)         : internal;;\n+\t\tshell)            : daemon;;\n+\t\tshow-ref)         : plumbing;;\n+\t\tsend-pack)        : plumbing;;\n+\t\tshow-index)       : plumbing;;\n+\t\tssh-*)            : transport;;\n+\t\tstripspace)       : plumbing;;\n+\t\tsymbolic-ref)     : plumbing;;\n+\t\ttar-tree)         : deprecated;;\n+\t\tunpack-file)      : plumbing;;\n+\t\tunpack-objects)   : plumbing;;\n+\t\tupdate-index)     : plumbing;;\n+\t\tupdate-ref)       : plumbing;;\n+\t\tupdate-server-info) : daemon;;\n+\t\tupload-archive)   : plumbing;;\n+\t\tupload-pack)      : plumbing;;\n+\t\twrite-tree)       : plumbing;;\n+\t\tvar)              : infrequent;;\n+\t\tverify-pack)      : infrequent;;\n+\t\tverify-tag)       : plumbing;;\n+\t\t*) echo $i;;\n+\t\tesac\n+\tdone\n+}\n+\n+\n+__git_merge_strategylist=$(__git_merge_strategies | tr '\\n' ' ')\n+__git_all_commandlist=\"$(__git_all_commands | tr '\\n' ' ')\"\n+__git_porcelain_commandlist=\"$(__git_porcelain_commands | tr '\\n' ' ')\"\n+\n+\n+sed -e \"s/__GIT_MERGE_STRATEGYLIST/\\\"$__git_merge_strategylist\\\"/\"\t\\\n+    -e \"s/__GIT_ALL_COMMANDLIST/\\\"$__git_all_commandlist\\\"/\"\t\\\n+    -e \"s/__GIT_PORCELAIN_COMMANDLIST/\\\"$__git_porcelain_commandlist\\\"/\"\t\\\n+    git-completion.bash.in > git-completion.bash\n+\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash.in\nold mode 100755\nnew mode 100644\nsimilarity index 90%\nrename from contrib/completion/git-completion.bash\nrename to contrib/completion/git-completion.bash.in\nindex 652a47c..67d03c3\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash.in\n@@ -21,13 +21,7 @@\n #    2) Added the following line to your .bashrc:\n #        source ~/.git-completion.sh\n #\n-#    3) You may want to make sure the git executable is available\n-#       in your PATH before this script is sourced, as some caching\n-#       is performed while the script loads.  If git isn't found\n-#       at source time then all lookups will be done on demand,\n-#       which may be slightly slower.\n-#\n-#    4) Consider changing your PS1 to also show the current branch:\n+#    3) Consider changing your PS1 to also show the current branch:\n #        PS1='[\\u@\\h \\W$(__git_ps1 \" (%s)\")]\\$ '\n #\n #       The argument to __git_ps1 will be displayed only if you\n@@ -60,6 +54,21 @@\n #       git@vger.kernel.org\n #\n \n+\n+# pregenerated stuff (to save load time)\n+__git_merge_strategylist=__GIT_MERGE_STRATEGYLIST\n+__git_all_commandlist=__GIT_ALL_COMMANDLIST\n+__git_porcelain_commandlist=__GIT_PORCELAIN_COMMANDLIST\n+\n+# remind folks that git-completion.bash.in can't be sourced\n+case \"$__git_merge_strategylist\" in\n+__GIT*)\n+\techo \"E: git-completion.bash.in can't be sourced\"\n+\treturn 1 ;;\n+esac\n+\n+\n+\n case \"$COMP_WORDBREAKS\" in\n *:*) : great ;;\n *)   COMP_WORDBREAKS=\"$COMP_WORDBREAKS:\"\n@@ -324,23 +333,6 @@ __git_remotes ()\n \tdone\n }\n \n-__git_merge_strategies ()\n-{\n-\tif [ -n \"${__git_merge_strategylist-}\" ]; then\n-\t\techo \"$__git_merge_strategylist\"\n-\t\treturn\n-\tfi\n-\tgit merge -s help 2>&1 |\n-\tsed -n -e '/[Aa]vailable strategies are: /,/^$/{\n-\t\ts/\\.$//\n-\t\ts/.*://\n-\t\ts/^[ \t]*//\n-\t\ts/[ \t]*$//\n-\t\tp\n-\t}'\n-}\n-__git_merge_strategylist=\n-__git_merge_strategylist=$(__git_merge_strategies 2>/dev/null)\n \n __git_complete_file ()\n {\n@@ -476,128 +468,19 @@ __git_complete_strategy ()\n {\n \tcase \"${COMP_WORDS[COMP_CWORD-1]}\" in\n \t-s|--strategy)\n-\t\t__gitcomp \"$(__git_merge_strategies)\"\n+\t\t__gitcomp \"$__git_merge_strategylist\"\n \t\treturn 0\n \tesac\n \tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n \tcase \"$cur\" in\n \t--strategy=*)\n-\t\t__gitcomp \"$(__git_merge_strategies)\" \"\" \"${cur##--strategy=}\"\n+\t\t__gitcomp \"$__git_merge_strategylist\" \"\" \"${cur##--strategy=}\"\n \t\treturn 0\n \t\t;;\n \tesac\n \treturn 1\n }\n \n-__git_all_commands ()\n-{\n-\tif [ -n \"${__git_all_commandlist-}\" ]; then\n-\t\techo \"$__git_all_commandlist\"\n-\t\treturn\n-\tfi\n-\tlocal i IFS=\" \"$'\\n'\n-\tfor i in $(git help -a|egrep '^  [a-zA-Z0-9]')\n-\tdo\n-\t\tcase $i in\n-\t\t*--*)             : helper pattern;;\n-\t\t*) echo $i;;\n-\t\tesac\n-\tdone\n-}\n-__git_all_commandlist=\n-__git_all_commandlist=\"$(__git_all_commands 2>/dev/null)\"\n-\n-__git_porcelain_commands ()\n-{\n-\tif [ -n \"${__git_porcelain_commandlist-}\" ]; then\n-\t\techo \"$__git_porcelain_commandlist\"\n-\t\treturn\n-\tfi\n-\tlocal i IFS=\" \"$'\\n'\n-\tfor i in \"help\" $(__git_all_commands)\n-\tdo\n-\t\tcase $i in\n-\t\t*--*)             : helper pattern;;\n-\t\tapplymbox)        : ask gittus;;\n-\t\tapplypatch)       : ask gittus;;\n-\t\tarchimport)       : import;;\n-\t\tcat-file)         : plumbing;;\n-\t\tcheck-attr)       : plumbing;;\n-\t\tcheck-ref-format) : plumbing;;\n-\t\tcheckout-index)   : plumbing;;\n-\t\tcommit-tree)      : plumbing;;\n-\t\tcount-objects)    : infrequent;;\n-\t\tcvsexportcommit)  : export;;\n-\t\tcvsimport)        : import;;\n-\t\tcvsserver)        : daemon;;\n-\t\tdaemon)           : daemon;;\n-\t\tdiff-files)       : plumbing;;\n-\t\tdiff-index)       : plumbing;;\n-\t\tdiff-tree)        : plumbing;;\n-\t\tfast-import)      : import;;\n-\t\tfast-export)      : export;;\n-\t\tfsck-objects)     : plumbing;;\n-\t\tfetch-pack)       : plumbing;;\n-\t\tfmt-merge-msg)    : plumbing;;\n-\t\tfor-each-ref)     : plumbing;;\n-\t\thash-object)      : plumbing;;\n-\t\thttp-*)           : transport;;\n-\t\tindex-pack)       : plumbing;;\n-\t\tinit-db)          : deprecated;;\n-\t\tlocal-fetch)      : plumbing;;\n-\t\tlost-found)       : infrequent;;\n-\t\tls-files)         : plumbing;;\n-\t\tls-remote)        : plumbing;;\n-\t\tls-tree)          : plumbing;;\n-\t\tmailinfo)         : plumbing;;\n-\t\tmailsplit)        : plumbing;;\n-\t\tmerge-*)          : plumbing;;\n-\t\tmktree)           : plumbing;;\n-\t\tmktag)            : plumbing;;\n-\t\tpack-objects)     : plumbing;;\n-\t\tpack-redundant)   : plumbing;;\n-\t\tpack-refs)        : plumbing;;\n-\t\tparse-remote)     : plumbing;;\n-\t\tpatch-id)         : plumbing;;\n-\t\tpeek-remote)      : plumbing;;\n-\t\tprune)            : plumbing;;\n-\t\tprune-packed)     : plumbing;;\n-\t\tquiltimport)      : import;;\n-\t\tread-tree)        : plumbing;;\n-\t\treceive-pack)     : plumbing;;\n-\t\treflog)           : plumbing;;\n-\t\trepo-config)      : deprecated;;\n-\t\trerere)           : plumbing;;\n-\t\trev-list)         : plumbing;;\n-\t\trev-parse)        : plumbing;;\n-\t\trunstatus)        : plumbing;;\n-\t\tsh-setup)         : internal;;\n-\t\tshell)            : daemon;;\n-\t\tshow-ref)         : plumbing;;\n-\t\tsend-pack)        : plumbing;;\n-\t\tshow-index)       : plumbing;;\n-\t\tssh-*)            : transport;;\n-\t\tstripspace)       : plumbing;;\n-\t\tsymbolic-ref)     : plumbing;;\n-\t\ttar-tree)         : deprecated;;\n-\t\tunpack-file)      : plumbing;;\n-\t\tunpack-objects)   : plumbing;;\n-\t\tupdate-index)     : plumbing;;\n-\t\tupdate-ref)       : plumbing;;\n-\t\tupdate-server-info) : daemon;;\n-\t\tupload-archive)   : plumbing;;\n-\t\tupload-pack)      : plumbing;;\n-\t\twrite-tree)       : plumbing;;\n-\t\tvar)              : infrequent;;\n-\t\tverify-pack)      : infrequent;;\n-\t\tverify-tag)       : plumbing;;\n-\t\t*) echo $i;;\n-\t\tesac\n-\tdone\n-}\n-__git_porcelain_commandlist=\n-__git_porcelain_commandlist=\"$(__git_porcelain_commands 2>/dev/null)\"\n-\n __git_aliases ()\n {\n \tlocal i IFS=$'\\n'\n@@ -1077,7 +960,7 @@ _git_help ()\n \t\treturn\n \t\t;;\n \tesac\n-\t__gitcomp \"$(__git_all_commands)\n+\t__gitcomp \"$__git_all_commandlist\n \t\tattributes cli core-tutorial cvs-migration\n \t\tdiffcore gitk glossary hooks ignore modules\n \t\trepository-layout tutorial tutorial-2\n@@ -1423,7 +1306,7 @@ _git_config ()\n \t\treturn\n \t\t;;\n \tpull.twohead|pull.octopus)\n-\t\t__gitcomp \"$(__git_merge_strategies)\"\n+\t\t__gitcomp \"$__git_merge_strategylist\"\n \t\treturn\n \t\t;;\n \tcolor.branch|color.diff|color.interactive|\\\n@@ -1524,7 +1407,7 @@ _git_config ()\n \tpager.*)\n \t\tlocal pfx=\"${cur%.*}.\"\n \t\tcur=\"${cur#*.}\"\n-\t\t__gitcomp \"$(__git_all_commands)\" \"$pfx\" \"$cur\"\n+\t\t__gitcomp \"$__git_all_commandlist\" \"$pfx\" \"$cur\"\n \t\treturn\n \t\t;;\n \tremote.*.*)\n@@ -2116,7 +1999,7 @@ _git ()\n \t\t\t--help\n \t\t\t\"\n \t\t\t;;\n-\t\t*)     __gitcomp \"$(__git_porcelain_commands) $(__git_aliases)\" ;;\n+\t\t*)     __gitcomp \"$__git_porcelain_commandlist $(__git_aliases)\" ;;\n \t\tesac\n \t\treturn\n \tfi\n-- \n1.6.5.rc2.18.g84f98.dirty\n"},{"id":"124509","messageId":"20091009161443.GX9261@spearce.org","threadId":"21132","inReplyTo":"20091009160856.GA26833@tugrik.mns.mnsspb.ru","subject":"Re: [PATCH] Speedup bash completion loading","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-10-09T16:14:43Z","receivedAt":"2009-10-09T16:14:43Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Kirill Smelkov <kirr@mns.spb.ru> wrote:\n> Now I see, OK. Here is the patch which should be applied on top of\n> Stephen's 1/2:\n> \n> ---- 8< ----\n> From: Kirill Smelkov <kirr@mns.spb.ru>\n> Date: Mon, 5 Oct 2009 13:36:15 +0400\n> Subject: [PATCH v4] Speedup bash completion loading\n\nAcked-by: Shawn O. Pearce <spearce@spearce.org>\n \n>  contrib/completion/.gitignore                      |    1 +\n>  contrib/completion/Makefile                        |   11 ++\n>  contrib/completion/git-completion.bash.generate    |  128 ++++++++++++++++\n>  ...{git-completion.bash => git-completion.bash.in} |  161 +++-----------------\n>  4 files changed, 162 insertions(+), 139 deletions(-)\n>  create mode 100644 contrib/completion/.gitignore\n>  create mode 100644 contrib/completion/Makefile\n>  create mode 100755 contrib/completion/git-completion.bash.generate\n>  rename contrib/completion/{git-completion.bash => git-completion.bash.in} (90%)\n>  mode change 100755 => 100644\n\n-- \nShawn.\n"},{"id":"124554","messageId":"7vd44wdq0n.fsf@alter.siamese.dyndns.org","threadId":"21132","inReplyTo":"20091009161443.GX9261@spearce.org","subject":"Re: [PATCH] Speedup bash completion loading","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-10-10T00:57:44Z","receivedAt":"2009-10-10T00:57:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thanks for this, and all the other acks and patches.\n"}]}