diff --git a/plugin/fugitive.vim b/plugin/fugitive.vim
index 2d9816b187009cad92d224f141fd43eed5cebc72..279289d6cae2081efddfa51a596b760cdc204c5a 100644
--- a/plugin/fugitive.vim
+++ b/plugin/fugitive.vim
@@ -145,6 +145,13 @@ function! fugitive#extract_git_dir(path) abort
     if root ==# $GIT_WORK_TREE && fugitive#is_git_dir($GIT_DIR)
       return $GIT_DIR
     endif
+    if fugitive#is_git_dir($GIT_DIR)
+      " Ensure that we've cached the worktree
+      call s:configured_tree($GIT_DIR)
+      if has_key(s:dir_for_worktree, root)
+        return s:dir_for_worktree[root]
+      endif
+    endif
     let dir = s:sub(root, '[\/]$', '') . '/.git'
     let type = getftype(dir)
     if type ==# 'dir' && fugitive#is_git_dir(dir)
@@ -211,6 +218,8 @@ augroup END
 
 let s:repo_prototype = {}
 let s:repos = {}
+let s:worktree_for_dir = {}
+let s:dir_for_worktree = {}
 
 function! s:repo(...) abort
   let dir = a:0 ? a:1 : (exists('b:git_dir') && b:git_dir !=# '' ? b:git_dir : fugitive#extract_git_dir(expand('%:p')))
@@ -234,21 +243,23 @@ function! s:repo_dir(...) dict abort
   return join([self.git_dir]+a:000,'/')
 endfunction
 
-function! s:repo_configured_tree() dict abort
-  if !has_key(self,'_tree')
-    let self._tree = ''
-    if filereadable(self.dir('config'))
-      let config = readfile(self.dir('config'),'',10)
+function! s:configured_tree(git_dir) abort
+  if !has_key(s:worktree_for_dir, a:git_dir)
+    let s:worktree_for_dir[a:git_dir] = ''
+    let config_file = a:git_dir . '/config'
+    if filereadable(config_file)
+      let config = readfile(config_file,'',10)
       call filter(config,'v:val =~# "^\\s*worktree *="')
       if len(config) == 1
-        let self._tree = matchstr(config[0], '= *\zs.*')
+        let s:worktree_for_dir[a:git_dir] = matchstr(config[0], '= *\zs.*')
+        let s:dir_for_worktree[s:worktree_for_dir[a:git_dir]] = a:git_dir
       endif
     endif
   endif
-  if self._tree =~# '^\.'
-    return simplify(self.dir(self._tree))
+  if s:worktree_for_dir[a:git_dir] =~# '^\.'
+    return simplify(a:git_dir . '/' . s:worktree_for_dir[a:git_dir])
   else
-    return self._tree
+    return s:worktree_for_dir[a:git_dir]
   endif
 endfunction
 
@@ -256,7 +267,7 @@ function! s:repo_tree(...) dict abort
   if self.dir() =~# '/\.git$'
     let dir = self.dir()[0:-6]
   else
-    let dir = self.configured_tree()
+    let dir = s:configured_tree(self.git_dir)
   endif
   if dir ==# ''
     call s:throw('no work tree')
@@ -269,7 +280,7 @@ function! s:repo_bare() dict abort
   if self.dir() =~# '/\.git$'
     return 0
   else
-    return self.configured_tree() ==# ''
+    return s:configured_tree(self.git_dir) ==# ''
   endif
 endfunction
 
@@ -334,7 +345,7 @@ function! s:repo_head(...) dict abort
     return branch
 endfunction
 
-call s:add_methods('repo',['dir','configured_tree','tree','bare','translate','head'])
+call s:add_methods('repo',['dir','tree','bare','translate','head'])
 
 function! s:repo_git_command(...) dict abort
   let git = g:fugitive_git_executable . ' --git-dir='.s:shellesc(self.git_dir)