* Don't use GIT_PREFIX when GIT_WORK_TREE=. because it seems git
  does not intend GIT_WORK_TREE to be relative to GIT_PREFIX in that
  case, despite GIT_WORK_TREE=.. being relative to GIT_PREFIX.
* Don't use GIT_PREFIX to fix up a relative GIT_DIR, because
  git 2.11 sets GIT_PREFIX set to a path it's not relative to.
  and apparently GIT_DIR is never relative to GIT_PREFIX.
Commit e50ed4ba48 led us down this path
by working around a git bug by relying on the barely documented GIT_PREFIX.
This commit was sponsored by Trenton Cronholm on Patreon.
		
	
			
		
			
				
	
	
		
			76 lines
		
	
	
	
		
			2.2 KiB
			
		
	
	
	
		
			Haskell
		
	
	
	
	
	
			
		
		
	
	
			76 lines
		
	
	
	
		
			2.2 KiB
			
		
	
	
	
		
			Haskell
		
	
	
	
	
	
{- The current git repository.
 | 
						|
 -
 | 
						|
 - Copyright 2012 Joey Hess <id@joeyh.name>
 | 
						|
 -
 | 
						|
 - Licensed under the GNU GPL version 3 or higher.
 | 
						|
 -}
 | 
						|
 | 
						|
module Git.CurrentRepo where
 | 
						|
 | 
						|
import Common
 | 
						|
import Git.Types
 | 
						|
import Git.Construct
 | 
						|
import qualified Git.Config
 | 
						|
import Utility.Env
 | 
						|
import Utility.Env.Set
 | 
						|
 | 
						|
{- Gets the current git repository.
 | 
						|
 -
 | 
						|
 - Honors GIT_DIR and GIT_WORK_TREE.
 | 
						|
 - Both environment variables are unset, to avoid confusing other git
 | 
						|
 - commands that also look at them. Instead, the Git module passes
 | 
						|
 - --work-tree and --git-dir to git commands it runs.
 | 
						|
 -
 | 
						|
 - When GIT_WORK_TREE or core.worktree are set, changes the working
 | 
						|
 - directory if necessary to ensure it is within the repository's work
 | 
						|
 - tree. While not needed for git commands, this is useful for anything
 | 
						|
 - else that looks for files in the worktree.
 | 
						|
 -
 | 
						|
 - Also works around a git bug when running some hooks. It
 | 
						|
 - runs the hooks in the top of the repository, but if GIT_WORK_TREE
 | 
						|
 - was relative (but not "."), it then points to the wrong directory.
 | 
						|
 - In this situation GIT_PREFIX contains the directory that 
 | 
						|
 - GIT_WORK_TREE is relative to.
 | 
						|
 -}
 | 
						|
get :: IO Repo
 | 
						|
get = do
 | 
						|
	gd <- getpathenv "GIT_DIR"
 | 
						|
	r <- configure gd =<< fromCwd
 | 
						|
	prefix <- getpathenv "GIT_PREFIX"
 | 
						|
	wt <- maybe (worktree $ location r) Just
 | 
						|
		<$> getpathenvprefix "GIT_WORK_TREE" prefix
 | 
						|
	case wt of
 | 
						|
		Nothing -> return r
 | 
						|
		Just d -> do
 | 
						|
			curr <- getCurrentDirectory
 | 
						|
			unless (d `dirContains` curr) $
 | 
						|
				setCurrentDirectory d
 | 
						|
			return $ addworktree wt r
 | 
						|
  where
 | 
						|
	getpathenv s = do
 | 
						|
		v <- getEnv s
 | 
						|
		case v of
 | 
						|
			Just d -> do
 | 
						|
				unsetEnv s
 | 
						|
				return (Just d)
 | 
						|
			Nothing -> return Nothing
 | 
						|
	
 | 
						|
	getpathenvprefix s (Just prefix) | not (null prefix) =
 | 
						|
		getpathenv s >>= \case
 | 
						|
			Nothing -> return Nothing
 | 
						|
			Just d
 | 
						|
				| d == "." -> return (Just d)
 | 
						|
				| otherwise -> Just <$> absPath (prefix </> d)
 | 
						|
	getpathenvprefix s _ = getpathenv s
 | 
						|
 | 
						|
	configure Nothing (Just r) = Git.Config.read r
 | 
						|
	configure (Just d) _ = do
 | 
						|
		absd <- absPath d
 | 
						|
		curr <- getCurrentDirectory
 | 
						|
		Git.Config.read $ newFrom $
 | 
						|
			Local { gitdir = absd, worktree = Just curr }
 | 
						|
	configure Nothing Nothing = giveup "Not in a git repository."
 | 
						|
 | 
						|
	addworktree w r = changelocation r $
 | 
						|
		Local { gitdir = gitdir (location r), worktree = w }
 | 
						|
	changelocation r l = r { location = l }
 |