From: Johannes Schindelin <johannes.schinde...@gmx.de>

Since v2.9.0, Git knows about the config variable core.hookspath
that allows overriding the path to the directory containing the
Git hooks.

Since v2.10.0, the `--git-path` option respects that config
variable, too, so we may just as well use that command.

For Git versions older than v2.5.0 (which was the first version to
support the `--git-path` option for the `rev-parse` command), we
simply fall back to the previous code.

An original patch handled only the hooksPath setting, however, during
the code submission it was deemed better to fix all call to the `gitdir`
function.

To avoid spawning a gazillion `git rev-parse --git-path` instances, we
cache the returned paths, priming the cache upon startup in a single
`git rev-parse invocation` with the known entries.

This fixes https://github.com/git-for-windows/git/issues/1755

Initial-patch-by: Philipp Gortan <phil...@gortan.org>
Signed-off-by: Johannes Schindelin <johannes.schinde...@gmx.de>
---
 git-gui.sh | 52 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 49 insertions(+), 3 deletions(-)

diff --git a/git-gui.sh b/git-gui.sh
index fd476b6999..8b72e59cd0 100755
--- a/git-gui.sh
+++ b/git-gui.sh
@@ -158,6 +158,7 @@ if {[tk windowingsystem] eq "aqua"} {
 
 set _appname {Git Gui}
 set _gitdir {}
+array set _gitdir_cache {}
 set _gitworktree {}
 set _isbare {}
 set _gitexec {}
@@ -197,12 +198,57 @@ proc appname {} {
        return $_appname
 }
 
+proc prime_gitdir_cache {} {
+       global _gitdir _gitdir_cache
+
+       set gitdir_cmd [list git rev-parse --git-dir]
+
+       # `--git-path` is only supported since Git v2.5.0
+       if {[package vcompare $::_git_version 2.5.0] >= 0} {
+               set gitdir_keys [list \
+                       CHERRY_PICK_HEAD FETCH_HEAD GITGUI_BCK GITGUI_EDITMSG \
+                       GITGUI_MSG HEAD hooks hooks/prepare-commit-msg \
+                       index.lock info info/exclude logs MERGE_HEAD MERGE_MSG \
+                       MERGE_RR objects "objects/4\[0-1\]/*" \
+                       "objects/4\[0-3\]/*" objects/info \
+                       objects/info/alternates objects/pack packed-refs \
+                       PREPARE_COMMIT_MSG rebase-merge/head-name remotes \
+                       rr-cache rr-cache/MERGE_RR SQUASH_MSG \
+               ]
+
+               foreach key $gitdir_keys {
+                       lappend gitdir_cmd --git-path $key
+               }
+       }
+
+       set i -1
+       foreach path [split [eval $gitdir_cmd] "\n"] {
+               if {$i eq -1} {
+                       set _gitdir $path
+               } else {
+                       set _gitdir_cache([lindex $gitdir_keys $i]) $path
+               }
+               incr i
+       }
+}
+
 proc gitdir {args} {
-       global _gitdir
+       global _gitdir _gitdir_cache
+
        if {$args eq {}} {
                return $_gitdir
        }
-       return [eval [list file join $_gitdir] $args]
+
+       set args [eval [list file join] $args]
+       if {![info exists _gitdir_cache($args)]} {
+               if {[package vcompare $::_git_version 2.5.0] >= 0} {
+                       set _gitdir_cache($args) [git rev-parse --git-path 
$args]
+               } else {
+                       set _gitdir_cache($args) [file join $_gitdir $args]
+               }
+       }
+
+       return $_gitdir_cache($args)
 }
 
 proc gitexec {args} {
@@ -1242,7 +1288,7 @@ if {[catch {
        && [catch {
                # beware that from the .git dir this sets _gitdir to .
                # and _prefix to the empty string
-               set _gitdir [git rev-parse --git-dir]
+               prime_gitdir_cache
                set _prefix [git rev-parse --show-prefix]
        } err]} {
        load_config 1
-- 
gitgitgadget

Reply via email to