git-annex/Git/Index.hs
Joey Hess 097605e2e9
git's handing of relative GIT_INDEX_FILE is more insane than I thought; always make absolute
This is actually worse than I thought; when git is being run with a
detached work tree, GIT_INDEX_FILE is treated as a path relative to CWD,
instead of the normal behavior of relative the top of the work tree.

This seems to make it basically impossible for any program that wants to
use GIT_INDEX_FILE to use anything other than an absolute path to it; there
are too many configurations to keep straight that can change how git
interprets what should be a simple relative path to a file.

(I have complained to the git developers.)
2016-05-22 15:02:55 -04:00

70 lines
2 KiB
Haskell

{- git index file stuff
-
- Copyright 2011 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module Git.Index where
import Common
import Git
import Utility.Env
indexEnv :: String
indexEnv = "GIT_INDEX_FILE"
{- Gets value to set GIT_INDEX_FILE to. Input should be absolute path,
- or relative to the CWD.
-
- When relative, GIT_INDEX_FILE is interpreted by git as being
- relative to the top of the work tree of the git repository,
- not to the CWD. Worse, other environment variables (GIT_WORK_TREE)
- or git options (--work-tree) or configuration (core.worktree)
- can change what the relative path is interpreted relative to.
-
- So, an absolute path is the only safe option for this to return.
-}
indexEnvVal :: FilePath -> IO String
indexEnvVal = absPath
{- Forces git to use the specified index file.
-
- Returns an action that will reset back to the default
- index file.
-
- Warning: Not thread safe.
-}
override :: FilePath -> Repo -> IO (IO ())
override index _r = do
res <- getEnv var
val <- indexEnvVal index
setEnv var val True
return $ reset res
where
var = "GIT_INDEX_FILE"
reset (Just v) = setEnv indexEnv v True
reset _ = unsetEnv var
indexFile :: Repo -> FilePath
indexFile r = localGitDir r </> "index"
{- Git locks the index by creating this file. -}
indexFileLock :: Repo -> FilePath
indexFileLock r = indexFile r ++ ".lock"
{- When the pre-commit hook is run, and git commit has been run with
- a file or files specified to commit, rather than committing the staged
- index, git provides the pre-commit hook with a "false index file".
-
- Changes made to this index will influence the commit, but won't
- affect the real index file.
-
- This detects when we're in this situation, using a heuristic, which
- might be broken by changes to git. Any use of this should have a test
- case to make sure it works.
-}
haveFalseIndex :: IO Bool
haveFalseIndex = maybe (False) check <$> getEnv indexEnv
where
check f = "next-index" `isPrefixOf` takeFileName f