{"thread":{"id":"30479","subject":"[PATCH 00/19] Bash prompt speedup","startedAt":"2012-05-09T00:44:31Z","lastAt":"2012-05-10T06:09:08Z","messageCount":50,"participants":["SZEDER Gábor","Johannes Sixt","Junio C Hamano","Andrew Sayers"],"isPatch":true,"patchVersion":1,"patchTotal":19},"messages":[{"id":"191159","messageId":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":null,"subject":"[PATCH 00/19] Bash prompt speedup","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:31Z","receivedAt":"2012-05-09T00:44:31Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Hi,\n\nIt was pointed out about a year ago that displaying the git-specific bash\nprompt on Windows/MinGW takes quite long, long enough to be noticeable.\nAnd indeed, while in a subdirectory of a repository and stash indicator\nenabled and my laptop running from battery I get this:\n\n  $ time prompt=$(__git_ps1)\n\n  real    0m0.412s\n  user    0m0.048s\n  sys     0m0.210s\n\nThis is mainly caused by the numerous fork()s and exec()s to create\nsubshells and run git commands, which are rather expensive on Windows.\n\nThis patch series eliminates many command substitutions and git commands\nfrom __git_ps1() by reorganizing code or replacing them with bash\nbuiltins.  This speeds up the prompt immensely: now I get the same prompt\nas above in about 10ms(!).  Timing results are shown in the log message of\npatch 19.\n\nUnfortunately, to achive this users have to change their configuration, in\nparticular change their $PS1 and $PROMPT_COMMAND (see patch 19) and should\nenable the discovery of git repositories across filesystem boundaries (see\npatch 10).\n\nThere are two RFC patches in there (9 and 18), please have a look.\n\n\nHere's an outline of the series:\n\nFirst, a couple of tests for the bash prompt, to lessen the chance that I\nbreak something ;)  These are basically the same patches that I sent out a\nwhile ago in [1], the only noteworthy change is that I renamed the helper\nlibrary to lib-bash.sh (from lib-completion.sh), because all it does is to\nrun tests under bash and there is nothing completion-specific in there.\n\n[1]: http://thread.gmane.org/gmane.comp.version-control.git/195587/focus=195711\n\n  [PATCH 01/19] tests: move code to run tests under bash into a helper library\n  [PATCH 02/19] tests: add tests for the bash prompt functions in the completion script\n\nThe next four patches contain a couple of fixes and cleanups:\n\n  [PATCH 03/19] completion: use __gitdir() in _git_log()\n  [PATCH 04/19] completion: respect $GIT_DIR\n  [PATCH 05/19] bash prompt: don't show the prompt when .git/HEAD is unreadable\n  [PATCH 06/19] bash prompt: return early from __git_ps1() when not in a git repository\n\nThese four make __gitdir() faster, so they'll benefit not only the\nbash prompt but completing refs, aliases, config variables, etc., too.\n\n  [PATCH 07/19] completion: make __gitdir() store repository path in $__git_dir\n  [PATCH 08/19] completion: use $__git_dir instead of $(__gitdir)\n  [RFC PATCH 09/19] completion: platform-specific helper function to get physical path\n  [PATCH 10/19] completion: use bash builtins to search for repository\n\nThese three make the main codepath in __git_ps1() faster by eliminating a\ncouple of command substitutions and git commands.\n\n  [PATCH 11/19] bash prompt: use bash builtins to find out current branch\n  [PATCH 12/19] bash prompt: use bash builtins to check whether inside git dir\n  [PATCH 13/19] bash prompt: check whether inside the worktree only when necessary\n\nEliminate some more command substitutions and git commands that are not\nnecessarily run for every prompt:\n\n  [PATCH 14/19] bash prompt: use bash builtins to find out current branch during rebase\n  [PATCH 15/19] bash prompt: use bash builtins to get detached HEAD abbrev. object name\n  [PATCH 16/19] bash prompt: display stash and upstream state even inside the repository\n  [PATCH 17/19] bash prompt: use bash builtins to check stash state\n  [RFC PATCH 18/19] bash prompt: avoid command substitution when checking for untracked files\n\nAnd finally get rid of the command substitution used to include the git\nprompt in $PS1:\n\n  [PATCH 19/19] bash prompt: alternative git prompt without command substitution\n\nEnjoy.\n\n\nBest,\nGábor\n\n\nSZEDER Gábor (19):\n  tests: move code to run tests under bash into a helper library\n  tests: add tests for the bash prompt functions in the completion\n    script\n  completion: use __gitdir() in _git_log()\n  completion: respect $GIT_DIR\n  bash prompt: don't show the prompt when .git/HEAD is unreadable\n  bash prompt: return early from __git_ps1() when not in a git\n    repository\n  completion: make __gitdir() store repository path in $__git_dir\n  completion: use $__git_dir instead of $(__gitdir)\n  completion: platform-specific helper function to get physical path\n  completion: use bash builtins to search for repository\n  bash prompt: use bash builtins to find out current branch\n  bash prompt: use bash builtins to check whether inside git dir\n  bash prompt: check whether inside the worktree only when necessary\n  bash prompt: use bash builtins to find out current branch during\n    rebase\n  bash prompt: use bash builtins to get detached HEAD abbrev. object\n    name\n  bash prompt: display stash and upstream state even inside the\n    repository\n  bash prompt: use bash builtins to check stash state\n  bash prompt: avoid command substitution when checking for untracked\n    files\n  bash prompt: alternative git prompt without command substitution\n\n contrib/completion/git-completion.bash | 315 ++++++++++-------\n t/lib-bash.sh                          |  18 +\n t/t9902-completion.sh                  |  14 +-\n t/t9903-bash-prompt.sh                 | 593 +++++++++++++++++++++++++++++++++\n 4 files changed, 815 insertions(+), 125 deletions(-)\n create mode 100644 t/lib-bash.sh\n create mode 100755 t/t9903-bash-prompt.sh\n\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191160","messageId":"1336524290-30023-2-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 01/19] tests: move code to run tests under bash into a helper library","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:32Z","receivedAt":"2012-05-09T00:44:32Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"The following patch will add tests for the bash prompt functions as a\nnew test script, which also has to be run under bash.\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n t/lib-bash.sh         | 18 ++++++++++++++++++\n t/t9902-completion.sh | 14 +-------------\n 2 files changed, 19 insertions(+), 13 deletions(-)\n create mode 100755 t/lib-bash.sh\n\ndiff --git a/t/lib-bash.sh b/t/lib-bash.sh\nnew file mode 100644\nindex 00000000..11397f74\n--- /dev/null\n+++ b/t/lib-bash.sh\n@@ -0,0 +1,18 @@\n+#!/bin/sh\n+#\n+# Ensures that tests are run under Bash; primarily intended for running tests\n+# of the completion script.\n+\n+if test -n \"$BASH\" && test -z \"$POSIXLY_CORRECT\"; then\n+\t# we are in full-on bash mode\n+\ttrue\n+elif type bash >/dev/null 2>&1; then\n+\t# execute in full-on bash mode\n+\tunset POSIXLY_CORRECT\n+\texec bash \"$0\" \"$@\"\n+else\n+\techo '1..0 #SKIP skipping bash completion tests; bash not available'\n+\texit 0\n+fi\n+\n+. ./test-lib.sh\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 5bda6b6e..a0ea9463 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -3,21 +3,9 @@\n # Copyright (c) 2012 Felipe Contreras\n #\n \n-if test -n \"$BASH\" && test -z \"$POSIXLY_CORRECT\"; then\n-\t# we are in full-on bash mode\n-\ttrue\n-elif type bash >/dev/null 2>&1; then\n-\t# execute in full-on bash mode\n-\tunset POSIXLY_CORRECT\n-\texec bash \"$0\" \"$@\"\n-else\n-\techo '1..0 #SKIP skipping bash completion tests; bash not available'\n-\texit 0\n-fi\n-\n test_description='test bash completion'\n \n-. ./test-lib.sh\n+. ./lib-bash.sh\n \n complete ()\n {\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191162","messageId":"1336524290-30023-3-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 02/19] tests: add tests for the bash prompt functions in the completion script","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:33Z","receivedAt":"2012-05-09T00:44:33Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"The tests cover the discovery of the '.git' directory in the\n__gitdir() function in different scenarios, and the prompt itself,\ni.e. branch name, detached heads, operations (rebase, merge,\ncherry-pick, bisect), and status indicators (dirty, stash, untracked\nfiles; but not the upstream status).\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n t/t9903-bash-prompt.sh | 448 +++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 448 insertions(+)\n create mode 100755 t/t9903-bash-prompt.sh\n\ndiff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh\nnew file mode 100755\nindex 00000000..a6c9ce94\n--- /dev/null\n+++ b/t/t9903-bash-prompt.sh\n@@ -0,0 +1,448 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2012 SZEDER Gábor\n+#\n+\n+test_description='test git-specific bash prompt functions'\n+\n+. ./lib-bash.sh\n+\n+. \"$GIT_BUILD_DIR/contrib/completion/git-completion.bash\"\n+\n+actual=\"$TRASH_DIRECTORY/actual\"\n+\n+test_expect_success 'setup for prompt tests' '\n+\tmkdir -p subdir/subsubdir &&\n+\tgit init otherrepo &&\n+\techo 1 > file &&\n+\tgit add file &&\n+\ttest_tick &&\n+\tgit commit -m initial &&\n+\tgit tag -a -m msg1 t1 &&\n+\tgit checkout -b b1 &&\n+\techo 2 > file &&\n+\tgit commit -m \"second b1\" file &&\n+\techo 3 > file &&\n+\tgit commit -m \"third b1\" file &&\n+\tgit tag -a -m msg2 t2 &&\n+\tgit checkout -b b2 master &&\n+\techo 0 > file &&\n+\tgit commit -m \"second b2\" file &&\n+\tgit checkout master\n+'\n+\n+test_expect_success 'gitdir - from command line (through $__git_dir)' '\n+\techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n+\t(\n+\t\t__git_dir=\"$TRASH_DIRECTORY/otherrepo/.git\" &&\n+\t\t__gitdir > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'gitdir - repo as argument' '\n+\techo \"otherrepo/.git\" > expected &&\n+\t__gitdir \"otherrepo\" > \"$actual\" &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'gitdir - remote as argument' '\n+\techo \"remote\" > expected &&\n+\t__gitdir \"remote\" > \"$actual\" &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'gitdir - .git directory in cwd' '\n+\techo \".git\" > expected &&\n+\t__gitdir > \"$actual\" &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'gitdir - .git directory in parent' '\n+\techo \"$TRASH_DIRECTORY/.git\" > expected &&\n+\t(\n+\t\tcd subdir/subsubdir &&\n+\t\t__gitdir > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'gitdir - cwd is a .git directory' '\n+\techo \".\" > expected &&\n+\t(\n+\t\tcd .git &&\n+\t\t__gitdir > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'gitdir - parent is a .git directory' '\n+\techo \"$TRASH_DIRECTORY/.git\" > expected &&\n+\t(\n+\t\tcd .git/refs/heads &&\n+\t\t__gitdir > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_failure 'gitdir - $GIT_DIR set while .git directory in cwd' '\n+\techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n+\t(\n+\t\tGIT_DIR=\"$TRASH_DIRECTORY/otherrepo/.git\" &&\n+\t\texport GIT_DIR &&\n+\t\t__gitdir > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'gitdir - $GIT_DIR set while .git directory in parent' '\n+\techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n+\t(\n+\t\tGIT_DIR=\"$TRASH_DIRECTORY/otherrepo/.git\" &&\n+\t\texport GIT_DIR &&\n+\t\tcd subdir &&\n+\t\t__gitdir > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'gitdir - gitfile in cwd' '\n+\techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n+\techo \"gitdir: $TRASH_DIRECTORY/otherrepo/.git\" > subdir/.git &&\n+\ttest_when_finished \"rm -f subdir/.git\" &&\n+\t(\n+\t\tcd subdir &&\n+\t\t__gitdir > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'gitdir - gitfile in parent' '\n+\techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n+\techo \"gitdir: $TRASH_DIRECTORY/otherrepo/.git\" > subdir/.git &&\n+\ttest_when_finished \"rm -f subdir/.git\" &&\n+\t(\n+\t\tcd subdir/subsubdir &&\n+\t\t__gitdir > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success SYMLINKS 'gitdir - resulting path avoids symlinks' '\n+\techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n+\tmkdir otherrepo/dir &&\n+\ttest_when_finished \"rm -rf otherrepo/dir\" &&\n+\tln -s otherrepo/dir link &&\n+\ttest_when_finished \"rm -f link\" &&\n+\t(\n+\t\tcd link &&\n+\t\t__gitdir > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'gitdir - not a git repository' '\n+\t(\n+\t\tcd subdir/subsubdir &&\n+\t\tGIT_CEILING_DIRECTORIES=\"$TRASH_DIRECTORY\" &&\n+\t\texport GIT_CEILING_DIRECTORIES &&\n+\t\ttest_must_fail __gitdir\n+\t)\n+'\n+\n+test_expect_success 'prompt - branch name' '\n+\tprintf \" (master)\" > expected &&\n+\t__git_ps1 > \"$actual\" &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - detached head' '\n+\tprintf \" ((%s...))\" $(git log -1 --format=\"%h\" b1^) > expected &&\n+\tgit checkout b1^ &&\n+\ttest_when_finished \"git checkout master\" &&\n+\t__git_ps1 > \"$actual\" &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - describe detached head - contains' '\n+\tprintf \" ((t2~1))\" > expected &&\n+\tgit checkout b1^ &&\n+\ttest_when_finished \"git checkout master\" &&\n+\t(\n+\t\tGIT_PS1_DESCRIBE_STYLE=contains &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - describe detached head - branch' '\n+\tprintf \" ((b1~1))\" > expected &&\n+\tgit checkout b1^ &&\n+\ttest_when_finished \"git checkout master\" &&\n+\t(\n+\t\tGIT_PS1_DESCRIBE_STYLE=branch &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - describe detached head - describe' '\n+\tprintf \" ((t1-1-g%s))\" $(git log -1 --format=\"%h\" b1^) > expected &&\n+\tgit checkout b1^ &&\n+\ttest_when_finished \"git checkout master\" &&\n+\t(\n+\t\tGIT_PS1_DESCRIBE_STYLE=describe &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - describe detached head - default' '\n+\tprintf \" ((t2))\" > expected &&\n+\tgit checkout --detach b1 &&\n+\ttest_when_finished \"git checkout master\" &&\n+\t__git_ps1 > \"$actual\" &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - inside .git directory' '\n+\tprintf \" (GIT_DIR!)\" > expected &&\n+\t(\n+\t\tcd .git &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - deep inside .git directory' '\n+\tprintf \" (GIT_DIR!)\" > expected &&\n+\t(\n+\t\tcd .git/refs/heads &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - inside bare repository' '\n+\tprintf \" (BARE:master)\" > expected &&\n+\tgit init --bare bare.git &&\n+\ttest_when_finished \"rm -rf bare.git\" &&\n+\t(\n+\t\tcd bare.git &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - interactive rebase' '\n+\tprintf \" (b1|REBASE-i)\" > expected\n+\techo \"#!$SHELL_PATH\" >fake_editor.sh &&\n+\tcat >>fake_editor.sh <<\\EOF &&\n+echo \"edit $(git log -1 --format=\"%h\")\" > \"$1\"\n+EOF\n+\ttest_when_finished \"rm -f fake_editor.sh\" &&\n+\tchmod a+x fake_editor.sh &&\n+\ttest_set_editor \"$TRASH_DIRECTORY/fake_editor.sh\" &&\n+\tgit checkout b1 &&\n+\ttest_when_finished \"git checkout master\" &&\n+\tgit rebase -i HEAD^ &&\n+\ttest_when_finished \"git rebase --abort\"\n+\t__git_ps1 > \"$actual\" &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - rebase merge' '\n+\tprintf \" (b2|REBASE-m)\" > expected &&\n+\tgit checkout b2 &&\n+\ttest_when_finished \"git checkout master\" &&\n+\ttest_must_fail git rebase --merge b1 b2 &&\n+\ttest_when_finished \"git rebase --abort\" &&\n+\t__git_ps1 > \"$actual\" &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - rebase' '\n+\tprintf \" ((t2)|REBASE)\" > expected &&\n+\tgit checkout b2 &&\n+\ttest_when_finished \"git checkout master\" &&\n+\ttest_must_fail git rebase b1 b2 &&\n+\ttest_when_finished \"git rebase --abort\" &&\n+\t__git_ps1 > \"$actual\" &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - merge' '\n+\tprintf \" (b1|MERGING)\" > expected &&\n+\tgit checkout b1 &&\n+\ttest_when_finished \"git checkout master\" &&\n+\ttest_must_fail git merge b2 &&\n+\ttest_when_finished \"git reset --hard\" &&\n+\t__git_ps1 > \"$actual\" &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - cherry-pick' '\n+\tprintf \" (master|CHERRY-PICKING)\" > expected &&\n+\ttest_must_fail git cherry-pick b1 &&\n+\ttest_when_finished \"git reset --hard\" &&\n+\t__git_ps1 > \"$actual\" &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - bisect' '\n+\tprintf \" (master|BISECTING)\" > expected &&\n+\tgit bisect start &&\n+\ttest_when_finished \"git bisect reset\" &&\n+\t__git_ps1 > \"$actual\" &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - dirty status indicator - clean' '\n+\tprintf \" (master)\" > expected &&\n+\t(\n+\t\tGIT_PS1_SHOWDIRTYSTATE=y &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - dirty status indicator - dirty worktree' '\n+\tprintf \" (master *)\" > expected &&\n+\techo \"dirty\" > file &&\n+\ttest_when_finished \"git reset --hard\" &&\n+\t(\n+\t\tGIT_PS1_SHOWDIRTYSTATE=y &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - dirty status indicator - dirty index' '\n+\tprintf \" (master +)\" > expected &&\n+\techo \"dirty\" > file &&\n+\ttest_when_finished \"git reset --hard\" &&\n+\tgit add -u &&\n+\t(\n+\t\tGIT_PS1_SHOWDIRTYSTATE=y &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - dirty status indicator - dirty index and worktree' '\n+\tprintf \" (master *+)\" > expected &&\n+\techo \"dirty index\" > file &&\n+\ttest_when_finished \"git reset --hard\" &&\n+\tgit add -u &&\n+\techo \"dirty worktree\" > file &&\n+\t(\n+\t\tGIT_PS1_SHOWDIRTYSTATE=y &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - dirty status indicator - before root commit' '\n+\tprintf \" (master #)\" > expected &&\n+\t(\n+\t\tGIT_PS1_SHOWDIRTYSTATE=y &&\n+\t\tcd otherrepo &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - dirty status indicator - disabled by config' '\n+\tprintf \" (master)\" > expected &&\n+\techo \"dirty\" > file &&\n+\ttest_when_finished \"git reset --hard\" &&\n+\ttest_config bash.showDirtyState false &&\n+\t(\n+\t\tGIT_PS1_SHOWDIRTYSTATE=y &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - dirty status indicator - not shown inside .git directory' '\n+\tprintf \" (GIT_DIR!)\" > expected &&\n+\techo \"dirty\" > file &&\n+\ttest_when_finished \"git reset --hard\" &&\n+\t(\n+\t\tGIT_PS1_SHOWDIRTYSTATE=y &&\n+\t\tcd .git &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - stash status indicator - no stash' '\n+\tprintf \" (master)\" > expected &&\n+\t(\n+\t\tGIT_PS1_SHOWSTASHSTATE=y &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - stash status indicator - stash' '\n+\tprintf \" (master $)\" > expected &&\n+\techo 2 >file &&\n+\tgit stash &&\n+\ttest_when_finished \"git stash drop\" &&\n+\t(\n+\t\tGIT_PS1_SHOWSTASHSTATE=y &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - stash status indicator - not shown inside .git directory' '\n+\tprintf \" (GIT_DIR!)\" > expected &&\n+\techo 2 >file &&\n+\tgit stash &&\n+\ttest_when_finished \"git stash drop\" &&\n+\t(\n+\t\tGIT_PS1_SHOWSTASHSTATE=y &&\n+\t\tcd .git &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - untracked files status indicator - no untracked files' '\n+\tprintf \" (master)\" > expected &&\n+\t(\n+\t\tGIT_PS1_SHOWUNTRACKEDFILES=y &&\n+\t\tcd otherrepo &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - untracked files status indicator - untracked files' '\n+\tprintf \" (master %%)\" > expected &&\n+\t(\n+\t\tGIT_PS1_SHOWUNTRACKEDFILES=y &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - untracked files status indicator - not shown inside .git directory' '\n+\tprintf \" (GIT_DIR!)\" > expected &&\n+\t(\n+\t\tGIT_PS1_SHOWUNTRACKEDFILES=y &&\n+\t\tcd .git &&\n+\t\t__git_ps1 > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - format string starting with dash' '\n+\tprintf -- \"-master\" > expected &&\n+\t__git_ps1 \"-%s\" > \"$actual\" &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_done\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191161","messageId":"1336524290-30023-4-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 03/19] completion: use __gitdir() in _git_log()","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:34Z","receivedAt":"2012-05-09T00:44:34Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"The standard way to find out the path to the repository in the\ncompletion script is the __gitdir() helper function, because that\nhandles the repository path given on the command line (i.e. git\n--git-dir=/path/to/repo log --<TAB>).  However, there is one\nexception: the completion function for 'git log' still uses 'git\nrev-parse --git-dir' directly, and could offer (or not) the '--merge'\noption erroneously when the repository is specified on the command\nline.\n\nUse __gitdir() there, too.\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n contrib/completion/git-completion.bash | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 9f56ec7a..f17abccb 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1551,7 +1551,7 @@ _git_log ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal g=\"$(git rev-parse --git-dir 2>/dev/null)\"\n+\tlocal g=\"$(__gitdir)\"\n \tlocal merge=\"\"\n \tif [ -f \"$g/MERGE_HEAD\" ]; then\n \t\tmerge=\"--merge\"\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191163","messageId":"1336524290-30023-5-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 04/19] completion: respect $GIT_DIR","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:35Z","receivedAt":"2012-05-09T00:44:35Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"The __gitdir() helper function finds out the path of the git\nrepository by running 'git rev-parse --git-dir'.  However, it has a\nshortcut first to avoid the overhead of running a git command in a\nsubshell when the current directory is at the top of the work tree,\ni.e. when it contains a '.git' subdirectory.\n\nIf the 'GIT_DIR' environment variable is set then it specifies the\npath to the git repository, and the autodetection of the '.git'\ndirectory is not necessary.  However, $GIT_DIR is only taken into\nacocunt by 'git rev-parse --git-dir', and the check for the '.git'\nsubdirectory is performed first, so it wins over the path given in\n$GIT_DIR.\n\nThere are several completion (helper) functions that depend on\n__gitdir(), and when the above case triggers the completion script\nwill do weird things, like offering refs, aliases, or stashes from a\ndifferent repository, or displaying wrong or broken prompt, etc.\n\nSo check first whether $GIT_DIR is set, and only proceed with checking\nthe '.git' directory in the current directory if it isn't.  'git\nrev-parse' would also check whether the path in $GIT_DIR is a proper\n'.git' directory, i.e. 'HEAD', 'refs/', and 'objects/' are present and\naccessible, but we don't have to be that thorough for the bash prompt.\nAnd we've lived with an equally permissive check for '.git' in the\ncurrent working directory for years anyway.\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n contrib/completion/git-completion.bash |  3 +++\n t/t9903-bash-prompt.sh                 | 10 +++++++++-\n 2 files changed, 12 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex f17abccb..ab26bdc8 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -77,6 +77,9 @@ __gitdir ()\n \tif [ -z \"${1-}\" ]; then\n \t\tif [ -n \"${__git_dir-}\" ]; then\n \t\t\techo \"$__git_dir\"\n+\t\telif [ -n \"${GIT_DIR-}\" ]; then\n+\t\t\ttest -d \"${GIT_DIR-}\" || return 1\n+\t\t\techo \"$GIT_DIR\"\n \t\telif [ -d .git ]; then\n \t\t\techo .git\n \t\telse\ndiff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh\nindex a6c9ce94..96468ceb 100755\n--- a/t/t9903-bash-prompt.sh\n+++ b/t/t9903-bash-prompt.sh\n@@ -85,7 +85,7 @@ test_expect_success 'gitdir - parent is a .git directory' '\n \ttest_cmp expected \"$actual\"\n '\n \n-test_expect_failure 'gitdir - $GIT_DIR set while .git directory in cwd' '\n+test_expect_success 'gitdir - $GIT_DIR set while .git directory in cwd' '\n \techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n \t(\n \t\tGIT_DIR=\"$TRASH_DIRECTORY/otherrepo/.git\" &&\n@@ -106,6 +106,14 @@ test_expect_success 'gitdir - $GIT_DIR set while .git directory in parent' '\n \ttest_cmp expected \"$actual\"\n '\n \n+test_expect_success 'gitdir - non-existing $GIT_DIR' '\n+\t(\n+\t\tGIT_DIR=\"$TRASH_DIRECTORY/non-existing\" &&\n+\t\texport GIT_DIR &&\n+\t\ttest_must_fail __gitdir\n+\t)\n+'\n+\n test_expect_success 'gitdir - gitfile in cwd' '\n \techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n \techo \"gitdir: $TRASH_DIRECTORY/otherrepo/.git\" > subdir/.git &&\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191164","messageId":"1336524290-30023-6-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 05/19] bash prompt: don't show the prompt when .git/HEAD is unreadable","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:36Z","receivedAt":"2012-05-09T00:44:36Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"__git_ps1() has a chain of commands to figure out what to display in\nthe prompt as current branch, i.e. the branch name, or a described\ndetached head, or the 7 hexdigits abbreviated object name, or\n\"(unknown)\" when all of the above fails.\n\nNow, when the 7 hexdigits case fails, then '/path/to/.git/HEAD' can't\nbe read.  This can happen when the file became unreadable after\n__gitdir() found it: unlikely, but a parallel process can racily\ndelete it or change it's permissions in that short timeframe.\nAlternatively, it is possible that either the subshell or the 'cut'\ncommand fail.  Either way, when HEAD is not readable, then the path is\nnot considered to be a git repository, therefore the bash prompt\nshouldn't be displayed at all.  And there is no point in continuing\nthe execution of __git_ps1(), because its subsequent git commands will\nerror out anyway.\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n contrib/completion/git-completion.bash | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex ab26bdc8..cd6a5f12 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -258,7 +258,7 @@ __git_ps1 ()\n \t\t\t\tesac 2>/dev/null)\" ||\n \n \t\t\t\tb=\"$(cut -c1-7 \"$g/HEAD\" 2>/dev/null)...\" ||\n-\t\t\t\tb=\"unknown\"\n+\t\t\t\treturn\n \t\t\t\tb=\"($b)\"\n \t\t\t}\n \t\tfi\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191168","messageId":"1336524290-30023-7-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 06/19] bash prompt: return early from __git_ps1() when not in a git repository","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:37Z","receivedAt":"2012-05-09T00:44:37Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"... to gain one level of indentation for the bulk of the function.\n\n(The patch looks quite unreadable, you'd better check it with 'git\ndiff -w'.)\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n contrib/completion/git-completion.bash | 154 +++++++++++++++++----------------\n 1 file changed, 78 insertions(+), 76 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex cd6a5f12..eaa3df9d 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -217,94 +217,96 @@ __git_ps1_show_upstream ()\n __git_ps1 ()\n {\n \tlocal g=\"$(__gitdir)\"\n-\tif [ -n \"$g\" ]; then\n-\t\tlocal r=\"\"\n-\t\tlocal b=\"\"\n-\t\tif [ -f \"$g/rebase-merge/interactive\" ]; then\n-\t\t\tr=\"|REBASE-i\"\n-\t\t\tb=\"$(cat \"$g/rebase-merge/head-name\")\"\n-\t\telif [ -d \"$g/rebase-merge\" ]; then\n-\t\t\tr=\"|REBASE-m\"\n-\t\t\tb=\"$(cat \"$g/rebase-merge/head-name\")\"\n-\t\telse\n-\t\t\tif [ -d \"$g/rebase-apply\" ]; then\n-\t\t\t\tif [ -f \"$g/rebase-apply/rebasing\" ]; then\n-\t\t\t\t\tr=\"|REBASE\"\n-\t\t\t\telif [ -f \"$g/rebase-apply/applying\" ]; then\n-\t\t\t\t\tr=\"|AM\"\n-\t\t\t\telse\n-\t\t\t\t\tr=\"|AM/REBASE\"\n-\t\t\t\tfi\n-\t\t\telif [ -f \"$g/MERGE_HEAD\" ]; then\n-\t\t\t\tr=\"|MERGING\"\n-\t\t\telif [ -f \"$g/CHERRY_PICK_HEAD\" ]; then\n-\t\t\t\tr=\"|CHERRY-PICKING\"\n-\t\t\telif [ -f \"$g/BISECT_LOG\" ]; then\n-\t\t\t\tr=\"|BISECTING\"\n-\t\t\tfi\n+\tif [ -z \"$g\" ]; then\n+\t\treturn\n+\tfi\n \n-\t\t\tb=\"$(git symbolic-ref HEAD 2>/dev/null)\" || {\n-\n-\t\t\t\tb=\"$(\n-\t\t\t\tcase \"${GIT_PS1_DESCRIBE_STYLE-}\" in\n-\t\t\t\t(contains)\n-\t\t\t\t\tgit describe --contains HEAD ;;\n-\t\t\t\t(branch)\n-\t\t\t\t\tgit describe --contains --all HEAD ;;\n-\t\t\t\t(describe)\n-\t\t\t\t\tgit describe HEAD ;;\n-\t\t\t\t(* | default)\n-\t\t\t\t\tgit describe --tags --exact-match HEAD ;;\n-\t\t\t\tesac 2>/dev/null)\" ||\n-\n-\t\t\t\tb=\"$(cut -c1-7 \"$g/HEAD\" 2>/dev/null)...\" ||\n-\t\t\t\treturn\n-\t\t\t\tb=\"($b)\"\n-\t\t\t}\n+\tlocal r=\"\"\n+\tlocal b=\"\"\n+\tif [ -f \"$g/rebase-merge/interactive\" ]; then\n+\t\tr=\"|REBASE-i\"\n+\t\tb=\"$(cat \"$g/rebase-merge/head-name\")\"\n+\telif [ -d \"$g/rebase-merge\" ]; then\n+\t\tr=\"|REBASE-m\"\n+\t\tb=\"$(cat \"$g/rebase-merge/head-name\")\"\n+\telse\n+\t\tif [ -d \"$g/rebase-apply\" ]; then\n+\t\t\tif [ -f \"$g/rebase-apply/rebasing\" ]; then\n+\t\t\t\tr=\"|REBASE\"\n+\t\t\telif [ -f \"$g/rebase-apply/applying\" ]; then\n+\t\t\t\tr=\"|AM\"\n+\t\t\telse\n+\t\t\t\tr=\"|AM/REBASE\"\n+\t\t\tfi\n+\t\telif [ -f \"$g/MERGE_HEAD\" ]; then\n+\t\t\tr=\"|MERGING\"\n+\t\telif [ -f \"$g/CHERRY_PICK_HEAD\" ]; then\n+\t\t\tr=\"|CHERRY-PICKING\"\n+\t\telif [ -f \"$g/BISECT_LOG\" ]; then\n+\t\t\tr=\"|BISECTING\"\n \t\tfi\n \n-\t\tlocal w=\"\"\n-\t\tlocal i=\"\"\n-\t\tlocal s=\"\"\n-\t\tlocal u=\"\"\n-\t\tlocal c=\"\"\n-\t\tlocal p=\"\"\n+\t\tb=\"$(git symbolic-ref HEAD 2>/dev/null)\" || {\n+\n+\t\t\tb=\"$(\n+\t\t\tcase \"${GIT_PS1_DESCRIBE_STYLE-}\" in\n+\t\t\t(contains)\n+\t\t\t\tgit describe --contains HEAD ;;\n+\t\t\t(branch)\n+\t\t\t\tgit describe --contains --all HEAD ;;\n+\t\t\t(describe)\n+\t\t\t\tgit describe HEAD ;;\n+\t\t\t(* | default)\n+\t\t\t\tgit describe --tags --exact-match HEAD ;;\n+\t\t\tesac 2>/dev/null)\" ||\n+\n+\t\t\tb=\"$(cut -c1-7 \"$g/HEAD\" 2>/dev/null)...\" ||\n+\t\t\treturn\n+\t\t\tb=\"($b)\"\n+\t\t}\n+\tfi\n \n-\t\tif [ \"true\" = \"$(git rev-parse --is-inside-git-dir 2>/dev/null)\" ]; then\n-\t\t\tif [ \"true\" = \"$(git rev-parse --is-bare-repository 2>/dev/null)\" ]; then\n-\t\t\t\tc=\"BARE:\"\n-\t\t\telse\n-\t\t\t\tb=\"GIT_DIR!\"\n-\t\t\tfi\n-\t\telif [ \"true\" = \"$(git rev-parse --is-inside-work-tree 2>/dev/null)\" ]; then\n-\t\t\tif [ -n \"${GIT_PS1_SHOWDIRTYSTATE-}\" ]; then\n-\t\t\t\tif [ \"$(git config --bool bash.showDirtyState)\" != \"false\" ]; then\n-\t\t\t\t\tgit diff --no-ext-diff --quiet --exit-code || w=\"*\"\n-\t\t\t\t\tif git rev-parse --quiet --verify HEAD >/dev/null; then\n-\t\t\t\t\t\tgit diff-index --cached --quiet HEAD -- || i=\"+\"\n-\t\t\t\t\telse\n-\t\t\t\t\t\ti=\"#\"\n-\t\t\t\t\tfi\n-\t\t\t\tfi\n-\t\t\tfi\n-\t\t\tif [ -n \"${GIT_PS1_SHOWSTASHSTATE-}\" ]; then\n-\t\t\t\tgit rev-parse --verify refs/stash >/dev/null 2>&1 && s=\"$\"\n-\t\t\tfi\n+\tlocal w=\"\"\n+\tlocal i=\"\"\n+\tlocal s=\"\"\n+\tlocal u=\"\"\n+\tlocal c=\"\"\n+\tlocal p=\"\"\n \n-\t\t\tif [ -n \"${GIT_PS1_SHOWUNTRACKEDFILES-}\" ]; then\n-\t\t\t\tif [ -n \"$(git ls-files --others --exclude-standard)\" ]; then\n-\t\t\t\t\tu=\"%\"\n+\tif [ \"true\" = \"$(git rev-parse --is-inside-git-dir 2>/dev/null)\" ]; then\n+\t\tif [ \"true\" = \"$(git rev-parse --is-bare-repository 2>/dev/null)\" ]; then\n+\t\t\tc=\"BARE:\"\n+\t\telse\n+\t\t\tb=\"GIT_DIR!\"\n+\t\tfi\n+\telif [ \"true\" = \"$(git rev-parse --is-inside-work-tree 2>/dev/null)\" ]; then\n+\t\tif [ -n \"${GIT_PS1_SHOWDIRTYSTATE-}\" ]; then\n+\t\t\tif [ \"$(git config --bool bash.showDirtyState)\" != \"false\" ]; then\n+\t\t\t\tgit diff --no-ext-diff --quiet --exit-code || w=\"*\"\n+\t\t\t\tif git rev-parse --quiet --verify HEAD >/dev/null; then\n+\t\t\t\t\tgit diff-index --cached --quiet HEAD -- || i=\"+\"\n+\t\t\t\telse\n+\t\t\t\t\ti=\"#\"\n \t\t\t\tfi\n \t\t\tfi\n+\t\tfi\n+\t\tif [ -n \"${GIT_PS1_SHOWSTASHSTATE-}\" ]; then\n+\t\t\tgit rev-parse --verify refs/stash >/dev/null 2>&1 && s=\"$\"\n+\t\tfi\n \n-\t\t\tif [ -n \"${GIT_PS1_SHOWUPSTREAM-}\" ]; then\n-\t\t\t\t__git_ps1_show_upstream\n+\t\tif [ -n \"${GIT_PS1_SHOWUNTRACKEDFILES-}\" ]; then\n+\t\t\tif [ -n \"$(git ls-files --others --exclude-standard)\" ]; then\n+\t\t\t\tu=\"%\"\n \t\t\tfi\n \t\tfi\n \n-\t\tlocal f=\"$w$i$s$u\"\n-\t\tprintf -- \"${1:- (%s)}\" \"$c${b##refs/heads/}${f:+ $f}$r$p\"\n+\t\tif [ -n \"${GIT_PS1_SHOWUPSTREAM-}\" ]; then\n+\t\t\t__git_ps1_show_upstream\n+\t\tfi\n \tfi\n+\n+\tlocal f=\"$w$i$s$u\"\n+\tprintf -- \"${1:- (%s)}\" \"$c${b##refs/heads/}${f:+ $f}$r$p\"\n }\n \n __gitcomp_1 ()\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191165","messageId":"1336524290-30023-8-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 07/19] completion: make __gitdir() store repository path in $__git_dir","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:38Z","receivedAt":"2012-05-09T00:44:38Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"The __gitdir() helper function is responsible for finding out the path\nto the repository, and it's invoked from several completion (helper)\nfunctions and from __git_ps1().  The path of the repository is printed\nto stdout, therefore it's invoked in a command substitution.  This has\nthe following drawbacks:\n\n  1. The command substitution involves the forking of a subshell,\n     which has a considerable overhead.\n\n  2. There are a few cases, where __gitdir() is called more than once\n     during a single completion, which means multiple command\n     substitutions and eventual multiple 'git rev-parse --git-dir'\n     executions.  For example, __gitdir() is invoked twice during the\n     completion of options for 'gitk', 'git log', 'git rebase', but\n     for certain aliases it might be invoked three times.\n\nNow, _git(), the top-level git completion function declares the local\n$__git_dir variable for storing the repository path given as parameter\nto the '--git-dir=' option.  Since $__git_dir is declared at the\ntop-level, it is already available in all completion functions, but\nit's only used in __gitdir() (if set then there's no need to\nautodetect the path to the repository).  This means that we can use\n$__git_dir to always store the path to the repository found by\n__gitdir().\n\nThis way we can address both of the above drawbacks.  We won't need\nthe command substitution when invoking __gitdir(), because won't need\n__gitdir()'s output anymore: the path to the repository will be\navailable in $__git_dir.  Furthermore, onlyt the first __gitdir()\ninvocation will perform the search for the repository, and all\nsubsequent calls will see the path already stored in $__git_dir by the\nfirst call.\n\nSo change __gitdir() to store the path to the repository in\n$__git_dir.  However, still print the found path, because there might\nbe user-supplied completion functions relying on it.\n\nAlso declare $__git_dir as local in __git_ps1() and _gitk() to prevent\nthe variable from leaking into the environment when they call\n__gitdir() (that would break completion and bash prompt when the user\nmoves to a different git repository).\n\nFinally, extend the __gitdir() tests to check the value of $__git_dir,\ntoo.\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n contrib/completion/git-completion.bash | 20 ++++----\n t/t9903-bash-prompt.sh                 | 85 +++++++++++++++++++++++-----------\n 2 files changed, 71 insertions(+), 34 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex eaa3df9d..85b933f2 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -71,25 +71,27 @@ case \"$COMP_WORDBREAKS\" in\n esac\n \n # __gitdir accepts 0 or 1 arguments (i.e., location)\n-# returns location of .git repo\n+# Prints the path to the .git directory, and stores it in $__git_dir as well.\n __gitdir ()\n {\n \tif [ -z \"${1-}\" ]; then\n \t\tif [ -n \"${__git_dir-}\" ]; then\n-\t\t\techo \"$__git_dir\"\n+\t\t\t:\n \t\telif [ -n \"${GIT_DIR-}\" ]; then\n \t\t\ttest -d \"${GIT_DIR-}\" || return 1\n-\t\t\techo \"$GIT_DIR\"\n+\t\t\t__git_dir=\"$GIT_DIR\"\n \t\telif [ -d .git ]; then\n-\t\t\techo .git\n+\t\t\t__git_dir=.git\n \t\telse\n-\t\t\tgit rev-parse --git-dir 2>/dev/null\n+\t\t\t__git_dir=\"$(git rev-parse --git-dir 2>/dev/null)\" || return 1\n \t\tfi\n \telif [ -d \"$1/.git\" ]; then\n-\t\techo \"$1/.git\"\n+\t\t__git_dir=\"$1/.git\"\n \telse\n-\t\techo \"$1\"\n+\t\t__git_dir=\"$1\"\n \tfi\n+\n+\techo \"$__git_dir\"\n }\n \n # stores the divergence from upstream in $p\n@@ -216,6 +218,7 @@ __git_ps1_show_upstream ()\n # returns text to add to bash PS1 prompt (includes branch name)\n __git_ps1 ()\n {\n+\tlocal __git_dir=\"\"\n \tlocal g=\"$(__gitdir)\"\n \tif [ -z \"$g\" ]; then\n \t\treturn\n@@ -2606,7 +2609,7 @@ _git_whatchanged ()\n \n _git ()\n {\n-\tlocal i c=1 command __git_dir\n+\tlocal i c=1 command __git_dir=\"\"\n \n \tif [[ -n ${ZSH_VERSION-} ]]; then\n \t\temulate -L bash\n@@ -2690,6 +2693,7 @@ _gitk ()\n \n \t__git_has_doubledash && return\n \n+\tlocal __git_dir=\"\"\n \tlocal g=\"$(__gitdir)\"\n \tlocal merge=\"\"\n \tif [ -f \"$g/MERGE_HEAD\" ]; then\ndiff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh\nindex 96468ceb..496e04ad 100755\n--- a/t/t9903-bash-prompt.sh\n+++ b/t/t9903-bash-prompt.sh\n@@ -10,6 +10,7 @@ test_description='test git-specific bash prompt functions'\n . \"$GIT_BUILD_DIR/contrib/completion/git-completion.bash\"\n \n actual=\"$TRASH_DIRECTORY/actual\"\n+actual_var=\"$TRASH_DIRECTORY/actual_var\"\n \n test_expect_success 'setup for prompt tests' '\n \tmkdir -p subdir/subsubdir &&\n@@ -35,54 +36,74 @@ test_expect_success 'gitdir - from command line (through $__git_dir)' '\n \techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n \t(\n \t\t__git_dir=\"$TRASH_DIRECTORY/otherrepo/.git\" &&\n-\t\t__gitdir > \"$actual\"\n+\t\t__gitdir > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n \t) &&\n-\ttest_cmp expected \"$actual\"\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n '\n \n test_expect_success 'gitdir - repo as argument' '\n \techo \"otherrepo/.git\" > expected &&\n-\t__gitdir \"otherrepo\" > \"$actual\" &&\n-\ttest_cmp expected \"$actual\"\n+\t(\n+\t\t__gitdir \"otherrepo\" > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n+\t) &&\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n '\n \n test_expect_success 'gitdir - remote as argument' '\n \techo \"remote\" > expected &&\n-\t__gitdir \"remote\" > \"$actual\" &&\n-\ttest_cmp expected \"$actual\"\n+\t(\n+\t\t__gitdir \"remote\" > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n+\t) &&\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n '\n \n test_expect_success 'gitdir - .git directory in cwd' '\n \techo \".git\" > expected &&\n-\t__gitdir > \"$actual\" &&\n-\ttest_cmp expected \"$actual\"\n+\t(\n+\t\t__gitdir > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n+\t) &&\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n '\n \n test_expect_success 'gitdir - .git directory in parent' '\n \techo \"$TRASH_DIRECTORY/.git\" > expected &&\n \t(\n \t\tcd subdir/subsubdir &&\n-\t\t__gitdir > \"$actual\"\n+\t\t__gitdir > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n \t) &&\n-\ttest_cmp expected \"$actual\"\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n '\n \n test_expect_success 'gitdir - cwd is a .git directory' '\n \techo \".\" > expected &&\n \t(\n \t\tcd .git &&\n-\t\t__gitdir > \"$actual\"\n+\t\t__gitdir > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n \t) &&\n-\ttest_cmp expected \"$actual\"\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n '\n \n test_expect_success 'gitdir - parent is a .git directory' '\n \techo \"$TRASH_DIRECTORY/.git\" > expected &&\n \t(\n \t\tcd .git/refs/heads &&\n-\t\t__gitdir > \"$actual\"\n+\t\t__gitdir > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n \t) &&\n-\ttest_cmp expected \"$actual\"\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n '\n \n test_expect_success 'gitdir - $GIT_DIR set while .git directory in cwd' '\n@@ -90,9 +111,11 @@ test_expect_success 'gitdir - $GIT_DIR set while .git directory in cwd' '\n \t(\n \t\tGIT_DIR=\"$TRASH_DIRECTORY/otherrepo/.git\" &&\n \t\texport GIT_DIR &&\n-\t\t__gitdir > \"$actual\"\n+\t\t__gitdir > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n \t) &&\n-\ttest_cmp expected \"$actual\"\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n '\n \n test_expect_success 'gitdir - $GIT_DIR set while .git directory in parent' '\n@@ -101,16 +124,19 @@ test_expect_success 'gitdir - $GIT_DIR set while .git directory in parent' '\n \t\tGIT_DIR=\"$TRASH_DIRECTORY/otherrepo/.git\" &&\n \t\texport GIT_DIR &&\n \t\tcd subdir &&\n-\t\t__gitdir > \"$actual\"\n+\t\t__gitdir > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n \t) &&\n-\ttest_cmp expected \"$actual\"\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n '\n \n test_expect_success 'gitdir - non-existing $GIT_DIR' '\n \t(\n \t\tGIT_DIR=\"$TRASH_DIRECTORY/non-existing\" &&\n \t\texport GIT_DIR &&\n-\t\ttest_must_fail __gitdir\n+\t\ttest_must_fail __gitdir &&\n+\t\ttest -z \"$__git_dir\"\n \t)\n '\n \n@@ -120,9 +146,11 @@ test_expect_success 'gitdir - gitfile in cwd' '\n \ttest_when_finished \"rm -f subdir/.git\" &&\n \t(\n \t\tcd subdir &&\n-\t\t__gitdir > \"$actual\"\n+\t\t__gitdir > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n \t) &&\n-\ttest_cmp expected \"$actual\"\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n '\n \n test_expect_success 'gitdir - gitfile in parent' '\n@@ -131,9 +159,11 @@ test_expect_success 'gitdir - gitfile in parent' '\n \ttest_when_finished \"rm -f subdir/.git\" &&\n \t(\n \t\tcd subdir/subsubdir &&\n-\t\t__gitdir > \"$actual\"\n+\t\t__gitdir > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n \t) &&\n-\ttest_cmp expected \"$actual\"\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n '\n \n test_expect_success SYMLINKS 'gitdir - resulting path avoids symlinks' '\n@@ -144,9 +174,11 @@ test_expect_success SYMLINKS 'gitdir - resulting path avoids symlinks' '\n \ttest_when_finished \"rm -f link\" &&\n \t(\n \t\tcd link &&\n-\t\t__gitdir > \"$actual\"\n+\t\t__gitdir > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n \t) &&\n-\ttest_cmp expected \"$actual\"\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n '\n \n test_expect_success 'gitdir - not a git repository' '\n@@ -154,7 +186,8 @@ test_expect_success 'gitdir - not a git repository' '\n \t\tcd subdir/subsubdir &&\n \t\tGIT_CEILING_DIRECTORIES=\"$TRASH_DIRECTORY\" &&\n \t\texport GIT_CEILING_DIRECTORIES &&\n-\t\ttest_must_fail __gitdir\n+\t\ttest_must_fail __gitdir &&\n+\t\ttest -z \"$__git_dir\"\n \t)\n '\n \n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191167","messageId":"1336524290-30023-9-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 08/19] completion: use $__git_dir instead of $(__gitdir)","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:39Z","receivedAt":"2012-05-09T00:44:39Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"The previous commit changed __gitdir() to store the repository path in\nthe $__git_dir variable.  Now we change all call sites to just call\n__gitdir() directly and then use $__git_dir instead of doing\n'dir=\"$(__gitdir)\"' command substitution, thereby sparing the overhead\nof fork()ing a subshell.\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n contrib/completion/git-completion.bash | 106 ++++++++++++++++++---------------\n 1 file changed, 58 insertions(+), 48 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 85b933f2..5c8d4aea 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -219,33 +219,33 @@ __git_ps1_show_upstream ()\n __git_ps1 ()\n {\n \tlocal __git_dir=\"\"\n-\tlocal g=\"$(__gitdir)\"\n-\tif [ -z \"$g\" ]; then\n+\t__gitdir >/dev/null\n+\tif [ -z \"$__git_dir\" ]; then\n \t\treturn\n \tfi\n \n \tlocal r=\"\"\n \tlocal b=\"\"\n-\tif [ -f \"$g/rebase-merge/interactive\" ]; then\n+\tif [ -f \"$__git_dir/rebase-merge/interactive\" ]; then\n \t\tr=\"|REBASE-i\"\n-\t\tb=\"$(cat \"$g/rebase-merge/head-name\")\"\n-\telif [ -d \"$g/rebase-merge\" ]; then\n+\t\tb=\"$(cat \"$__git_dir/rebase-merge/head-name\")\"\n+\telif [ -d \"$__git_dir/rebase-merge\" ]; then\n \t\tr=\"|REBASE-m\"\n-\t\tb=\"$(cat \"$g/rebase-merge/head-name\")\"\n+\t\tb=\"$(cat \"$__git_dir/rebase-merge/head-name\")\"\n \telse\n-\t\tif [ -d \"$g/rebase-apply\" ]; then\n-\t\t\tif [ -f \"$g/rebase-apply/rebasing\" ]; then\n+\t\tif [ -d \"$__git_dir/rebase-apply\" ]; then\n+\t\t\tif [ -f \"$__git_dir/rebase-apply/rebasing\" ]; then\n \t\t\t\tr=\"|REBASE\"\n-\t\t\telif [ -f \"$g/rebase-apply/applying\" ]; then\n+\t\t\telif [ -f \"$__git_dir/rebase-apply/applying\" ]; then\n \t\t\t\tr=\"|AM\"\n \t\t\telse\n \t\t\t\tr=\"|AM/REBASE\"\n \t\t\tfi\n-\t\telif [ -f \"$g/MERGE_HEAD\" ]; then\n+\t\telif [ -f \"$__git_dir/MERGE_HEAD\" ]; then\n \t\t\tr=\"|MERGING\"\n-\t\telif [ -f \"$g/CHERRY_PICK_HEAD\" ]; then\n+\t\telif [ -f \"$__git_dir/CHERRY_PICK_HEAD\" ]; then\n \t\t\tr=\"|CHERRY-PICKING\"\n-\t\telif [ -f \"$g/BISECT_LOG\" ]; then\n+\t\telif [ -f \"$__git_dir/BISECT_LOG\" ]; then\n \t\t\tr=\"|BISECTING\"\n \t\tfi\n \n@@ -263,7 +263,7 @@ __git_ps1 ()\n \t\t\t\tgit describe --tags --exact-match HEAD ;;\n \t\t\tesac 2>/dev/null)\" ||\n \n-\t\t\tb=\"$(cut -c1-7 \"$g/HEAD\" 2>/dev/null)...\" ||\n+\t\t\tb=\"$(cut -c1-7 \"$__git_dir/HEAD\" 2>/dev/null)...\" ||\n \t\t\treturn\n \t\t\tb=\"($b)\"\n \t\t}\n@@ -522,9 +522,9 @@ __gitcomp_nl ()\n \n __git_heads ()\n {\n-\tlocal dir=\"$(__gitdir)\"\n-\tif [ -d \"$dir\" ]; then\n-\t\tgit --git-dir=\"$dir\" for-each-ref --format='%(refname:short)' \\\n+\t__gitdir \"${1-}\" >/dev/null\n+\tif [ -d \"$__git_dir\" ]; then\n+\t\tgit --git-dir=\"$__git_dir\" for-each-ref --format='%(refname:short)' \\\n \t\t\trefs/heads\n \t\treturn\n \tfi\n@@ -532,9 +532,9 @@ __git_heads ()\n \n __git_tags ()\n {\n-\tlocal dir=\"$(__gitdir)\"\n-\tif [ -d \"$dir\" ]; then\n-\t\tgit --git-dir=\"$dir\" for-each-ref --format='%(refname:short)' \\\n+\t__gitdir \"${1-}\" >/dev/null\n+\tif [ -d \"$__git_dir\" ]; then\n+\t\tgit --git-dir=\"$__git_dir\" for-each-ref --format='%(refname:short)' \\\n \t\t\trefs/tags\n \t\treturn\n \tfi\n@@ -545,9 +545,10 @@ __git_tags ()\n # by checkout for tracking branches\n __git_refs ()\n {\n-\tlocal i hash dir=\"$(__gitdir \"${1-}\")\" track=\"${2-}\"\n+\tlocal i hash track=\"${2-}\"\n \tlocal format refs\n-\tif [ -d \"$dir\" ]; then\n+\t__gitdir \"${1-}\" >/dev/null\n+\tif [ -d \"$__git_dir\" ]; then\n \t\tcase \"$cur\" in\n \t\trefs|refs/*)\n \t\t\tformat=\"refname\"\n@@ -556,20 +557,20 @@ __git_refs ()\n \t\t\t;;\n \t\t*)\n \t\t\tfor i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do\n-\t\t\t\tif [ -e \"$dir/$i\" ]; then echo $i; fi\n+\t\t\t\tif [ -e \"$__git_dir/$i\" ]; then echo $i; fi\n \t\t\tdone\n \t\t\tformat=\"refname:short\"\n \t\t\trefs=\"refs/tags refs/heads refs/remotes\"\n \t\t\t;;\n \t\tesac\n-\t\tgit --git-dir=\"$dir\" for-each-ref --format=\"%($format)\" \\\n+\t\tgit --git-dir=\"$__git_dir\" for-each-ref --format=\"%($format)\" \\\n \t\t\t$refs\n \t\tif [ -n \"$track\" ]; then\n \t\t\t# employ the heuristic used by git checkout\n \t\t\t# Try to find a remote branch that matches the completion word\n \t\t\t# but only output if the branch name is unique\n \t\t\tlocal ref entry\n-\t\t\tgit --git-dir=\"$dir\" for-each-ref --shell --format=\"ref=%(refname:short)\" \\\n+\t\t\tgit --git-dir=\"$__git_dir\" for-each-ref --shell --format=\"ref=%(refname:short)\" \\\n \t\t\t\t\"refs/remotes/\" | \\\n \t\t\twhile read -r entry; do\n \t\t\t\teval \"$entry\"\n@@ -583,7 +584,7 @@ __git_refs ()\n \tfi\n \tcase \"$cur\" in\n \trefs|refs/*)\n-\t\tgit ls-remote \"$dir\" \"$cur*\" 2>/dev/null | \\\n+\t\tgit ls-remote \"$__git_dir\" \"$cur*\" 2>/dev/null | \\\n \t\twhile read -r hash i; do\n \t\t\tcase \"$i\" in\n \t\t\t*^{}) ;;\n@@ -592,7 +593,7 @@ __git_refs ()\n \t\tdone\n \t\t;;\n \t*)\n-\t\tgit ls-remote \"$dir\" HEAD ORIG_HEAD 'refs/tags/*' 'refs/heads/*' 'refs/remotes/*' 2>/dev/null | \\\n+\t\tgit ls-remote \"$__git_dir\" HEAD ORIG_HEAD 'refs/tags/*' 'refs/heads/*' 'refs/remotes/*' 2>/dev/null | \\\n \t\twhile read -r hash i; do\n \t\t\tcase \"$i\" in\n \t\t\t*^{}) ;;\n@@ -625,9 +626,10 @@ __git_refs_remotes ()\n \n __git_remotes ()\n {\n-\tlocal i IFS=$'\\n' d=\"$(__gitdir)\"\n-\ttest -d \"$d/remotes\" && ls -1 \"$d/remotes\"\n-\tfor i in $(git --git-dir=\"$d\" config --get-regexp 'remote\\..*\\.url' 2>/dev/null); do\n+\tlocal i IFS=$'\\n'\n+\t__gitdir >/dev/null\n+\ttest -d \"$__git_dir/remotes\" && ls -1 \"$__git_dir/remotes\"\n+\tfor i in $(git --git-dir=\"$__git_dir\" config --get-regexp 'remote\\..*\\.url' 2>/dev/null); do\n \t\ti=\"${i#remote.}\"\n \t\techo \"${i/.url*/}\"\n \tdone\n@@ -685,8 +687,9 @@ __git_complete_revlist_file ()\n \t\tesac\n \n \t\tlocal IFS=$'\\n'\n+\t\t__gitdir >/dev/null\n \t\tCOMPREPLY=($(compgen -P \"$pfx\" \\\n-\t\t\t-W \"$(git --git-dir=\"$(__gitdir)\" ls-tree \"$ls\" \\\n+\t\t\t-W \"$(git --git-dir=\"$__git_dir\" ls-tree \"$ls\" \\\n \t\t\t\t| sed '/^100... blob /{\n \t\t\t\t           s,^.*\t,,\n \t\t\t\t           s,$, ,\n@@ -936,7 +939,8 @@ __git_compute_porcelain_commands ()\n __git_pretty_aliases ()\n {\n \tlocal i IFS=$'\\n'\n-\tfor i in $(git --git-dir=\"$(__gitdir)\" config --get-regexp \"pretty\\..*\" 2>/dev/null); do\n+\t__gitdir >/dev/null\n+\tfor i in $(git --git-dir=\"$__git_dir\" config --get-regexp \"pretty\\..*\" 2>/dev/null); do\n \t\tcase \"$i\" in\n \t\tpretty.*)\n \t\t\ti=\"${i#pretty.}\"\n@@ -949,7 +953,8 @@ __git_pretty_aliases ()\n __git_aliases ()\n {\n \tlocal i IFS=$'\\n'\n-\tfor i in $(git --git-dir=\"$(__gitdir)\" config --get-regexp \"alias\\..*\" 2>/dev/null); do\n+\t__gitdir >/dev/null\n+\tfor i in $(git --git-dir=\"$__git_dir\" config --get-regexp \"alias\\..*\" 2>/dev/null); do\n \t\tcase \"$i\" in\n \t\talias.*)\n \t\t\ti=\"${i#alias.}\"\n@@ -962,7 +967,8 @@ __git_aliases ()\n # __git_aliased_command requires 1 argument\n __git_aliased_command ()\n {\n-\tlocal word cmdline=$(git --git-dir=\"$(__gitdir)\" \\\n+\t__gitdir >/dev/null\n+\tlocal word cmdline=$(git --git-dir=\"$__git_dir\" \\\n \t\tconfig --get \"alias.$1\")\n \tfor word in $cmdline; do\n \t\tcase \"$word\" in\n@@ -1013,8 +1019,8 @@ __git_whitespacelist=\"nowarn warn error error-all fix\"\n \n _git_am ()\n {\n-\tlocal dir=\"$(__gitdir)\"\n-\tif [ -d \"$dir\"/rebase-apply ]; then\n+\t__gitdir >/dev/null\n+\tif [ -d \"$__git_dir\"/rebase-apply ]; then\n \t\t__gitcomp \"--skip --continue --resolved --abort\"\n \t\treturn\n \tfi\n@@ -1099,7 +1105,8 @@ _git_bisect ()\n \tlocal subcommands=\"start bad good skip reset visualize replay log run\"\n \tlocal subcommand=\"$(__git_find_on_cmdline \"$subcommands\")\"\n \tif [ -z \"$subcommand\" ]; then\n-\t\tif [ -f \"$(__gitdir)\"/BISECT_START ]; then\n+\t\t__gitdir >/dev/null\n+\t\tif [ -f \"$__git_dir\"/BISECT_START ]; then\n \t\t\t__gitcomp \"$subcommands\"\n \t\telse\n \t\t\t__gitcomp \"replay start\"\n@@ -1559,9 +1566,9 @@ _git_log ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal g=\"$(__gitdir)\"\n+\t__gitdir >/dev/null\n \tlocal merge=\"\"\n-\tif [ -f \"$g/MERGE_HEAD\" ]; then\n+\tif [ -f \"$__git_dir/MERGE_HEAD\" ]; then\n \t\tmerge=\"--merge\"\n \tfi\n \tcase \"$cur\" in\n@@ -1745,8 +1752,8 @@ _git_push ()\n \n _git_rebase ()\n {\n-\tlocal dir=\"$(__gitdir)\"\n-\tif [ -d \"$dir\"/rebase-apply ] || [ -d \"$dir\"/rebase-merge ]; then\n+\t__gitdir >/dev/null\n+\tif [ -d \"$__git_dir\"/rebase-apply ] || [ -d \"$__git_dir\"/rebase-merge ]; then\n \t\t__gitcomp \"--continue --skip --abort\"\n \t\treturn\n \tfi\n@@ -1845,7 +1852,8 @@ __git_config_get_set_variables ()\n \t\tc=$((--c))\n \tdone\n \n-\tgit --git-dir=\"$(__gitdir)\" config $config_file --list 2>/dev/null |\n+\t__gitdir >/dev/null\n+\tgit --git-dir=\"$__git_dir\" config $config_file --list 2>/dev/null |\n \twhile read -r line\n \tdo\n \t\tcase \"$line\" in\n@@ -1880,7 +1888,8 @@ _git_config ()\n \tremote.*.push)\n \t\tlocal remote=\"${prev#remote.}\"\n \t\tremote=\"${remote%.push}\"\n-\t\t__gitcomp_nl \"$(git --git-dir=\"$(__gitdir)\" \\\n+\t\t__gitdir >/dev/null\n+\t\t__gitcomp_nl \"$(git --git-dir=\"$__git_dir\" \\\n \t\t\tfor-each-ref --format='%(refname):%(refname)' \\\n \t\t\trefs/heads)\"\n \t\treturn\n@@ -2304,7 +2313,8 @@ _git_remote ()\n \t\t;;\n \tupdate)\n \t\tlocal i c='' IFS=$'\\n'\n-\t\tfor i in $(git --git-dir=\"$(__gitdir)\" config --get-regexp \"remotes\\..*\" 2>/dev/null); do\n+\t\t__gitdir >/dev/null\n+\t\tfor i in $(git --git-dir=\"$__git_dir\" config --get-regexp \"remotes\\..*\" 2>/dev/null); do\n \t\t\ti=\"${i#remotes.}\"\n \t\t\tc=\"$c ${i/ */}\"\n \t\tdone\n@@ -2441,7 +2451,8 @@ _git_stash ()\n \t\t\tCOMPREPLY=()\n \t\t\t;;\n \t\tshow,*|apply,*|drop,*|pop,*|branch,*)\n-\t\t\t__gitcomp_nl \"$(git --git-dir=\"$(__gitdir)\" stash list \\\n+\t\t\t__gitdir >/dev/null\n+\t\t\t__gitcomp_nl \"$(git --git-dir=\"$__git_dir\" stash list \\\n \t\t\t\t\t| sed -n -e 's/:.*//p')\"\n \t\t\t;;\n \t\t*)\n@@ -2693,10 +2704,9 @@ _gitk ()\n \n \t__git_has_doubledash && return\n \n-\tlocal __git_dir=\"\"\n-\tlocal g=\"$(__gitdir)\"\n-\tlocal merge=\"\"\n-\tif [ -f \"$g/MERGE_HEAD\" ]; then\n+\tlocal __git_dir=\"\" merge=\"\"\n+\t__gitdir >/dev/null\n+\tif [ -f \"$__git_dir/MERGE_HEAD\" ]; then\n \t\tmerge=\"--merge\"\n \tfi\n \tcase \"$cur\" in\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191166","messageId":"1336524290-30023-10-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[RFC PATCH 09/19] completion: platform-specific helper function to get physical path","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:40Z","receivedAt":"2012-05-09T00:44:40Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Two upcoming optimizations will replace invocations of git commands in\ncommand substitutions with bash builtins examining the path of the\ncurrent working directory.  Since git works with physical paths, we\ncan't use logical path provided in $PWD, but have to resort to the\n'$(pwd -P)' command substitution to get the physical path of the\ncurrent directory.\n\nHowever, on platforms not supporting symbolic links, such as MinGW,\nthe path in $PWD is bound to be the physical path.  So on those\nplatforms we could avoid the command substitution and use $PWD\ndirectly.  Great for MinGW, because the overhead of forking a subshell\nis relatively large there.\n\nSo add a platform-specific helper function to get the physical path of\nthe current directory: on MinGW it's defined such that it gets the\nphysical path from $PWD, while on other platforms from '$(pwd -P)'.\nThe path is stored in a variable whose name is passed as argument, so\nno command substitution is needed when invoking this function.\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n\nI'm not sure how to check for MinGW; I just looked through the output from\n'set', and saw OSTYPE=msys there.\n\n contrib/completion/git-completion.bash | 14 ++++++++++++++\n t/t9903-bash-prompt.sh                 | 21 +++++++++++++++++++++\n 2 files changed, 35 insertions(+)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 5c8d4aea..bd7d39e3 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -70,6 +70,20 @@ case \"$COMP_WORDBREAKS\" in\n *)   COMP_WORDBREAKS=\"$COMP_WORDBREAKS:\"\n esac\n \n+# __git_pwd_p() stores the physical path of the current working directory\n+# in the variable whose name is given as argument\n+if [ ${OSTYPE-} = \"msys\" ]; then\n+__git_pwd_p ()\n+{\n+\teval $1=\"$PWD\"\n+}\n+else\n+__git_pwd_p ()\n+{\n+\teval $1=\\\"$(pwd -P)\\\"\n+}\n+fi\n+\n # __gitdir accepts 0 or 1 arguments (i.e., location)\n # Prints the path to the .git directory, and stores it in $__git_dir as well.\n __gitdir ()\ndiff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh\nindex 496e04ad..3d722b25 100755\n--- a/t/t9903-bash-prompt.sh\n+++ b/t/t9903-bash-prompt.sh\n@@ -32,6 +32,27 @@ test_expect_success 'setup for prompt tests' '\n \tgit checkout master\n '\n \n+test_expect_success 'getting pwd -P' '\n+\techo \"$TRASH_DIRECTORY\" > expected &&\n+\t(\n+\t\t__git_pwd_p p &&\n+\t\techo \"$p\" > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success SYMLINKS 'getting pwd -P - avoids symlinks' '\n+\techo \"$TRASH_DIRECTORY/otherrepo\" > expected &&\n+\tln -s otherrepo link &&\n+\ttest_when_finished \"rm -f link\" &&\n+\t(\n+\t\tcd link &&\n+\t\t__git_pwd_p p &&\n+\t\techo \"$p\" > \"$actual\"\n+\t) &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n test_expect_success 'gitdir - from command line (through $__git_dir)' '\n \techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n \t(\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191169","messageId":"1336524290-30023-11-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 10/19] completion: use bash builtins to search for repository","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:41Z","receivedAt":"2012-05-09T00:44:41Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"When not at the top of the work tree or when no path is specified by\n'git --git-dir=...' or $GIT_DIR, the __gitdir() helper function finds\nout the physical path to the '.git' directory by running the '$(git\nrev-parse --git-dir)' command substitution.  fork()ing a subshell and\nfork()+exec()ing a git command take some time; during the same amount\nof time we can stat a lot of files and directories using bash\nbuiltins, likely finding the '.git' directory faster.\n\nThis patch extends __gitdir() to search for a '.git' directory using\nonly bash builtins.  Like the existing check for '.git' in the current\nworking directory or the previously added check for $GIT_DIR, this\nsearch is not that thorough either, as it doesn't check whether the\nfound '.git' directory or the directory pointed to by a gitfile is a\nvalid '.git' repository.\n\nSince git doesn't search for a .git directory beyond filesystem\nboundaries and beyond paths specified in $GIT_CEILING_DIRECTORIES, the\nsearch in __gitdir() should not do that either.  However, bash doesn't\nprovide builtins to check that two paths are on the same filesystem,\nso we can't limit the search cheaply to one filesystem.  Therefore,\n__gitdir() will only use bash builtins when neither of these limits\nare active, i.e. $GIT_DISCOVERY_ACROSS_FILESYSTEM is set and\n$GIT_CEILING_DIRECTORIES is empty, otherwise it will fall back on\nexecuting 'git rev-parse'.  $GIT_CEILING_DIRECTORIES is empty by\ndefault, but users have to set $GIT_DISCOVERY_ACROSS_FILESYSTEM\nexplicitly to enable this optimisation, when they find its\nconsequences acceptable.\n\nOf course, stat()ing in C is much faster than in bash, so there is a\npoint when bash builtins will be slower than '$(git rev-parse\n--git-dir)' despite all the fork()s+exec() overhead.  On MinGW this\noverhead is considerable, and the builtins version is faster even at a\ndepth of 50 directories.  On Linux the builtins version is only faster\nfor paths less than 10 directories deeper than the toplevel; with my\nusage patterns that covers 99.9% of the prompts displayed.\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n contrib/completion/git-completion.bash | 30 ++++++++++++\n t/t9903-bash-prompt.sh                 | 83 ++++++++++++++++++++++++++++++++++\n 2 files changed, 113 insertions(+)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex bd7d39e3..dd69e56e 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -89,13 +89,43 @@ fi\n __gitdir ()\n {\n \tif [ -z \"${1-}\" ]; then\n+\t\tlocal gitfile\n+\n \t\tif [ -n \"${__git_dir-}\" ]; then\n \t\t\t:\n \t\telif [ -n \"${GIT_DIR-}\" ]; then\n \t\t\ttest -d \"${GIT_DIR-}\" || return 1\n \t\t\t__git_dir=\"$GIT_DIR\"\n+\t\telif [ -f .git ]; then\n+\t\t\tread gitfile <.git 2>/dev/null || return 1\n+\t\t\t__git_dir=\"${gitfile#gitdir: }\"\n \t\telif [ -d .git ]; then\n \t\t\t__git_dir=.git\n+\t\telif [ -d refs ] && [ -r HEAD ] && \\\n+\t\t\t\t[ -d \"${GIT_OBJECT_DIRECTORY:-objects}\" ]; then\n+\t\t\t__git_dir=.\n+\t\telif [ -n \"${GIT_DISCOVERY_ACROSS_FILESYSTEM-}\" -a \\\n+\t\t\t\t-z \"${GIT_CEILING_DIRECTORIES-}\" ]; then\n+\t\t\tlocal p\n+\t\t\t__git_pwd_p p\n+\t\t\twhile true; do\n+\t\t\t\tp=\"${p%/*}\"\n+\t\t\t\tif [ -f \"$p/.git\" ]; then\n+\t\t\t\t\tread gitfile <\"$p/.git\" 2>/dev/null || return 1\n+\t\t\t\t\t__git_dir=\"${gitfile#gitdir: }\"\n+\t\t\t\t\tbreak\n+\t\t\t\telif [ -d \"$p/.git\" ]; then\n+\t\t\t\t\t__git_dir=\"$p/.git\"\n+\t\t\t\t\tbreak\n+\t\t\t\telif [ -d \"$p/refs\" ] && [ -r \"$p/HEAD\" ] && \\\n+\t\t\t\t\t\t[ -d \"${GIT_OBJECT_DIRECTORY:-$p/objects}\" ]; then\n+\t\t\t\t\t__git_dir=\"${p:-/}\"\n+\t\t\t\t\tbreak\n+\t\t\t\tfi\n+\t\t\t\tif [ -z \"$p\" ]; then\n+\t\t\t\t\treturn 1\n+\t\t\t\tfi\n+\t\t\tdone\n \t\telse\n \t\t\t__git_dir=\"$(git rev-parse --git-dir 2>/dev/null)\" || return 1\n \t\tfi\ndiff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh\nindex 3d722b25..ffa22d39 100755\n--- a/t/t9903-bash-prompt.sh\n+++ b/t/t9903-bash-prompt.sh\n@@ -105,6 +105,18 @@ test_expect_success 'gitdir - .git directory in parent' '\n \ttest_cmp expected \"$actual_var\"\n '\n \n+test_expect_success 'gitdir - .git directory in parent - with builtins' '\n+\techo \"$TRASH_DIRECTORY/.git\" > expected &&\n+\t(\n+\t\tGIT_DISCOVERY_ACROSS_FILESYSTEM=true &&\n+\t\tcd subdir/subsubdir &&\n+\t\t__gitdir > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n+\t) &&\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n+'\n+\n test_expect_success 'gitdir - cwd is a .git directory' '\n \techo \".\" > expected &&\n \t(\n@@ -116,6 +128,20 @@ test_expect_success 'gitdir - cwd is a .git directory' '\n \ttest_cmp expected \"$actual_var\"\n '\n \n+test_expect_success 'gitdir - cwd is a .git directory - GIT_OBJECT_DIRECTORY' '\n+\techo \".\" > expected &&\n+\tmv .git/objects _objects &&\n+\ttest_when_finished \"mv _objects .git/objects\" &&\n+\t(\n+\t\tGIT_OBJECT_DIRECTORY=\"$TRASH_DIRECTORY/_objects\" &&\n+\t\tcd .git &&\n+\t\t__gitdir > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n+\t) &&\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n+'\n+\n test_expect_success 'gitdir - parent is a .git directory' '\n \techo \"$TRASH_DIRECTORY/.git\" > expected &&\n \t(\n@@ -127,6 +153,33 @@ test_expect_success 'gitdir - parent is a .git directory' '\n \ttest_cmp expected \"$actual_var\"\n '\n \n+test_expect_success 'gitdir - parent is a .git directory - with builtins' '\n+\techo \"$TRASH_DIRECTORY/.git\" > expected &&\n+\t(\n+\t\tGIT_DISCOVERY_ACROSS_FILESYSTEM=true &&\n+\t\tcd .git/refs/heads &&\n+\t\t__gitdir > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n+\t) &&\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n+'\n+\n+test_expect_success 'gitdir - parent is a .git directory - with builtins and GIT_OBJECT_DIRECTORY' '\n+\techo \"$TRASH_DIRECTORY/.git\" > expected &&\n+\tmv .git/objects _objects &&\n+\ttest_when_finished \"mv _objects .git/objects\" &&\n+\t(\n+\t\tGIT_OBJECT_DIRECTORY=\"$TRASH_DIRECTORY/_objects\" &&\n+\t\tGIT_DISCOVERY_ACROSS_FILESYSTEM=true &&\n+\t\tcd .git/refs/heads &&\n+\t\t__gitdir > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n+\t) &&\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n+'\n+\n test_expect_success 'gitdir - $GIT_DIR set while .git directory in cwd' '\n \techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n \t(\n@@ -187,6 +240,20 @@ test_expect_success 'gitdir - gitfile in parent' '\n \ttest_cmp expected \"$actual_var\"\n '\n \n+test_expect_success 'gitdir - gitfile in parent - with builtins' '\n+\techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n+\techo \"gitdir: $TRASH_DIRECTORY/otherrepo/.git\" > subdir/.git &&\n+\ttest_when_finished \"rm -f subdir/.git\" &&\n+\t(\n+\t\tGIT_DISCOVERY_ACROSS_FILESYSTEM=true &&\n+\t\tcd subdir/subsubdir &&\n+\t\t__gitdir > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n+\t) &&\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n+'\n+\n test_expect_success SYMLINKS 'gitdir - resulting path avoids symlinks' '\n \techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n \tmkdir otherrepo/dir &&\n@@ -202,6 +269,22 @@ test_expect_success SYMLINKS 'gitdir - resulting path avoids symlinks' '\n \ttest_cmp expected \"$actual_var\"\n '\n \n+test_expect_success SYMLINKS 'gitdir - resulting path avoids symlinks - with builtins' '\n+\techo \"$TRASH_DIRECTORY/otherrepo/.git\" >expected &&\n+\tmkdir otherrepo/dir &&\n+\ttest_when_finished \"rm -rf otherrepo/dir\" &&\n+\tln -s otherrepo/dir link &&\n+\ttest_when_finished \"rm -f link\" &&\n+\t(\n+\t\tGIT_DISCOVERY_ACROSS_FILESYSTEM=true &&\n+\t\tcd link &&\n+\t\t__gitdir > \"$actual\" &&\n+\t\techo \"$__git_dir\" > \"$actual_var\"\n+\t) &&\n+\ttest_cmp expected \"$actual\" &&\n+\ttest_cmp expected \"$actual_var\"\n+'\n+\n test_expect_success 'gitdir - not a git repository' '\n \t(\n \t\tcd subdir/subsubdir &&\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191170","messageId":"1336524290-30023-12-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 11/19] bash prompt: use bash builtins to find out current branch","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:42Z","receivedAt":"2012-05-09T00:44:42Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"__git_ps1() runs the '$(git symbolic-ref HEAD)' command substitution\nto find out whether we are on a branch and to find out the name of\nthat branch.  This imposes the overhead of fork()ing a subshell and\nfork()+exec()ing a git process.\n\nSince HEAD is a single-line file and the symbolic ref format is quite\nsimple to recognize and parse, read and parse it using only bash\nbuiltins, thereby sparing all that fork()+exec() overhead.\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n contrib/completion/git-completion.bash | 9 ++++++---\n 1 file changed, 6 insertions(+), 3 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex dd69e56e..ed372c41 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -293,8 +293,11 @@ __git_ps1 ()\n \t\t\tr=\"|BISECTING\"\n \t\tfi\n \n-\t\tb=\"$(git symbolic-ref HEAD 2>/dev/null)\" || {\n-\n+\t\tlocal head=\"\"\n+\t\tread head 2>/dev/null <\"$__git_dir/HEAD\" || return\n+\t\t# is it a symbolic ref?\n+\t\tb=\"${head#ref: }\"\n+\t\tif [ \"$head\" = \"$b\" ]; then\n \t\t\tb=\"$(\n \t\t\tcase \"${GIT_PS1_DESCRIBE_STYLE-}\" in\n \t\t\t(contains)\n@@ -310,7 +313,7 @@ __git_ps1 ()\n \t\t\tb=\"$(cut -c1-7 \"$__git_dir/HEAD\" 2>/dev/null)...\" ||\n \t\t\treturn\n \t\t\tb=\"($b)\"\n-\t\t}\n+\t\tfi\n \tfi\n \n \tlocal w=\"\"\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191171","messageId":"1336524290-30023-13-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 12/19] bash prompt: use bash builtins to check whether inside git dir","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:43Z","receivedAt":"2012-05-09T00:44:43Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"__git_ps1() runs the '$(git rev-parse --is-inside-git-dir)' command\nsubstitution to check whether we are inside a .git directory and the\nbash prompt needs to be adjusted accordingly (i.e. display 'BARE!' or\n'GIT_DIR!').  This imposes the overhead of fork()ing a subshell and\nfork()+exec()ing a git process.\n\nPerform this check by comparing the path to the repository and the\ncurrent directory using only bash builtins, thereby sparing all that\nfork()+exec() overhead.\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n contrib/completion/git-completion.bash | 6 +++++-\n 1 file changed, 5 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex ed372c41..72f7d0ed 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -323,7 +323,11 @@ __git_ps1 ()\n \tlocal c=\"\"\n \tlocal p=\"\"\n \n-\tif [ \"true\" = \"$(git rev-parse --is-inside-git-dir 2>/dev/null)\" ]; then\n+\tlocal pwd_p\n+\t__git_pwd_p pwd_p\n+\t# inside .git dir?\n+\tif [ \"$__git_dir\" = \".\" -o \\\n+\t\t\t\"${pwd_p#$__git_dir}\" != \"$pwd_p\" ]; then\n \t\tif [ \"true\" = \"$(git rev-parse --is-bare-repository 2>/dev/null)\" ]; then\n \t\t\tc=\"BARE:\"\n \t\telse\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191172","messageId":"1336524290-30023-14-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 13/19] bash prompt: check whether inside the worktree only when necessary","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:44Z","receivedAt":"2012-05-09T00:44:44Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Besides the current branch name or detached head info __git_ps1() can\nalso display status indicators in the prompt for changes in the work\ntree, stashes, untracked files, and divergence from upstream.  These\nare only displayed when enabled by specific environment variables and\nwhen we are in a work tree.  The latter condition is checked by the\n'$(git rev-parse --is-inside-work-tree)' command substitution,\nimpossing the overhead of fork()ing a subshell and fork()+exec()ing a\ngit process.\n\nHowever, the check for the work tree preceeds the check of the\nenvironment variables enabling status indicators, so it's evaluated\neven when all these indicators are disabled.\n\nCheck upfront whether any of these indicators are enabled, i.e. a\ncorresponding environment variable is set, to spare the unnecessary\nfork()+exec() overhead when all of them are disabled.\n\n(Ideally we could check whether we are in a work tree using only bash\nbuiltins, like we did in the previous commit for .git directory, but\nthe path of the work tree can be specified by the 'core.worktree'\nconfig variable, and running 'git config' to get its value would be\njust as expensive.)\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n contrib/completion/git-completion.bash | 42 +++++++++++++++++++---------------\n 1 file changed, 24 insertions(+), 18 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 72f7d0ed..64b96f13 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -333,29 +333,35 @@ __git_ps1 ()\n \t\telse\n \t\t\tb=\"GIT_DIR!\"\n \t\tfi\n-\telif [ \"true\" = \"$(git rev-parse --is-inside-work-tree 2>/dev/null)\" ]; then\n-\t\tif [ -n \"${GIT_PS1_SHOWDIRTYSTATE-}\" ]; then\n-\t\t\tif [ \"$(git config --bool bash.showDirtyState)\" != \"false\" ]; then\n-\t\t\t\tgit diff --no-ext-diff --quiet --exit-code || w=\"*\"\n-\t\t\t\tif git rev-parse --quiet --verify HEAD >/dev/null; then\n-\t\t\t\t\tgit diff-index --cached --quiet HEAD -- || i=\"+\"\n-\t\t\t\telse\n-\t\t\t\t\ti=\"#\"\n+\telif [ -n \"${GIT_PS1_SHOWDIRTYSTATE-}\" \\\n+\t\t\t-o -n \"${GIT_PS1_SHOWSTASHSTATE-}\" \\\n+\t\t\t-o -n \"${GIT_PS1_SHOWUNTRACKEDFILES-}\" \\\n+\t\t\t-n \"${GIT_PS1_SHOWUPSTREAM-}\" ]; then\n+\t\tif [ \"true\" = \"$(git rev-parse --is-inside-work-tree 2>/dev/null)\" ]; then\n+\t\t\tif [ -n \"${GIT_PS1_SHOWDIRTYSTATE-}\" ]; then\n+\t\t\t\tif [ \"$(git config --bool bash.showDirtyState)\" != \"false\" ]; then\n+\t\t\t\t\tgit diff --no-ext-diff --quiet --exit-code || w=\"*\"\n+\t\t\t\t\tif git rev-parse --quiet --verify HEAD >/dev/null; then\n+\t\t\t\t\t\tgit diff-index --cached --quiet HEAD -- || i=\"+\"\n+\t\t\t\t\telse\n+\t\t\t\t\t\ti=\"#\"\n+\t\t\t\t\tfi\n \t\t\t\tfi\n \t\t\tfi\n-\t\tfi\n-\t\tif [ -n \"${GIT_PS1_SHOWSTASHSTATE-}\" ]; then\n-\t\t\tgit rev-parse --verify refs/stash >/dev/null 2>&1 && s=\"$\"\n-\t\tfi\n \n-\t\tif [ -n \"${GIT_PS1_SHOWUNTRACKEDFILES-}\" ]; then\n-\t\t\tif [ -n \"$(git ls-files --others --exclude-standard)\" ]; then\n-\t\t\t\tu=\"%\"\n+\t\t\tif [ -n \"${GIT_PS1_SHOWSTASHSTATE-}\" ]; then\n+\t\t\t        git rev-parse --verify refs/stash >/dev/null 2>&1 && s=\"$\"\n \t\t\tfi\n-\t\tfi\n \n-\t\tif [ -n \"${GIT_PS1_SHOWUPSTREAM-}\" ]; then\n-\t\t\t__git_ps1_show_upstream\n+\t\t\tif [ -n \"${GIT_PS1_SHOWUNTRACKEDFILES-}\" ]; then\n+\t\t\t\tif [ -n \"$(git ls-files --others --exclude-standard)\" ]; then\n+\t\t\t\t\tu=\"%\"\n+\t\t\t\tfi\n+\t\t\tfi\n+\n+\t\t\tif [ -n \"${GIT_PS1_SHOWUPSTREAM-}\" ]; then\n+\t\t\t\t__git_ps1_show_upstream\n+\t\t\tfi\n \t\tfi\n \tfi\n \n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191174","messageId":"1336524290-30023-15-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 14/19] bash prompt: use bash builtins to find out current branch during rebase","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:45Z","receivedAt":"2012-05-09T00:44:45Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"During an ongoing interactive rebase __git_ps1() finds out the name of\nthe rebased branch by executing the '$(cat .git/rebase-merge/head-name)'\ncommand substitution.  That is not quite the most efficient way to\nread a single line single word file, because it imposes the overhead\nof fork()ing a subshell and fork()+exec()ing 'cat'.\n\nUse the 'read' bash builtin instead to avoid that overhead.\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n contrib/completion/git-completion.bash | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 64b96f13..671032bf 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -272,10 +272,10 @@ __git_ps1 ()\n \tlocal b=\"\"\n \tif [ -f \"$__git_dir/rebase-merge/interactive\" ]; then\n \t\tr=\"|REBASE-i\"\n-\t\tb=\"$(cat \"$__git_dir/rebase-merge/head-name\")\"\n+\t\tread b <\"$__git_dir/rebase-merge/head-name\"\n \telif [ -d \"$__git_dir/rebase-merge\" ]; then\n \t\tr=\"|REBASE-m\"\n-\t\tb=\"$(cat \"$__git_dir/rebase-merge/head-name\")\"\n+\t\tread b <\"$__git_dir/rebase-merge/head-name\"\n \telse\n \t\tif [ -d \"$__git_dir/rebase-apply\" ]; then\n \t\t\tif [ -f \"$__git_dir/rebase-apply/rebasing\" ]; then\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191173","messageId":"1336524290-30023-16-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 15/19] bash prompt: use bash builtins to get detached HEAD abbrev. object name","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:46Z","receivedAt":"2012-05-09T00:44:46Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"When describing a detached HEAD according to the $GIT_PS1_DESCRIBE\nenvironment variable fails, __git_ps1() runs the '$(cut -c1-7\n.git/HEAD)' command substitution to put the 7 hexdigits abbreviated\ncommit object name in the prompt.  This imposes the overhead of\nfork()ing a subshell and fork(+exec()ing 'cut'.\n\nThanks to an earlier commit in this series the contents of HEAD is\nalready read into a local variable, so we can get the 7 hexdigits\nusing only parameter expansions, sparing the fork()+exec() overhead.\n\nSince zsh doesn't implement substring expansion we can't just use\n${head:0:7}, hence the \"remove everything except the first 7 chars\"\nparameter expansion combination.\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n contrib/completion/git-completion.bash | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 671032bf..2346962d 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -310,8 +310,8 @@ __git_ps1 ()\n \t\t\t\tgit describe --tags --exact-match HEAD ;;\n \t\t\tesac 2>/dev/null)\" ||\n \n-\t\t\tb=\"$(cut -c1-7 \"$__git_dir/HEAD\" 2>/dev/null)...\" ||\n-\t\t\treturn\n+\t\t\t# detached head abbreviated object name\n+\t\t\tb=\"${head%${head#???????}}...\"\n \t\t\tb=\"($b)\"\n \t\tfi\n \tfi\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191175","messageId":"1336524290-30023-17-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 16/19] bash prompt: display stash and upstream state even inside the repository","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:47Z","receivedAt":"2012-05-09T00:44:47Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Besides the current branch name or detached head info __git_ps1() can\nalso display some status indicators in the prompt.  The first such\nindicator was for changes in the work tree in 738a94a9 (bash: offer to\nshow (un)staged changes, 2009-02-03), and was only checked/displayed\nwhen inside the work tree.  Later other indicators were added in\n2414b45c (Show presence of stashed changes in bash prompt.,\n2009-06-02), 397f7c63 (Show the presence of untracked files in the\nbash prompt., 2009-07-22), and 6d158cba (bash completion: Support\n\"divergence from upstream\" messages in __git_ps1, 2010-06-17).  All of\nthese just followed suit and were checked only when inside the work\ntree, i.e. after checking the results of the '$(git rev-parse\n--is-inside-work-tree)' command substitution, imposing the overhead of\nfork()ing a subshell and fork()+exec()ing a git process.\n\nHowever, the presence of stashes and the divergence from upstream is\nnot a property of the work tree but a property of the repository, and\nthe implementation of their indicators doesn't actually require a work\ntree.  Therefore, we can display these two indicators even inside the\nrepository.  Not that it's very useful to see the stash status while\npoking around deep inside the .git directory, but this way users\nenabling only the stash indicator won't pay the additional performance\npenalty of the check for the work tree.\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n contrib/completion/git-completion.bash | 20 +++++++++-----------\n t/t9903-bash-prompt.sh                 |  4 ++--\n 2 files changed, 11 insertions(+), 13 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 2346962d..64207e3c 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -334,9 +334,7 @@ __git_ps1 ()\n \t\t\tb=\"GIT_DIR!\"\n \t\tfi\n \telif [ -n \"${GIT_PS1_SHOWDIRTYSTATE-}\" \\\n-\t\t\t-o -n \"${GIT_PS1_SHOWSTASHSTATE-}\" \\\n-\t\t\t-o -n \"${GIT_PS1_SHOWUNTRACKEDFILES-}\" \\\n-\t\t\t-n \"${GIT_PS1_SHOWUPSTREAM-}\" ]; then\n+\t\t\t-o -n \"${GIT_PS1_SHOWUNTRACKEDFILES-}\" ]; then\n \t\tif [ \"true\" = \"$(git rev-parse --is-inside-work-tree 2>/dev/null)\" ]; then\n \t\t\tif [ -n \"${GIT_PS1_SHOWDIRTYSTATE-}\" ]; then\n \t\t\t\tif [ \"$(git config --bool bash.showDirtyState)\" != \"false\" ]; then\n@@ -349,22 +347,22 @@ __git_ps1 ()\n \t\t\t\tfi\n \t\t\tfi\n \n-\t\t\tif [ -n \"${GIT_PS1_SHOWSTASHSTATE-}\" ]; then\n-\t\t\t        git rev-parse --verify refs/stash >/dev/null 2>&1 && s=\"$\"\n-\t\t\tfi\n-\n \t\t\tif [ -n \"${GIT_PS1_SHOWUNTRACKEDFILES-}\" ]; then\n \t\t\t\tif [ -n \"$(git ls-files --others --exclude-standard)\" ]; then\n \t\t\t\t\tu=\"%\"\n \t\t\t\tfi\n \t\t\tfi\n-\n-\t\t\tif [ -n \"${GIT_PS1_SHOWUPSTREAM-}\" ]; then\n-\t\t\t\t__git_ps1_show_upstream\n-\t\t\tfi\n \t\tfi\n \tfi\n \n+\tif [ -n \"${GIT_PS1_SHOWSTASHSTATE-}\" ]; then\n+\t        git rev-parse --verify refs/stash >/dev/null 2>&1 && s=\"$\"\n+\tfi\n+\n+\tif [ -n \"${GIT_PS1_SHOWUPSTREAM-}\" ]; then\n+\t\t__git_ps1_show_upstream\n+\tfi\n+\n \tlocal f=\"$w$i$s$u\"\n \tprintf -- \"${1:- (%s)}\" \"$c${b##refs/heads/}${f:+ $f}$r$p\"\n }\ndiff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh\nindex ffa22d39..a43d402a 100755\n--- a/t/t9903-bash-prompt.sh\n+++ b/t/t9903-bash-prompt.sh\n@@ -542,8 +542,8 @@ test_expect_success 'prompt - stash status indicator - stash' '\n \ttest_cmp expected \"$actual\"\n '\n \n-test_expect_success 'prompt - stash status indicator - not shown inside .git directory' '\n-\tprintf \" (GIT_DIR!)\" > expected &&\n+test_expect_success 'prompt - stash status indicator - stash while inside .git directory' '\n+\tprintf \" (GIT_DIR! $)\" > expected &&\n \techo 2 >file &&\n \tgit stash &&\n \ttest_when_finished \"git stash drop\" &&\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191176","messageId":"1336524290-30023-18-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 17/19] bash prompt: use bash builtins to check stash state","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:48Z","receivedAt":"2012-05-09T00:44:48Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"When the environment variable $GIT_PS1_SHOWSTASHSTATE is set\n__git_ps1() checks the presence of stashes by running 'git rev-parse\n--verify refs/stash'.  This command not only checks that the\n'refs/stash' ref exists but also, well, verifies that it's a valid\nref.\n\nHowever, we don't need to be that thorough for the bash prompt.  We\ncan omit that verification and only check whether 'refs/stash' exists\nor not.  Since 'git pack-refs' never packs 'refs/stash', it's a matter\nof checking the existence of a ref file.  Perform this check using\nonly bash builtins to spare the overhead of fork()+exec()ing a git\nprocess.\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n contrib/completion/git-completion.bash | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 64207e3c..c4feab68 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -356,7 +356,9 @@ __git_ps1 ()\n \tfi\n \n \tif [ -n \"${GIT_PS1_SHOWSTASHSTATE-}\" ]; then\n-\t        git rev-parse --verify refs/stash >/dev/null 2>&1 && s=\"$\"\n+\t\tif [ -r \"$__git_dir/refs/stash\" ]; then\n+\t\t\ts=\"$\"\n+\t\tfi\n \tfi\n \n \tif [ -n \"${GIT_PS1_SHOWUPSTREAM-}\" ]; then\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191178","messageId":"1336524290-30023-19-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[RFC PATCH 18/19] bash prompt: avoid command substitution when checking for untracked files","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:49Z","receivedAt":"2012-05-09T00:44:49Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"When enabled, the bash prompt can indicate the presence of untracked\nfiles with a '%' sign.  __git_ps1() checks for untracked files by running the\n'$(git ls-files --others --exclude-standard)' command substitution,\nand displays the indicator when there is no output.\n\nAvoid this command substitution by additionally passing\n'--error-unmatch *', and checking the command's return value.\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n\nThis seems to do the right thing, but I'm not quite sure, so I would\nappreciate a pair of expert eyeballs on it.\n\n contrib/completion/git-completion.bash | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex c4feab68..5ea19018 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -348,9 +348,8 @@ __git_ps1 ()\n \t\t\tfi\n \n \t\t\tif [ -n \"${GIT_PS1_SHOWUNTRACKEDFILES-}\" ]; then\n-\t\t\t\tif [ -n \"$(git ls-files --others --exclude-standard)\" ]; then\n-\t\t\t\t\tu=\"%\"\n-\t\t\t\tfi\n+\t\t\t\tgit ls-files --others --exclude-standard --error-unmatch -- '*' >/dev/null 2>/dev/null &&\n+\t\t\t\tu=\"%\"\n \t\t\tfi\n \t\tfi\n \tfi\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191177","messageId":"1336524290-30023-20-git-send-email-szeder@ira.uka.de","threadId":"30479","inReplyTo":"1336524290-30023-1-git-send-email-szeder@ira.uka.de","subject":"[PATCH 19/19] bash prompt: alternative git prompt without command substitution","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T00:44:50Z","receivedAt":"2012-05-09T00:44:50Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"__git_ps1() prints the branch name, status indicators, etc. to stdout,\ntherefore it has to be included in $PS1 through a command substitution\nto display that information in the prompt.  The configuration is\nstraightforward, but it imposes the overhead of fork()ing a subshell\nfor the command substitution.\n\nHowever, bash has the $PROMPT_COMMAND shell variable, which \"if set,\nthe value is executed as a command prior to issuing each primary\nprompt\" (quoted from bash man page).  Its value isn't executed in a\nsubshell but in the context of the \"main\" shell, hence (non-local)\nvariables set in invoked shell functions are available when expanding\n$PS1.  We can use this facility to avoid that command substitution for\n__git_ps1().\n\nSo split out the meat of __git_ps1() into the new\n__git_prompt_command() function, which stores the branch name & co.\nin the $__git_ps1_string variable.  This function, as its name\nsuggests, should be included in $PROMPT_COMMAND, and $__git_ps1_string\nshould in turn be included in $PS1 with a bit of a twist to put the\nparentheses around it:\n\n   PROMPT_COMMAND=__git_prompt_command\n   PS1='[\\u@\\h \\W${__git_ps1_string:+ ($__git_ps1_string)}]\\$ '\n\nTurn __git_ps1() into a wrapper around __git_prompt_command() such\nthat it's functionality remains unaltered, so already configured\nprompts won't break.\n\nThe whole series speeds up the bash prompt on Windows/MinGW\nimmensely, in many cases brings it down to around 10ms on my\nmachine while in powersave mode.  Here are some timing results in\nthree common scenarios (repeated 10 times, because the after cases\nwere too fast to measure a single execution accurately with 'time'):\n\nIn my home directory, i.e. not in a git repository, before:\n\n    /c/Users/szeder\n    $ time for i in {0..9} ; do prompt=$(__git_ps1) ; done\n\n    real    0m0.952s\n    user    0m0.214s\n    sys     0m0.444s\n\n  After:\n\n    /c/Users/szeder\n    $ time for i in {0..9} ; do __git_prompt_command ;\n           prompt=${__git_ps1_string:+ ($__git_ps1_string)} ; done\n\n    real    0m0.718s\n    user    0m0.136s\n    sys     0m0.354s\n\n  After, with discovery across filesystems enabled:\n\n    /c/Users/szeder\n    $ time for i in {0..9} ; do __git_prompt_command ;\n           prompt=${__git_ps1_string:+ ($__git_ps1_string)} ; done\n\n    real    0m0.078s\n    user    0m0.016s\n    sys     0m0.062s\n\nAt the top of a work tree, before:\n\n    /c/Users/szeder/repo (master)\n    $ time for i in {0..9} ; do prompt=$(__git_ps1) ; done\n\n    real    0m2.901s\n    user    0m0.391s\n    sys     0m1.468s\n\n  After:\n\n    /c/Users/szeder/repo (master)\n    $ time for i in {0..9} ; do __git_prompt_command ;\n           prompt=${__git_ps1_string:+ ($__git_ps1_string)} ; done\n\n    real    0m0.094s\n    user    0m0.047s\n    sys     0m0.047s\n\nIn a subdirectory, stash indicator enabled, before:\n\n    /c/Users/szeder/repo/subdir (master $)\n    $ time for i in {0..9} ; do prompt=$(__git_ps1) ; done\n\n    real    0m4.118s\n    user    0m0.468s\n    sys     0m2.056s\n\n  After:\n\n    /c/Users/szeder/repo/subdir (master $)\n    $ time for i in {0..9} ; do __git_prompt_command ;\n           prompt=${__git_ps1_string:+ ($__git_ps1_string)} ; done\n\n    real    0m0.858s\n    user    0m0.152s\n    sys     0m0.322s\n\n  After, discovery across filesystems enabled:\n\n    /c/Users/szeder/repo/subdir (master $)\n    $ time for i in {0..9} ; do __git_prompt_command ;\n           prompt=${__git_ps1_string:+ ($__git_ps1_string)} ; done\n\n    real    0m0.109s\n    user    0m0.047s\n    sys     0m0.063s\n\nWell, that's about 97% improvement.\n\nThe performance gain on Linux is smaller, the latter case goes down\nfrom 0.264s to 0.047, but since it was fast enough to begin with I\nwon't lengthen this commit message with further timing results on\nLinux.\n\nSigned-off-by: SZEDER Gábor <szeder@ira.uka.de>\n---\n\nWe had some discussions recently about putting user-facing functions into\na separate \"namespace\".  This patch doesn't take that into account, but\nonce a consensus is reached __git_prompt_command() should be put in that\nnamespace.\n\n contrib/completion/git-completion.bash | 25 +++++++++++++++++++++----\n 1 file changed, 21 insertions(+), 4 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 5ea19018..1c29f3d0 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -29,6 +29,11 @@\n #       are currently in a git repository.  The %s token will be\n #       the name of the current branch.\n #\n+#       Alternatively, to make the above Bash prompt a bit faster:\n+#               PROMPT_COMMAND=__git_prompt_command\n+#               PS1='[\\u@\\h \\W${__git_ps1_string:+ ($__git_ps1_string)}]\\$ '\n+#               GIT_DISCOVERY_ACROSS_FILESYSTEM=true\n+#\n #       In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty\n #       value, unstaged (*) and staged (+) changes will be shown next\n #       to the branch name.  You can configure this per-repository\n@@ -258,11 +263,12 @@ __git_ps1_show_upstream ()\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+# Stores the text to be added to the bash prompt (branch name, status\n+# indicators, etc.) in the $__git_ps1_string variable.\n+__git_prompt_command ()\n {\n \tlocal __git_dir=\"\"\n+\t__git_ps1_string=\"\"\n \t__gitdir >/dev/null\n \tif [ -z \"$__git_dir\" ]; then\n \t\treturn\n@@ -365,7 +371,18 @@ __git_ps1 ()\n \tfi\n \n \tlocal f=\"$w$i$s$u\"\n-\tprintf -- \"${1:- (%s)}\" \"$c${b##refs/heads/}${f:+ $f}$r$p\"\n+\t__git_ps1_string=\"$c${b##refs/heads/}${f:+ $f}$r$p\"\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+{\n+\tlocal __git_ps1_string\n+\t__git_prompt_command\n+\tif [ -n \"$__git_ps1_string\" ]; then\n+\t\tprintf -- \"${1:- (%s)}\" \"$__git_ps1_string\"\n+\tfi\n }\n \n __gitcomp_1 ()\n-- \n1.7.10.1.541.gb1be298\n"},{"id":"191181","messageId":"4FAA1EC7.5030200@viscovery.net","threadId":"30479","inReplyTo":"1336524290-30023-10-git-send-email-szeder@ira.uka.de","subject":"Re: [RFC PATCH 09/19] completion: platform-specific helper function to get physical path","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2012-05-09T07:37:43Z","receivedAt":"2012-05-09T07:37:43Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 5/9/2012 2:44, schrieb SZEDER Gábor:\n> I'm not sure how to check for MinGW; I just looked through the output from\n> 'set', and saw OSTYPE=msys there.\n\nUsusally, we check uname -s for *MINGW* for \"portability\", but\nsince a subshell is counter-productive and we are sure that we have a\nbash here, I think your check is OK.\n\n> +# __git_pwd_p() stores the physical path of the current working directory\n> +# in the variable whose name is given as argument\n> +if [ ${OSTYPE-} = \"msys\" ]; then\n> +__git_pwd_p ()\n> +{\n> +\teval $1=\"$PWD\"\n> +}\n> +else\n> +__git_pwd_p ()\n> +{\n> +\teval $1=\\\"$(pwd -P)\\\"\n> +}\n> +fi\n> +\n\nThe following fixup of the quoting is needed at any rate to make the\neval'd commands resistent against directory names with blanks and\ndouble-quotes.\n\n--- >8 ---\nFrom: Johannes Sixt <j6t@kdbg.org>\nSubject: [PATCH] fixup! completion: platform-specific helper function to get\n physical path\n\nSigned-off-by: Johannes Sixt <j6t@kdbg.org>\n---\n contrib/completion/git-completion.bash |    4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex bd7d39e..2cab4a0 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -75,12 +75,12 @@ esac\n if [ ${OSTYPE-} = \"msys\" ]; then\n __git_pwd_p ()\n {\n-\teval $1=\"$PWD\"\n+\teval \"$1=\\$PWD\"\n }\n else\n __git_pwd_p ()\n {\n-\teval $1=\\\"$(pwd -P)\\\"\n+\teval \"$1=\\$(pwd -P)\"\n }\n fi\n \n-- \n1.7.10.1.1689.gacdfbde\n"},{"id":"191182","messageId":"4FAA25A7.4020300@viscovery.net","threadId":"30479","inReplyTo":"1336524290-30023-3-git-send-email-szeder@ira.uka.de","subject":"Re: [PATCH 02/19] tests: add tests for the bash prompt functions in the completion script","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2012-05-09T08:07:03Z","receivedAt":"2012-05-09T08:07:03Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 5/9/2012 2:44, schrieb SZEDER Gábor:\n> The tests cover the discovery of the '.git' directory in the\n> __gitdir() function in different scenarios, and the prompt itself,\n> i.e. branch name, detached heads, operations (rebase, merge,\n> cherry-pick, bisect), and status indicators (dirty, stash, untracked\n> files; but not the upstream status).\n\nThe following patch contains fixups are needed to pass the tests at\nthis point plus a few more changes.\n\n--- >8 ---\nFrom: Johannes Sixt <j6t@kdbg.org>\nSubject: [PATCH] fixup! tests: add tests for the bash prompt functions in the\n completion script\n\n- $TRASH_DIRECTORY is /c/dir style path, but git produces c:/dir style\n  paths. Use $(pwd), which is short for $(pwd -W) that produces the\n  latter, to assemble expected test data and paths read by git.\n\n- As long as GIT_DIR is only exported for use by git and not used by\n  the completion functions, the move to $(pwd) is only cosmetic and\n  for consistency.\n\n- Insert a #!/bin/sh in the shell script to ensure the test will pass\n  should git-rebase ever be ported to C.\n\nSigned-off-by: Johannes Sixt <j6t@kdbg.org>\n---\n t/t9903-bash-prompt.sh |   29 +++++++++++++++--------------\n 1 file changed, 15 insertions(+), 14 deletions(-)\n\ndiff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh\nindex a6c9ce9..3880c56 100755\n--- a/t/t9903-bash-prompt.sh\n+++ b/t/t9903-bash-prompt.sh\n@@ -32,9 +32,9 @@ test_expect_success 'setup for prompt tests' '\n '\n \n test_expect_success 'gitdir - from command line (through $__git_dir)' '\n-\techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n+\techo \"$(pwd)/otherrepo/.git\" > expected &&\n \t(\n-\t\t__git_dir=\"$TRASH_DIRECTORY/otherrepo/.git\" &&\n+\t\t__git_dir=\"$(pwd)/otherrepo/.git\" &&\n \t\t__gitdir > \"$actual\"\n \t) &&\n \ttest_cmp expected \"$actual\"\n@@ -59,7 +59,7 @@ test_expect_success 'gitdir - .git directory in cwd' '\n '\n \n test_expect_success 'gitdir - .git directory in parent' '\n-\techo \"$TRASH_DIRECTORY/.git\" > expected &&\n+\techo \"$(pwd)/.git\" > expected &&\n \t(\n \t\tcd subdir/subsubdir &&\n \t\t__gitdir > \"$actual\"\n@@ -77,7 +77,7 @@ test_expect_success 'gitdir - cwd is a .git directory' '\n '\n \n test_expect_success 'gitdir - parent is a .git directory' '\n-\techo \"$TRASH_DIRECTORY/.git\" > expected &&\n+\techo \"$(pwd)/.git\" > expected &&\n \t(\n \t\tcd .git/refs/heads &&\n \t\t__gitdir > \"$actual\"\n@@ -86,9 +86,9 @@ test_expect_success 'gitdir - parent is a .git directory' '\n '\n \n test_expect_failure 'gitdir - $GIT_DIR set while .git directory in cwd' '\n-\techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n+\techo \"$(pwd)/otherrepo/.git\" > expected &&\n \t(\n-\t\tGIT_DIR=\"$TRASH_DIRECTORY/otherrepo/.git\" &&\n+\t\tGIT_DIR=\"$(pwd)/otherrepo/.git\" &&\n \t\texport GIT_DIR &&\n \t\t__gitdir > \"$actual\"\n \t) &&\n@@ -96,9 +96,9 @@ test_expect_failure 'gitdir - $GIT_DIR set while .git directory in cwd' '\n '\n \n test_expect_success 'gitdir - $GIT_DIR set while .git directory in parent' '\n-\techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n+\techo \"$(pwd)/otherrepo/.git\" > expected &&\n \t(\n-\t\tGIT_DIR=\"$TRASH_DIRECTORY/otherrepo/.git\" &&\n+\t\tGIT_DIR=\"$(pwd)/otherrepo/.git\" &&\n \t\texport GIT_DIR &&\n \t\tcd subdir &&\n \t\t__gitdir > \"$actual\"\n@@ -107,8 +107,8 @@ test_expect_success 'gitdir - $GIT_DIR set while .git directory in parent' '\n '\n \n test_expect_success 'gitdir - gitfile in cwd' '\n-\techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n-\techo \"gitdir: $TRASH_DIRECTORY/otherrepo/.git\" > subdir/.git &&\n+\techo \"$(pwd)/otherrepo/.git\" > expected &&\n+\techo \"gitdir: $(pwd)/otherrepo/.git\" > subdir/.git &&\n \ttest_when_finished \"rm -f subdir/.git\" &&\n \t(\n \t\tcd subdir &&\n@@ -118,8 +118,8 @@ test_expect_success 'gitdir - gitfile in cwd' '\n '\n \n test_expect_success 'gitdir - gitfile in parent' '\n-\techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n-\techo \"gitdir: $TRASH_DIRECTORY/otherrepo/.git\" > subdir/.git &&\n+\techo \"$(pwd)/otherrepo/.git\" > expected &&\n+\techo \"gitdir: $(pwd)/otherrepo/.git\" > subdir/.git &&\n \ttest_when_finished \"rm -f subdir/.git\" &&\n \t(\n \t\tcd subdir/subsubdir &&\n@@ -129,7 +129,7 @@ test_expect_success 'gitdir - gitfile in parent' '\n '\n \n test_expect_success SYMLINKS 'gitdir - resulting path avoids symlinks' '\n-\techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n+\techo \"$(pwd)/otherrepo/.git\" > expected &&\n \tmkdir otherrepo/dir &&\n \ttest_when_finished \"rm -rf otherrepo/dir\" &&\n \tln -s otherrepo/dir link &&\n@@ -238,11 +238,12 @@ test_expect_success 'prompt - interactive rebase' '\n \tprintf \" (b1|REBASE-i)\" > expected\n \techo \"#!$SHELL_PATH\" >fake_editor.sh &&\n \tcat >>fake_editor.sh <<\\EOF &&\n+#!/bin/sh\n echo \"edit $(git log -1 --format=\"%h\")\" > \"$1\"\n EOF\n \ttest_when_finished \"rm -f fake_editor.sh\" &&\n \tchmod a+x fake_editor.sh &&\n-\ttest_set_editor \"$TRASH_DIRECTORY/fake_editor.sh\" &&\n+\ttest_set_editor \"$(pwd)/fake_editor.sh\" &&\n \tgit checkout b1 &&\n \ttest_when_finished \"git checkout master\" &&\n \tgit rebase -i HEAD^ &&\n-- \n1.7.10.1.1689.gacdfbde\n"},{"id":"191183","messageId":"4FAA25B9.3010208@viscovery.net","threadId":"30479","inReplyTo":"1336524290-30023-13-git-send-email-szeder@ira.uka.de","subject":"Re: [PATCH 12/19] bash prompt: use bash builtins to check whether inside git dir","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2012-05-09T08:07:21Z","receivedAt":"2012-05-09T08:07:21Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 5/9/2012 2:44, schrieb SZEDER Gábor:\n> __git_ps1() runs the '$(git rev-parse --is-inside-git-dir)' command\n> substitution to check whether we are inside a .git directory and the\n> bash prompt needs to be adjusted accordingly (i.e. display 'BARE!' or\n> 'GIT_DIR!').  This imposes the overhead of fork()ing a subshell and\n> fork()+exec()ing a git process.\n> \n> Perform this check by comparing the path to the repository and the\n> current directory using only bash builtins, thereby sparing all that\n> fork()+exec() overhead.\n\n> -\tif [ \"true\" = \"$(git rev-parse --is-inside-git-dir 2>/dev/null)\" ]; then\n> +\tlocal pwd_p\n> +\t__git_pwd_p pwd_p\n> +\t# inside .git dir?\n> +\tif [ \"$__git_dir\" = \".\" -o \\\n> +\t\t\t\"${pwd_p#$__git_dir}\" != \"$pwd_p\" ]; then\n\nAt this point, $__git_dir is c:/dir style, whereas $pwd_p is /c/dir style,\nand the intended prefix check does not trigger.\n\nAs long as $__git_dir is only used to access files, it does not matter\nwhether it is Windows style or POSIX style. But if $__git_dir is used in a\ncomparison, then you must make 100% sure that the involved paths are of\nthe same vintage.\n\nWhat would be lost if this patch were dropped?\n\n-- Hannes\n"},{"id":"191184","messageId":"4FAA263A.4000207@viscovery.net","threadId":"30479","inReplyTo":"1336524290-30023-5-git-send-email-szeder@ira.uka.de","subject":"Re: [PATCH 04/19] completion: respect $GIT_DIR","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2012-05-09T08:09:30Z","receivedAt":"2012-05-09T08:09:30Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 5/9/2012 2:44, schrieb SZEDER Gábor:\n> +test_expect_success 'gitdir - non-existing $GIT_DIR' '\n> +\t(\n> +\t\tGIT_DIR=\"$TRASH_DIRECTORY/non-existing\" &&\n> +\t\texport GIT_DIR &&\n> +\t\ttest_must_fail __gitdir\n> +\t)\n> +'\n\nAnother fixup, but it is only for consistency.\n\n--- >8 ---\nFrom: Johannes Sixt <j6t@kdbg.org>\nSubject: [PATCH] fixup! completion: respect $GIT_DIR\n\nSigned-off-by: Johannes Sixt <j6t@kdbg.org>\n---\n t/t9903-bash-prompt.sh |    2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh\nindex cf8e0ca..0318288 100755\n--- a/t/t9903-bash-prompt.sh\n+++ b/t/t9903-bash-prompt.sh\n@@ -108,7 +108,7 @@ test_expect_success 'gitdir - $GIT_DIR set while .git directory in parent' '\n \n test_expect_success 'gitdir - non-existing $GIT_DIR' '\n \t(\n-\t\tGIT_DIR=\"$TRASH_DIRECTORY/non-existing\" &&\n+\t\tGIT_DIR=\"$(pwd)/non-existing\" &&\n \t\texport GIT_DIR &&\n \t\ttest_must_fail __gitdir\n \t)\n-- \n1.7.10.1.1689.gacdfbde\n"},{"id":"191210","messageId":"7vzk9hrzwf.fsf@alter.siamese.dyndns.org","threadId":"30479","inReplyTo":"4FAA25A7.4020300@viscovery.net","subject":"Re: [PATCH 02/19] tests: add tests for the bash prompt functions in the completion script","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-09T18:08:00Z","receivedAt":"2012-05-09T18:08:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j.sixt@viscovery.net> writes:\n\n> From: Johannes Sixt <j6t@kdbg.org>\n> Subject: [PATCH] fixup! tests: add tests for the bash prompt functions in the\n>  completion script\n>\n> - $TRASH_DIRECTORY is /c/dir style path, but git produces c:/dir style\n>   paths. Use $(pwd), which is short for $(pwd -W) that produces the\n>   latter, to assemble expected test data and paths read by git.\n\nThis comes up very often whenever somebody (including me) touches test\nscripts.  We do have a write-up in t/README in \"Dos and Don'ts\" section,\nbut apparently that is not sufficient to avoid fix-ups.\n\nWould it be possible to arrange so that $TRASH_DIRECTORY, $TEST_DIRECTORY\nand $PWD are set to c:/dir style paths in Windows environment?  What would\nwe break if we did so?\n\nThe other direction of changing the Windows port of git to produce /c/dir\nstyle paths would probably not work, as it would involve ripping out the\npath mangling feature of bash in MSYS, which is done for some reason, I\npresume.\n"},{"id":"191211","messageId":"7vvck5ryl2.fsf@alter.siamese.dyndns.org","threadId":"30479","inReplyTo":"1336524290-30023-3-git-send-email-szeder@ira.uka.de","subject":"Re: [PATCH 02/19] tests: add tests for the bash prompt functions in the completion script","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-09T18:36:25Z","receivedAt":"2012-05-09T18:36:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder@ira.uka.de> writes:\n\n> The tests cover the discovery of the '.git' directory in the __gitdir()\n> function in different scenarios, and the prompt itself, i.e. branch\n> name, detached heads, operations (rebase, merge, cherry-pick, bisect),\n> and status indicators (dirty, stash, untracked files; but not the\n> upstream status).\n>\n> Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>\n\nLooks like a quite comprehensive tests around GIT_PS1_$MANY_DIFFERENT_STYLES\n(except that GIT_PS1_SHOWUPSTREAM seems to be missing); very nice.\n\n> +\techo 1 > file &&\n\nWhen you are going to re-roll to add the missing SHOWUPSTREAM test, in\naddition to J6t's $PWD vs $(pwd) vs $TRASH_DIRECTORY fix, please fix these\nredirections to match the coding styles (i.e. \"cmd >file\" and \"cmd <file\",\nwith SP before and without SP after redirection operators).\n"},{"id":"191212","messageId":"7vr4utryd2.fsf@alter.siamese.dyndns.org","threadId":"30479","inReplyTo":"1336524290-30023-4-git-send-email-szeder@ira.uka.de","subject":"Re: [PATCH 03/19] completion: use __gitdir() in _git_log()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-09T18:41:13Z","receivedAt":"2012-05-09T18:41:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder@ira.uka.de> writes:\n\n> The standard way to find out the path to the repository in the\n> completion script is the __gitdir() helper function, because that\n> handles the repository path given on the command line (i.e. git\n> --git-dir=/path/to/repo log --<TAB>).  However, there is one\n> exception: the completion function for 'git log' still uses 'git\n> rev-parse --git-dir' directly, and could offer (or not) the '--merge'\n> option erroneously when the repository is specified on the command\n> line.\n\nHere `--merge` is the visible symptom, and the real issue you fixed is\nthat it used to be looking into a repository that is different from the\nuser is working with, right [*1*]?\n\nWell spotted, and the fix sounds correct.\n\nThanks.\n\n[Footnote]\n\n*1* I am just making sure I am reading the above right; I am not\nsuggesting to omit description of visible symptom at all---quite\nthe opposite, I do want to see these visible symptom descriptions\nin the log messages.\n"},{"id":"191214","messageId":"7vmx5hrxql.fsf@alter.siamese.dyndns.org","threadId":"30479","inReplyTo":"1336524290-30023-5-git-send-email-szeder@ira.uka.de","subject":"Re: [PATCH 04/19] completion: respect $GIT_DIR","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-09T18:54:42Z","receivedAt":"2012-05-09T18:54:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder@ira.uka.de> writes:\n\n> The __gitdir() helper function finds out the path of the git\n> repository by running 'git rev-parse --git-dir'.  However, it has a\n> shortcut first to avoid the overhead of running a git command in a\n> subshell when the current directory is at the top of the work tree,\n> i.e. when it contains a '.git' subdirectory.\n>\n> If the 'GIT_DIR' environment variable is set then it specifies the\n> path to the git repository, and the autodetection of the '.git'\n> directory is not necessary.  However, $GIT_DIR is only taken into\n> acocunt by 'git rev-parse --git-dir', and the check for the '.git'\n> subdirectory is performed first, so it wins over the path given in\n> $GIT_DIR.\n\nStrictly speaking, you have to be a bit careful here, though.  If GIT_DIR\nis set as a shell variable without being exported, it will not affect\nwhere the \"git\" process you will spawn from your interactive shell session\nwill find the repository.  Only when it is exported it does.\n\nIt is a different matter if the distinction matters in the real life, in\nother words, GIT_DIR set but not exported is a use case that is worth\nworrying about.  But note that our own git-sh-setup script is one such use\ncase, so I wouldn't be surprised if somebody uses it for a strange\nworkflow (I suspect that might involve a working tree that has its .git\ndir in a totally unrelated place, and the user runs \"GIT_DIR=$GIT_DIR git\nsubcmd\", using the set but not exported GIT_DIR as a typesaver).\n\n> diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh\n> index a6c9ce94..96468ceb 100755\n> --- a/t/t9903-bash-prompt.sh\n> +++ b/t/t9903-bash-prompt.sh\n> @@ -85,7 +85,7 @@ test_expect_success 'gitdir - parent is a .git directory' '\n>  \ttest_cmp expected \"$actual\"\n>  '\n>  \n> -test_expect_failure 'gitdir - $GIT_DIR set while .git directory in cwd' '\n> +test_expect_success 'gitdir - $GIT_DIR set while .git directory in cwd' '\n>  \techo \"$TRASH_DIRECTORY/otherrepo/.git\" > expected &&\n>  \t(\n>  \t\tGIT_DIR=\"$TRASH_DIRECTORY/otherrepo/.git\" &&\n\nAnd it is a good thing that the next line that comes after the above\ncontext is \"export GIT_DIR\".  If we were to declare \"set but not exported\"\nan uninteresting use case whose outcome is undefined (and that might be\nfine), this still tests the defined behaviour of having the GIT_DIR in the\nenvironment.\n"},{"id":"191215","messageId":"20120509190100.GB6958@goldbirke","threadId":"30479","inReplyTo":"7vr4utryd2.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 03/19] completion: use __gitdir() in _git_log()","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T19:01:00Z","receivedAt":"2012-05-09T19:01:00Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Wed, May 09, 2012 at 11:41:13AM -0700, Junio C Hamano wrote:\n> SZEDER Gábor <szeder@ira.uka.de> writes:\n> \n> > The standard way to find out the path to the repository in the\n> > completion script is the __gitdir() helper function, because that\n> > handles the repository path given on the command line (i.e. git\n> > --git-dir=/path/to/repo log --<TAB>).  However, there is one\n> > exception: the completion function for 'git log' still uses 'git\n> > rev-parse --git-dir' directly, and could offer (or not) the '--merge'\n> > option erroneously when the repository is specified on the command\n> > line.\n> \n> Here `--merge` is the visible symptom, and the real issue you fixed is\n> that it used to be looking into a repository that is different from the\n> user is working with, right [*1*]?\n\nExactly; will add a sentence about it to be more explicit in the\nreroll.\n\nNote, however, that this doesn't influence refs completion, because\n__git_refs() does use __gitdir(), so it will look into the right\nrepository.\n\n\nGábor\n"},{"id":"191217","messageId":"7vipg5rvzf.fsf@alter.siamese.dyndns.org","threadId":"30479","inReplyTo":"1336524290-30023-6-git-send-email-szeder@ira.uka.de","subject":"Re: [PATCH 05/19] bash prompt: don't show the prompt when .git/HEAD is unreadable","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-09T19:32:36Z","receivedAt":"2012-05-09T19:32:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder@ira.uka.de> writes:\n\n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> index ab26bdc8..cd6a5f12 100755\n> --- a/contrib/completion/git-completion.bash\n> +++ b/contrib/completion/git-completion.bash\n> @@ -258,7 +258,7 @@ __git_ps1 ()\n>  \t\t\t\tesac 2>/dev/null)\" ||\n>  \n>  \t\t\t\tb=\"$(cut -c1-7 \"$g/HEAD\" 2>/dev/null)...\" ||\n> -\t\t\t\tb=\"unknown\"\n> +\t\t\t\treturn\n\nWhile you are touching the vicinity of the code, could we lose that \"cut\"\nand replace it with \"rev-parse --short HEAD\", without the hardcoded 1-7?\n\nI wondered if we can use a single \"git describe\" output for all the\ndescribe/default and failure cases but didn't come up with a good way to\ndo so only by using bash built-ins.\n"},{"id":"191218","messageId":"7vehqtrvt8.fsf@alter.siamese.dyndns.org","threadId":"30479","inReplyTo":"1336524290-30023-8-git-send-email-szeder@ira.uka.de","subject":"Re: [PATCH 07/19] completion: make __gitdir() store repository path in $__git_dir","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-09T19:36:19Z","receivedAt":"2012-05-09T19:36:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder@ira.uka.de> writes:\n\n> Also declare $__git_dir as local in __git_ps1() and _gitk() to prevent\n> the variable from leaking into the environment when they call\n> __gitdir() (that would break completion and bash prompt when the user\n> moves to a different git repository).\n\nGood; this was actually the only major thing I worried about when I saw\nthe tail part of the series.  So $__git_dir is global across the call\nchain of a single invocation to show __git_ps1, but it always is reset\nonce __git_ps1 is called again, so that it will always know where the\nthen-current git repository is, right?\n\nLooks quite a sane and valid optimization to me.\n"},{"id":"191219","messageId":"4FAAC7AE.3020002@pileofstuff.org","threadId":"30479","inReplyTo":"1336524290-30023-20-git-send-email-szeder@ira.uka.de","subject":"Re: [PATCH 19/19] bash prompt: alternative git prompt without command substitution","fromName":"Andrew Sayers","fromEmail":"andrew-git@pileofstuff.org","sentAt":"2012-05-09T19:38:22Z","receivedAt":"2012-05-09T19:38:22Z","isPatch":true,"sender":{"key":"andrew-git@pileofstuff.org","avatar":null},"body":"On 09/05/12 01:44, SZEDER Gábor wrote:\n> __git_ps1() prints the branch name, status indicators, etc. to stdout,\n> therefore it has to be included in $PS1 through a command substitution\n> to display that information in the prompt.  The configuration is\n> straightforward, but it imposes the overhead of fork()ing a subshell\n> for the command substitution.\n> \n> However, bash has the $PROMPT_COMMAND shell variable, which \"if set,\n> the value is executed as a command prior to issuing each primary\n> prompt\" (quoted from bash man page).  Its value isn't executed in a\n> subshell but in the context of the \"main\" shell, hence (non-local)\n> variables set in invoked shell functions are available when expanding\n> $PS1.  We can use this facility to avoid that command substitution for\n> __git_ps1().\n> \n> So split out the meat of __git_ps1() into the new\n> __git_prompt_command() function, which stores the branch name & co.\n> in the $__git_ps1_string variable.  This function, as its name\n> suggests, should be included in $PROMPT_COMMAND, and $__git_ps1_string\n> should in turn be included in $PS1 with a bit of a twist to put the\n> parentheses around it:\n> \n>    PROMPT_COMMAND=__git_prompt_command\n\nRather than overwrite any existing PROMPT_COMMAND, it would be better to\ndo something like:\n\nPROMPT_COMMAND=\"__git_prompt_command; $PROMPT_COMMAND\"\n\n>    PS1='[\\u@\\h \\W${__git_ps1_string:+ ($__git_ps1_string)}]\\$ '\n> \n> Turn __git_ps1() into a wrapper around __git_prompt_command() such\n> that it's functionality remains unaltered, so already configured\n> prompts won't break.\n> \n> The whole series speeds up the bash prompt on Windows/MinGW\n> immensely, in many cases brings it down to around 10ms on my\n> machine while in powersave mode.  Here are some timing results in\n> three common scenarios (repeated 10 times, because the after cases\n> were too fast to measure a single execution accurately with 'time'):\n> \n> In my home directory, i.e. not in a git repository, before:\n> \n>     /c/Users/szeder\n>     $ time for i in {0..9} ; do prompt=$(__git_ps1) ; done\n> \n>     real    0m0.952s\n>     user    0m0.214s\n>     sys     0m0.444s\n> \n>   After:\n> \n>     /c/Users/szeder\n>     $ time for i in {0..9} ; do __git_prompt_command ;\n>            prompt=${__git_ps1_string:+ ($__git_ps1_string)} ; done\n> \n>     real    0m0.718s\n>     user    0m0.136s\n>     sys     0m0.354s\n> \n>   After, with discovery across filesystems enabled:\n> \n>     /c/Users/szeder\n>     $ time for i in {0..9} ; do __git_prompt_command ;\n>            prompt=${__git_ps1_string:+ ($__git_ps1_string)} ; done\n> \n>     real    0m0.078s\n>     user    0m0.016s\n>     sys     0m0.062s\n> \n> At the top of a work tree, before:\n> \n>     /c/Users/szeder/repo (master)\n>     $ time for i in {0..9} ; do prompt=$(__git_ps1) ; done\n> \n>     real    0m2.901s\n>     user    0m0.391s\n>     sys     0m1.468s\n> \n>   After:\n> \n>     /c/Users/szeder/repo (master)\n>     $ time for i in {0..9} ; do __git_prompt_command ;\n>            prompt=${__git_ps1_string:+ ($__git_ps1_string)} ; done\n> \n>     real    0m0.094s\n>     user    0m0.047s\n>     sys     0m0.047s\n> \n> In a subdirectory, stash indicator enabled, before:\n> \n>     /c/Users/szeder/repo/subdir (master $)\n>     $ time for i in {0..9} ; do prompt=$(__git_ps1) ; done\n> \n>     real    0m4.118s\n>     user    0m0.468s\n>     sys     0m2.056s\n> \n>   After:\n> \n>     /c/Users/szeder/repo/subdir (master $)\n>     $ time for i in {0..9} ; do __git_prompt_command ;\n>            prompt=${__git_ps1_string:+ ($__git_ps1_string)} ; done\n> \n>     real    0m0.858s\n>     user    0m0.152s\n>     sys     0m0.322s\n> \n>   After, discovery across filesystems enabled:\n> \n>     /c/Users/szeder/repo/subdir (master $)\n>     $ time for i in {0..9} ; do __git_prompt_command ;\n>            prompt=${__git_ps1_string:+ ($__git_ps1_string)} ; done\n> \n>     real    0m0.109s\n>     user    0m0.047s\n>     sys     0m0.063s\n> \n> Well, that's about 97% improvement.\n> \n> The performance gain on Linux is smaller, the latter case goes down\n> from 0.264s to 0.047, but since it was fast enough to begin with I\n> won't lengthen this commit message with further timing results on\n> Linux.\n> \n> Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>\n> ---\n> \n> We had some discussions recently about putting user-facing functions into\n> a separate \"namespace\".  This patch doesn't take that into account, but\n> once a consensus is reached __git_prompt_command() should be put in that\n> namespace.\n> \n>  contrib/completion/git-completion.bash | 25 +++++++++++++++++++++----\n>  1 file changed, 21 insertions(+), 4 deletions(-)\n> \n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> index 5ea19018..1c29f3d0 100755\n> --- a/contrib/completion/git-completion.bash\n> +++ b/contrib/completion/git-completion.bash\n> @@ -29,6 +29,11 @@\n>  #       are currently in a git repository.  The %s token will be\n>  #       the name of the current branch.\n>  #\n> +#       Alternatively, to make the above Bash prompt a bit faster:\n> +#               PROMPT_COMMAND=__git_prompt_command\n\nAs above, I'd recommend a simple documentation change:\nPROMPT_COMMAND=\"__git_prompt_command; $PROMPT_COMMAND\"\n(to show people how to chain any other prompt commands they have)\n\n> +#               PS1='[\\u@\\h \\W${__git_ps1_string:+ ($__git_ps1_string)}]\\$ '\n> +#               GIT_DISCOVERY_ACROSS_FILESYSTEM=true\n> +#\n>  #       In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty\n>  #       value, unstaged (*) and staged (+) changes will be shown next\n>  #       to the branch name.  You can configure this per-repository\n> @@ -258,11 +263,12 @@ __git_ps1_show_upstream ()\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> +# Stores the text to be added to the bash prompt (branch name, status\n> +# indicators, etc.) in the $__git_ps1_string variable.\n> +__git_prompt_command ()\n>  {\n>  \tlocal __git_dir=\"\"\n> +\t__git_ps1_string=\"\"\n>  \t__gitdir >/dev/null\n>  \tif [ -z \"$__git_dir\" ]; then\n>  \t\treturn\n> @@ -365,7 +371,18 @@ __git_ps1 ()\n>  \tfi\n>  \n>  \tlocal f=\"$w$i$s$u\"\n> -\tprintf -- \"${1:- (%s)}\" \"$c${b##refs/heads/}${f:+ $f}$r$p\"\n> +\t__git_ps1_string=\"$c${b##refs/heads/}${f:+ $f}$r$p\"\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> +{\n> +\tlocal __git_ps1_string\n> +\t__git_prompt_command\n> +\tif [ -n \"$__git_ps1_string\" ]; then\n> +\t\tprintf -- \"${1:- (%s)}\" \"$__git_ps1_string\"\n> +\tfi\n\nHow hard/appropriate would it be to export individual parts of the\nprompt here?  Something like:\n\n__git_ps1_string_dirtystate=\"$i\"\n__git_ps1_string_untrackedfiles=\"$u\"\n\nThere have been requests in the past to let people individually\ncolourise different bits of the prompt, which this would make practical.\n\n>  }\n>  \n>  __gitcomp_1 ()\n"},{"id":"191220","messageId":"7vaa1hrvh6.fsf@alter.siamese.dyndns.org","threadId":"30479","inReplyTo":"1336524290-30023-9-git-send-email-szeder@ira.uka.de","subject":"Re: [PATCH 08/19] completion: use $__git_dir instead of $(__gitdir)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-09T19:43:33Z","receivedAt":"2012-05-09T19:43:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder@ira.uka.de> writes:\n\n> +\t__gitdir >/dev/null\n\nIf this becomes the only call site of __gitdir helper function (and that\nwas the way I read the log message), it would be sane to rename it to\na more descriptive __setup_dash_dash_git_dir function and lose the need to\nredirect its output, no?\n\n> @@ -962,7 +967,8 @@ __git_aliases ()\n>  # __git_aliased_command requires 1 argument\n>  __git_aliased_command ()\n>  {\n> -\tlocal word cmdline=$(git --git-dir=\"$(__gitdir)\" \\\n> +\t__gitdir >/dev/null\n> +\tlocal word cmdline=$(git --git-dir=\"$__git_dir\" \\\n>  \t\tconfig --get \"alias.$1\")\n>  \tfor word in $cmdline; do\n>  \t\tcase \"$word\" in\n\nNow this worries me.  The way I read 07/19 was that the local __git_dir=\"\"\ndeclarations in __git_ps1 and __git were what protected this whole\nmachinery to protect us against surprises from user doing \"cd\" between\ninteractive commands, but you have the same __gitdir call to set up the\nglobal $__git_dir variable there, without the initialization to \"\".\n\nHaving to have a call to __gitdir seems to indicate to me that you cannot\nassume that the other initialization sites may not have been called before\nwe get to this point.  Then why is 'local __git_dir=\"\"' unneeded here?\n"},{"id":"191221","messageId":"20120509194549.GA7824@goldbirke","threadId":"30479","inReplyTo":"7vipg5rvzf.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 05/19] bash prompt: don't show the prompt when .git/HEAD is unreadable","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T19:45:49Z","receivedAt":"2012-05-09T19:45:49Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Wed, May 09, 2012 at 12:32:36PM -0700, Junio C Hamano wrote:\n> SZEDER Gábor <szeder@ira.uka.de> writes:\n> \n> > diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> > index ab26bdc8..cd6a5f12 100755\n> > --- a/contrib/completion/git-completion.bash\n> > +++ b/contrib/completion/git-completion.bash\n> > @@ -258,7 +258,7 @@ __git_ps1 ()\n> >  \t\t\t\tesac 2>/dev/null)\" ||\n> >  \n> >  \t\t\t\tb=\"$(cut -c1-7 \"$g/HEAD\" 2>/dev/null)...\" ||\n> > -\t\t\t\tb=\"unknown\"\n> > +\t\t\t\treturn\n> \n> While you are touching the vicinity of the code, could we lose that \"cut\"\n> and replace it with \"rev-parse --short HEAD\", without the hardcoded 1-7?\n\nPatch 15 (bash prompt: use bash builtins to get detached HEAD abbrev.\nobject name) eliminates that 'cut' with some parameter expansions.\nWhile it doesn't respect the 'core.abbrev' config variable, it's much\nmuch faster, so IMHO it's worth it.\n\n\nGábor\n"},{"id":"191222","messageId":"7v62c5rv1q.fsf@alter.siamese.dyndns.org","threadId":"30479","inReplyTo":"1336524290-30023-11-git-send-email-szeder@ira.uka.de","subject":"Re: [PATCH 10/19] completion: use bash builtins to search for repository","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-09T19:52:49Z","receivedAt":"2012-05-09T19:52:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder@ira.uka.de> writes:\n\n> ..., this\n> search is not that thorough either, as it doesn't check whether the\n> found '.git' directory or the directory pointed to by a gitfile is a\n> valid '.git' repository.\n> ...\n> Of course, stat()ing in C is much faster than in bash, so there is a\n> point when bash builtins will be slower than '$(git rev-parse\n> --git-dir)' despite all the fork()s+exec() overhead.\n\nI'd feel safer if this new logic were an opt-in feature, at least in the\nbeginning, with these pros-and-cons summarized near the beginning of the\nfile to let the users choose if they want to use \"exactly matches the\ncommand the prompt script is trying to help\" version (i.e. rev-parse) vs\n\"matches most of the time and faster under these conditions\" version\n(i.e. the new logic).\n\nThanks.\n"},{"id":"191223","messageId":"7vzk9hqg0u.fsf@alter.siamese.dyndns.org","threadId":"30479","inReplyTo":"1336524290-30023-12-git-send-email-szeder@ira.uka.de","subject":"Re: [PATCH 11/19] bash prompt: use bash builtins to find out current branch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-09T20:02:41Z","receivedAt":"2012-05-09T20:02:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder@ira.uka.de> writes:\n\n> Since HEAD is a single-line file and the symbolic ref format is quite\n> simple to recognize and parse,...\n\nStrictly speaking, that is true only if you somehow know that HEAD is not\na symlinked symref.  You may end up reading [0-9a-f]{40} out of HEAD\nwithout learning where the symbolic link pointed at.\n\nI personally do not _know_ of anybody who is still using a symlinked\nsymref, but the reasoning behind 9f0bb90 (core.prefersymlinkrefs: use\nsymlinks for .git/HEAD, 2006-05-02) cannot go away by definition until\nevery project that benefited from the configuration the commit introduced\ngoes extinct, so I wouldn't be surprised if you get complaints from the\nusers if we adopt this patch.\n"},{"id":"191224","messageId":"7vvck5qfun.fsf@alter.siamese.dyndns.org","threadId":"30479","inReplyTo":"4FAA25B9.3010208@viscovery.net","subject":"Re: [PATCH 12/19] bash prompt: use bash builtins to check whether inside git dir","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-09T20:06:24Z","receivedAt":"2012-05-09T20:06:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j.sixt@viscovery.net> writes:\n\n>> __git_ps1() runs the '$(git rev-parse --is-inside-git-dir)' command\n>> substitution to check whether we are inside a .git directory and the\n>> bash prompt needs to be adjusted accordingly (i.e. display 'BARE!' or\n>> 'GIT_DIR!').  This imposes the overhead of fork()ing a subshell and\n>> fork()+exec()ing a git process.\n>> \n>> Perform this check by comparing the path to the repository and the\n>> current directory using only bash builtins, thereby sparing all that\n>> fork()+exec() overhead.\n>\n>> -\tif [ \"true\" = \"$(git rev-parse --is-inside-git-dir 2>/dev/null)\" ]; then\n>> +\tlocal pwd_p\n>> +\t__git_pwd_p pwd_p\n>> +\t# inside .git dir?\n>> +\tif [ \"$__git_dir\" = \".\" -o \\\n>> +\t\t\t\"${pwd_p#$__git_dir}\" != \"$pwd_p\" ]; then\n>\n> At this point, $__git_dir is c:/dir style, whereas $pwd_p is /c/dir style,\n> and the intended prefix check does not trigger.\n>\n> As long as $__git_dir is only used to access files, it does not matter\n> whether it is Windows style or POSIX style. But if $__git_dir is used in a\n> comparison, then you must make 100% sure that the involved paths are of\n> the same vintage.\n>\n> What would be lost if this patch were dropped?\n\nOne loss of fork/exec is what would be lost, I would guess, and that seems\nto be the primary point of this entire series, so...\n\nAt the conceptual level, I think the optimization in this patch makes\nsense, but if the assumed primary beneficiary (i.e. Windows) cannot\nbenefit from this particular optimization due to two different path\nrepresentations, it wouldn't help being conceptually sound X-<.\n"},{"id":"191228","messageId":"20120509202220.GB7824@goldbirke","threadId":"30479","inReplyTo":"7vaa1hrvh6.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 08/19] completion: use $__git_dir instead of $(__gitdir)","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T20:22:20Z","receivedAt":"2012-05-09T20:22:20Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Wed, May 09, 2012 at 12:43:33PM -0700, Junio C Hamano wrote:\n> SZEDER Gábor <szeder@ira.uka.de> writes:\n> \n> > +\t__gitdir >/dev/null\n> \n> If this becomes the only call site of __gitdir helper function (and that\n> was the way I read the log message), it would be sane to rename it to\n> a more descriptive __setup_dash_dash_git_dir function and lose the need to\n> redirect its output, no?\n\nThere might be user-defined completion functions using __gitdir(), and\nI didn't want to break them by changing the function's name or\naltering its existing behavior, i.e. printing the path.\n\n> > @@ -962,7 +967,8 @@ __git_aliases ()\n> >  # __git_aliased_command requires 1 argument\n> >  __git_aliased_command ()\n> >  {\n> > -\tlocal word cmdline=$(git --git-dir=\"$(__gitdir)\" \\\n> > +\t__gitdir >/dev/null\n> > +\tlocal word cmdline=$(git --git-dir=\"$__git_dir\" \\\n> >  \t\tconfig --get \"alias.$1\")\n> >  \tfor word in $cmdline; do\n> >  \t\tcase \"$word\" in\n> \n> Now this worries me.  The way I read 07/19 was that the local __git_dir=\"\"\n> declarations in __git_ps1 and __git were what protected this whole\n> machinery to protect us against surprises from user doing \"cd\" between\n> interactive commands, but you have the same __gitdir call to set up the\n> global $__git_dir variable there, without the initialization to \"\".\n> \n> Having to have a call to __gitdir seems to indicate to me that you cannot\n> assume that the other initialization sites may not have been called before\n> we get to this point.  Then why is 'local __git_dir=\"\"' unneeded here?\n\nYour comments to the previous patch apply here.\n\nAll completion functions are called either from _git() or from\n_gitk(), where $__git_dir is declared as local.  So no matter how deep\nis $__git_dir set in the callchain, it can't leak into the\nenvironment.  It won't even survive between two subsequent completions\non the same command line.\n\nNow, it would definitely be simpler to just initialize $__git_dir in\nthe two toplevel functions.  But there are many codepatch that don't\nneed $__git_dir at all, and would only be slowed down by an additional\n$(git rev-parse --git-dir).\n\n\nGábor\n"},{"id":"191232","messageId":"7vr4utqemg.fsf@alter.siamese.dyndns.org","threadId":"30479","inReplyTo":"1336524290-30023-19-git-send-email-szeder@ira.uka.de","subject":"Re: [RFC PATCH 18/19] bash prompt: avoid command substitution when checking for untracked files","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-09T20:32:55Z","receivedAt":"2012-05-09T20:32:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder@ira.uka.de> writes:\n\n> When enabled, the bash prompt can indicate the presence of untracked\n> files with a '%' sign.  __git_ps1() checks for untracked files by running the\n> '$(git ls-files --others --exclude-standard)' command substitution,\n> and displays the indicator when there is no output.\n>\n> Avoid this command substitution by additionally passing\n> '--error-unmatch *', and checking the command's return value.\n\nThis is too subtle and needs to be explained in a in-code comment.  For\nexample, it is unclear to me how this '*' pathspec and an untracked file\nthat does not fnmatch(3) with the pattern (e.g. \".trash\").\n\n\n        $ rm -fr /var/tmp/x && git init /var/tmp/x && cd /var/tmp/x\n\t$ args='ls-files --others --exclude-standard'\n\n\t$ git $args | wc -l\n        0\n        $ git $args --error-unmatch -- '*' >/dev/null 2>&1 ; echo $?\n        1\n\n        $ >a\n        $ git $args | wc -l\n\t1\n        $ git $args --error-unmatch -- '*' >/dev/null 2>&1 ; echo $?\n\t0\n\n\t$ mv a .a\n        $ git $args | wc -l\n\t1\n        $ git $args --error-unmatch -- '*' >/dev/null 2>&1 ; echo $?\n\t0\n\nThe first two cases seem to be fine, but isn't the last one showing that\nyour update is incorrect?\n\n>\n> Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>\n> ---\n>\n> This seems to do the right thing, but I'm not quite sure, so I would\n> appreciate a pair of expert eyeballs on it.\n>\n>  contrib/completion/git-completion.bash | 5 ++---\n>  1 file changed, 2 insertions(+), 3 deletions(-)\n>\n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> index c4feab68..5ea19018 100755\n> --- a/contrib/completion/git-completion.bash\n> +++ b/contrib/completion/git-completion.bash\n> @@ -348,9 +348,8 @@ __git_ps1 ()\n>  \t\t\tfi\n>  \n>  \t\t\tif [ -n \"${GIT_PS1_SHOWUNTRACKEDFILES-}\" ]; then\n> -\t\t\t\tif [ -n \"$(git ls-files --others --exclude-standard)\" ]; then\n> -\t\t\t\t\tu=\"%\"\n> -\t\t\t\tfi\n> +\t\t\t\tgit ls-files --others --exclude-standard --error-unmatch -- '*' >/dev/null 2>/dev/null &&\n> +\t\t\t\tu=\"%\"\n>  \t\t\tfi\n>  \t\tfi\n>  \tfi\n"},{"id":"191233","messageId":"20120509203354.GC6958@goldbirke","threadId":"30479","inReplyTo":"7vvck5ryl2.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 02/19] tests: add tests for the bash prompt functions in the completion script","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T20:33:54Z","receivedAt":"2012-05-09T20:33:54Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Wed, May 09, 2012 at 11:36:25AM -0700, Junio C Hamano wrote:\n> SZEDER Gábor <szeder@ira.uka.de> writes:\n> \n> > The tests cover the discovery of the '.git' directory in the __gitdir()\n> > function in different scenarios, and the prompt itself, i.e. branch\n> > name, detached heads, operations (rebase, merge, cherry-pick, bisect),\n> > and status indicators (dirty, stash, untracked files; but not the\n> > upstream status).\n> >\n> > Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>\n> \n> Looks like a quite comprehensive tests around GIT_PS1_$MANY_DIFFERENT_STYLES\n> (except that GIT_PS1_SHOWUPSTREAM seems to be missing); very nice.\n\nI've mentioned in the commit message that \"... status indicators ...\nbut not the upstream status\".  I didn't wrote tests for that because\nthis series doesn't changes anything in the function producing the\nupstream status indicator.\n\nHowever, thinking about it now, this series, in particular patch 16\n(bash prompt: display stash and upstream state even inside the\nrepository), does change the context in which that function might be\ninvoked, i.e. not only from the work tree but even from within the\nrepository.  I don't think that would break anything (famous last\nwords ;), because that function runs git config, rev-list, and log,\nand AFAICT these commands should work in a repository just as well,\nand the rest of the function is just preparing their arguments and\nprocessing their output.\n\nAnyway, it would be definitely better to have a test to show that it\nindeed works from within a repository, but I didn't want to fiddle\nwith svn upstreams.  Perhaps patch 16 should leave the upstream status\nindicator as it is until someone ;) writes tests for it; since that\nfunction doesn't affect the main codepath and it involves several\nsubshells and git processes anyway, there is not that much to be\ngained anyway.\n\n> > +\techo 1 > file &&\n> \n> When you are going to re-roll to add the missing SHOWUPSTREAM test, in\n> addition to J6t's $PWD vs $(pwd) vs $TRASH_DIRECTORY fix, please fix these\n> redirections to match the coding styles (i.e. \"cmd >file\" and \"cmd <file\",\n> with SP before and without SP after redirection operators).\n\nOK.\n\nI just followed suit of the recently added t9902-completion.sh, which\nuses SP on both sides of redirection operators.\n"},{"id":"191235","messageId":"7vmx5hqdjx.fsf@alter.siamese.dyndns.org","threadId":"30479","inReplyTo":"20120509202220.GB7824@goldbirke","subject":"Re: [PATCH 08/19] completion: use $__git_dir instead of $(__gitdir)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-09T20:56:02Z","receivedAt":"2012-05-09T20:56:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder@ira.uka.de> writes:\n\n>> > @@ -962,7 +967,8 @@ __git_aliases ()\n>> >  # __git_aliased_command requires 1 argument\n>> >  __git_aliased_command ()\n>> >  {\n>> > -\tlocal word cmdline=$(git --git-dir=\"$(__gitdir)\" \\\n>> > +\t__gitdir >/dev/null\n>> > +\tlocal word cmdline=$(git --git-dir=\"$__git_dir\" \\\n>> >  \t\tconfig --get \"alias.$1\")\n>> >  \tfor word in $cmdline; do\n>> >  \t\tcase \"$word\" in\n>> \n>> Now this worries me.  The way I read 07/19 was that the local __git_dir=\"\"\n>> declarations in __git_ps1 and __git were what protected this whole\n>> machinery to protect us against surprises from user doing \"cd\" between\n>> interactive commands, but you have the same __gitdir call to set up the\n>> global $__git_dir variable there, without the initialization to \"\".\n>> \n>> Having to have a call to __gitdir seems to indicate to me that you cannot\n>> assume that the other initialization sites may not have been called before\n>> we get to this point.  Then why is 'local __git_dir=\"\"' unneeded here?\n>\n> Your comments to the previous patch apply here.\n\nNot really.  __git_ps1 and __gitk seems to do __gitdir very early to make\nsure anybody that use $__git_dir can rely on it, but having to sprinkle\n\"set up $__git_dir variable\" everywhere means anybody who wants to update\nneed to know if it is already called, which defeats the point of \"we can\nuse $__git_dir instead of calling $(__gitdir)\" from maintainability's\npoint of view.\n"},{"id":"191236","messageId":"20120509211143.GE6958@goldbirke","threadId":"30479","inReplyTo":"7vzk9hqg0u.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 11/19] bash prompt: use bash builtins to find out current branch","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T21:11:43Z","receivedAt":"2012-05-09T21:11:43Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Wed, May 09, 2012 at 01:02:41PM -0700, Junio C Hamano wrote:\n> SZEDER Gábor <szeder@ira.uka.de> writes:\n> \n> > Since HEAD is a single-line file and the symbolic ref format is quite\n> > simple to recognize and parse,...\n> \n> Strictly speaking, that is true only if you somehow know that HEAD is not\n> a symlinked symref.  You may end up reading [0-9a-f]{40} out of HEAD\n> without learning where the symbolic link pointed at.\n> \n> I personally do not _know_ of anybody who is still using a symlinked\n> symref, but the reasoning behind 9f0bb90 (core.prefersymlinkrefs: use\n> symlinks for .git/HEAD, 2006-05-02) cannot go away by definition until\n> every project that benefited from the configuration the commit introduced\n> goes extinct, so I wouldn't be surprised if you get complaints from the\n> users if we adopt this patch.\n\nSymlinked symref, wow.  That was long before my time ;)\n\nSo, let's see whether I understand it correctly:\n\n- If HEAD is a symlink, then it's a symlinked symref, and points to\n  a real ref file somewhere under refs/.\n- If HEAD is a regular file, then it's either a symref containing\n  'ref: refs/...', or it's a detached HEAD containing 40 hexdigits.\n\nIf the above is right, then we could check with bash builtins whether\nHEAD is a symbolic link, which is cheap, and stick to '$(git\nsymbolic-ref HEAD)' if it is, or use bash builtins if it isn't, right?  \nThis way we could get most of the performance benefits for modern\nHEADs, while still supporting symlinked symrefs.\n\nGábor\n"},{"id":"191238","messageId":"7vehqtqc6d.fsf@alter.siamese.dyndns.org","threadId":"30479","inReplyTo":"20120509211143.GE6958@goldbirke","subject":"Re: [PATCH 11/19] bash prompt: use bash builtins to find out current branch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-09T21:25:46Z","receivedAt":"2012-05-09T21:25:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder@ira.uka.de> writes:\n\n> If the above is right, then we could check with bash builtins whether\n> HEAD is a symbolic link, which is cheap, and stick to '$(git\n> symbolic-ref HEAD)' if it is, or use bash builtins if it isn't, right?  \n\nSure.  Alternatively, you could run \"readlink\" on it if that is available\nbuilt-in, and manipulate the result in string builtins, but that is a b/c\nslow path anyway, so I wouldn't bother.\n\nThanks.\n"},{"id":"191239","messageId":"20120509213636.GC7824@goldbirke","threadId":"30479","inReplyTo":"7vmx5hqdjx.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 08/19] completion: use $__git_dir instead of $(__gitdir)","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T21:36:36Z","receivedAt":"2012-05-09T21:36:36Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Wed, May 09, 2012 at 01:56:02PM -0700, Junio C Hamano wrote:\n> SZEDER Gábor <szeder@ira.uka.de> writes:\n> \n> >> > @@ -962,7 +967,8 @@ __git_aliases ()\n> >> >  # __git_aliased_command requires 1 argument\n> >> >  __git_aliased_command ()\n> >> >  {\n> >> > -\tlocal word cmdline=$(git --git-dir=\"$(__gitdir)\" \\\n> >> > +\t__gitdir >/dev/null\n> >> > +\tlocal word cmdline=$(git --git-dir=\"$__git_dir\" \\\n> >> >  \t\tconfig --get \"alias.$1\")\n> >> >  \tfor word in $cmdline; do\n> >> >  \t\tcase \"$word\" in\n> >> \n> >> Now this worries me.  The way I read 07/19 was that the local __git_dir=\"\"\n> >> declarations in __git_ps1 and __git were what protected this whole\n> >> machinery to protect us against surprises from user doing \"cd\" between\n> >> interactive commands, but you have the same __gitdir call to set up the\n> >> global $__git_dir variable there, without the initialization to \"\".\n> >> \n> >> Having to have a call to __gitdir seems to indicate to me that you cannot\n> >> assume that the other initialization sites may not have been called before\n> >> we get to this point.  Then why is 'local __git_dir=\"\"' unneeded here?\n> >\n> > Your comments to the previous patch apply here.\n> \n> Not really.  __git_ps1 and __gitk seems to do __gitdir very early to make\n> sure anybody that use $__git_dir can rely on it\n\nNo, __git_ps1() and __gitk() do __gitdir() early, because they need\nthe path to the repository very early.\n\n> but having to sprinkle\n> \"set up $__git_dir variable\" everywhere means anybody who wants to update\n> need to know if it is already called, which defeats the point of \"we can\n> use $__git_dir instead of calling $(__gitdir)\" from maintainability's\n> point of view.\n\nWell, the point is better explained in the body of the commit message:\n\n  just call __gitdir() directly and then use $__git_dir instead of\n  doing 'dir=\"$(__gitdir)\"' command substitution\n\nUnfortunately, I just couldn't manage to squeeze all this into a\none-line short description.  So it really is about performance, and\nnot maintainability.\n"},{"id":"191242","messageId":"20120509214534.GF6958@goldbirke","threadId":"30479","inReplyTo":"7vehqtqc6d.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 11/19] bash prompt: use bash builtins to find out current branch","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T21:45:34Z","receivedAt":"2012-05-09T21:45:34Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Wed, May 09, 2012 at 02:25:46PM -0700, Junio C Hamano wrote:\n> SZEDER Gábor <szeder@ira.uka.de> writes:\n> \n> > If the above is right, then we could check with bash builtins whether\n> > HEAD is a symbolic link, which is cheap, and stick to '$(git\n> > symbolic-ref HEAD)' if it is, or use bash builtins if it isn't, right?  \n> \n> Sure.  Alternatively, you could run \"readlink\" on it if that is available\n> built-in, and manipulate the result in string builtins, but that is a b/c\n> slow path anyway, so I wouldn't bother.\n\nOK, will do that then.\n\n'readlink' is not a bash builtin, so it would need the same number of\nfork()s and exec() as 'symbolic-ref'.  Of course, the 'readlink'\nbinary is much smaller than git and has less to do, so it might be a\ntiny bit faster, but for this rare corner case it really doesn't\nmatter.\n"},{"id":"191243","messageId":"7vaa1hqb1j.fsf@alter.siamese.dyndns.org","threadId":"30479","inReplyTo":"20120509214534.GF6958@goldbirke","subject":"Re: [PATCH 11/19] bash prompt: use bash builtins to find out current branch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-09T21:50:16Z","receivedAt":"2012-05-09T21:50:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder@ira.uka.de> writes:\n\n> 'readlink' is not a bash builtin, so it would need the same number of\n> fork()s and exec() as 'symbolic-ref'.  Of course, the 'readlink'\n> binary is much smaller than git and has less to do, so it might be a\n> tiny bit faster, but for this rare corner case it really doesn't\n> matter.\n\nCorrect, and by not using it you do not have to worry about systems\nthat does not install the binary.\n"},{"id":"191246","messageId":"20120509220844.GG6958@goldbirke","threadId":"30479","inReplyTo":"4FAAC7AE.3020002@pileofstuff.org","subject":"Re: [PATCH 19/19] bash prompt: alternative git prompt without command substitution","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T22:08:44Z","receivedAt":"2012-05-09T22:08:44Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Hi,\n\nOn Wed, May 09, 2012 at 08:38:22PM +0100, Andrew Sayers wrote:\n> On 09/05/12 01:44, SZEDER Gábor wrote:\n> >    PROMPT_COMMAND=__git_prompt_command\n> \n> Rather than overwrite any existing PROMPT_COMMAND, it would be better to\n> do something like:\n> \n> PROMPT_COMMAND=\"__git_prompt_command; $PROMPT_COMMAND\"\n\n> > +#       Alternatively, to make the above Bash prompt a bit faster:\n> > +#               PROMPT_COMMAND=__git_prompt_command\n> \n> As above, I'd recommend a simple documentation change:\n> PROMPT_COMMAND=\"__git_prompt_command; $PROMPT_COMMAND\"\n> (to show people how to chain any other prompt commands they have)\n\nThat's a good idea.  In fact I did manage to overwrite my\n$PROMPT_COMMAND and was wondering why did the title of my terminal\nwindows disappear so suddenly...\n\n\n> > @@ -365,7 +371,18 @@ __git_ps1 ()\n> >  \tfi\n> >  \n> >  \tlocal f=\"$w$i$s$u\"\n> > -\tprintf -- \"${1:- (%s)}\" \"$c${b##refs/heads/}${f:+ $f}$r$p\"\n> > +\t__git_ps1_string=\"$c${b##refs/heads/}${f:+ $f}$r$p\"\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> > +{\n> > +\tlocal __git_ps1_string\n> > +\t__git_prompt_command\n> > +\tif [ -n \"$__git_ps1_string\" ]; then\n> > +\t\tprintf -- \"${1:- (%s)}\" \"$__git_ps1_string\"\n> > +\tfi\n> \n> How hard/appropriate would it be to export individual parts of the\n> prompt here?  Something like:\n> \n> __git_ps1_string_dirtystate=\"$i\"\n> __git_ps1_string_untrackedfiles=\"$u\"\n> \n> There have been requests in the past to let people individually\n> colourise different bits of the prompt, which this would make practical.\n\nWe can't do that from __git_ps1(), because, as I mentioned in the commit\nmessage, it must be invoked in a command substitution from $PS1, and\nwhat's exported in a subshell that stays in that subshell.\n\nDoing so from __git_prompt_command() would be quite simple: just\nrename the appropriate variables and don't declare them as local.\nIt would even be more pleasing to the eyes than the current one-letter\nvariable names.\n\n\nGábor\n"},{"id":"191249","messageId":"20120509223444.GH6958@goldbirke","threadId":"30479","inReplyTo":"7v62c5rv1q.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 10/19] completion: use bash builtins to search for repository","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2012-05-09T22:34:44Z","receivedAt":"2012-05-09T22:34:44Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Wed, May 09, 2012 at 12:52:49PM -0700, Junio C Hamano wrote:\n> SZEDER Gábor <szeder@ira.uka.de> writes:\n> \n> > ..., this\n> > search is not that thorough either, as it doesn't check whether the\n> > found '.git' directory or the directory pointed to by a gitfile is a\n> > valid '.git' repository.\n> > ...\n> > Of course, stat()ing in C is much faster than in bash, so there is a\n> > point when bash builtins will be slower than '$(git rev-parse\n> > --git-dir)' despite all the fork()s+exec() overhead.\n> \n> I'd feel safer if this new logic were an opt-in feature, at least in the\n> beginning, with these pros-and-cons summarized near the beginning of the\n> file to let the users choose if they want to use \"exactly matches the\n> command the prompt script is trying to help\" version (i.e. rev-parse) vs\n> \"matches most of the time and faster under these conditions\" version\n> (i.e. the new logic).\n\nI'm not sure what you mean by opt-in.  It's already opt-in in the\nsense that users have to set $GIT_DISCOVERY_ACROSS_FILESYSTEM to\nenable this logic.  Or do you mean that\n$GIT_DISCOVERY_ACROSS_FILESYSTEM should not implicitly enable this\nlogic, but it should be controlled by a new dedicated variable?\n"},{"id":"191251","messageId":"7vsjf9ot9p.fsf@alter.siamese.dyndns.org","threadId":"30479","inReplyTo":"20120509223444.GH6958@goldbirke","subject":"Re: [PATCH 10/19] completion: use bash builtins to search for repository","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-05-09T22:59:30Z","receivedAt":"2012-05-09T22:59:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder@ira.uka.de> writes:\n\n> I'm not sure what you mean by opt-in.  It's already opt-in in the\n> sense that users have to set $GIT_DISCOVERY_ACROSS_FILESYSTEM to\n> enable this logic.  Or do you mean that\n> $GIT_DISCOVERY_ACROSS_FILESYSTEM should not implicitly enable this\n> logic, but it should be controlled by a new dedicated variable?\n\nExactly.  In the three words in DISCOVERY_ACROSS_FILESYSTEM, I do not see\nanything that indicates that the user wishes to use a \"may be faster in\nsome situations but may be less correct\" behaviour for one thing.  Also,\nsome day you or somebody else may find out how to take advantage of the\nnew code in this patch series and still stop at the filesystem boundary\nand at that point, people may want to still forbid git to go up across\nfilesystem boundary and want to use the new prompt code.  Tying these two\nindependent concepts (i.e. \"do I want to use the new experimental prompt\ncode?\" and \"do I want git to stop going up across fs boundaries?\")\ntogether only because the initial implementation happens to rely on it is\nnot such a good idea.\n"},{"id":"191268","messageId":"4FAB5B84.5050201@viscovery.net","threadId":"30479","inReplyTo":"7vzk9hrzwf.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 02/19] tests: add tests for the bash prompt functions in the completion script","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2012-05-10T06:09:08Z","receivedAt":"2012-05-10T06:09:08Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 5/9/2012 20:08, schrieb Junio C Hamano:\n> Would it be possible to arrange so that $TRASH_DIRECTORY, $TEST_DIRECTORY\n> and $PWD are set to c:/dir style paths in Windows environment?  What would\n> we break if we did so?\n\nI don't think that this is possible. The POSIX emulation in MSYS (or bash,\ndunno) always converts to POSIX style:\n\n> bash -c \"cd c:/temp; PWD=$(pwd -W); echo $PWD; cd $PWD; pwd; echo $PWD\"\nc:/temp\n/c/temp\n/c/temp\n\nThat is, even if I use Windows style path to chdir around, the result is\nPOSIX style.\n\n> The other direction of changing the Windows port of git to produce /c/dir\n> style paths would probably not work, as it would involve ripping out the\n> path mangling feature of bash in MSYS, which is done for some reason, I\n> presume.\n\nDoing that is certainly not something that I would be prepared to do just\nto make the bash prompt work right ;-) And the added maintainance burden\nincurred by the status quo is certainly much cheaper than yet another fork\nof MSYS and/or bash.\n\n-- Hannes\n"}]}