Support git remotes where .git is a file, not a directory

Eg when --separate-git-dir was used, and core.symlinks=false.

This commit was sponsored by Brock Spratlen on Patreon.
This commit is contained in:
Joey Hess 2020-08-28 15:08:14 -04:00
parent cde3e5eb0c
commit 41ebed3941
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
4 changed files with 60 additions and 17 deletions

View file

@ -16,6 +16,8 @@ git-annex (8.20200815) UNRELEASED; urgency=medium
held by another process. held by another process.
* test: Stop gpg-agent daemons that are started for the test framework's * test: Stop gpg-agent daemons that are started for the test framework's
gpg key. gpg key.
* Support git remotes where .git is a file, not a directory,
eg when --separate-git-dir was used.
-- Joey Hess <id@joeyh.name> Fri, 14 Aug 2020 14:57:45 -0400 -- Joey Hess <id@joeyh.name> Fri, 14 Aug 2020 14:57:45 -0400

View file

@ -1,6 +1,6 @@
{- Construction of Git Repo objects {- Construction of Git Repo objects
- -
- Copyright 2010-2012 Joey Hess <id@joeyh.name> - Copyright 2010-2020 Joey Hess <id@joeyh.name>
- -
- Licensed under the GNU AGPL version 3 or higher. - Licensed under the GNU AGPL version 3 or higher.
-} -}
@ -73,7 +73,7 @@ fromAbsPath dir
, ret (takeDirectory canondir) , ret (takeDirectory canondir)
) )
| otherwise = ifM (doesDirectoryExist dir) | otherwise = ifM (doesDirectoryExist dir)
( ret dir ( gitDirFile dir >>= maybe (ret dir) (pure . newFrom)
-- git falls back to dir.git when dir doesn't -- git falls back to dir.git when dir doesn't
-- exist, as long as dir didn't end with a -- exist, as long as dir didn't end with a
-- path separator -- path separator
@ -198,7 +198,7 @@ expandTilde = expandt True
checkForRepo :: FilePath -> IO (Maybe RepoLocation) checkForRepo :: FilePath -> IO (Maybe RepoLocation)
checkForRepo dir = checkForRepo dir =
check isRepo $ check isRepo $
check gitDirFile $ check (gitDirFile dir) $
check isBareRepo $ check isBareRepo $
return Nothing return Nothing
where where
@ -217,22 +217,26 @@ checkForRepo dir =
gitSignature (".git" </> "gitdir") gitSignature (".git" </> "gitdir")
isBareRepo = checkdir $ gitSignature "config" isBareRepo = checkdir $ gitSignature "config"
<&&> doesDirectoryExist (dir </> "objects") <&&> doesDirectoryExist (dir </> "objects")
gitDirFile = do
-- git-submodule, git-worktree, and --separate-git-dir
-- make .git be a file pointing to the real git directory.
c <- firstLine <$>
catchDefaultIO "" (readFile $ dir </> ".git")
return $ if gitdirprefix `isPrefixOf` c
then Just $ Local
{ gitdir = toRawFilePath $ absPathFrom dir $
drop (length gitdirprefix) c
, worktree = Just (toRawFilePath dir)
}
else Nothing
where
gitdirprefix = "gitdir: "
gitSignature file = doesFileExist $ dir </> file gitSignature file = doesFileExist $ dir </> file
-- git-submodule, git-worktree, and --separate-git-dir
-- make .git be a file pointing to the real git directory.
-- Detect that, and return a RepoLocation with gitdir pointing
-- to the real git directory.
gitDirFile :: FilePath -> IO (Maybe RepoLocation)
gitDirFile dir = do
c <- firstLine <$>
catchDefaultIO "" (readFile $ dir </> ".git")
return $ if gitdirprefix `isPrefixOf` c
then Just $ Local
{ gitdir = toRawFilePath $ absPathFrom dir $
drop (length gitdirprefix) c
, worktree = Just (toRawFilePath dir)
}
else Nothing
where
gitdirprefix = "gitdir: "
newFrom :: RepoLocation -> Repo newFrom :: RepoLocation -> Repo
newFrom l = Repo newFrom l = Repo
{ location = l { location = l

View file

@ -178,3 +178,5 @@ shaddy@jazz-debian:~/slaveproj$ ls -lL services
### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders) ### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)
This issue is not a show stopper. I otherwise love the concepts behind git-annex very much. This issue is not a show stopper. I otherwise love the concepts behind git-annex very much.
> [[fixed|done]] --[[Joey]]

View file

@ -0,0 +1,35 @@
[[!comment format=mdwn
username="joey"
subject="""comment 1"""
date="2020-08-28T18:03:46Z"
content="""
--separate-git-dir makes eg, masterproj/.git be a file that contains the
path to the git dir.
git-annex init converts such a .git file to a symlink. That is necessary
for git-annex symlinks to be resolved, since they always link to files
inside .git, and if it's a file, the symlinks won't point to the object
files.
On windows, since core.symlinks is false, it does not make that change.
So, I think the problem might be that, when .git is a file rather
than a symlink, git-annex in the clone doesn't read the .git file to determine
the real git repo location, and so can't find annexed files in its remote.
Seem to have found a way to produce the same problem on linux:
* git init --separate-git-dir masterproj.git masterproj
* cd masterproj; git config core.symlinks false
* git-annex init
* add file, commit, make clone
git-annex get in the clone then fails
openat(AT_FDCWD, "../masterproj/.git/annex/objects/3f/3K/SHA256E-s30--32a7ec5a2905bbeda54a699ed797c96c1fea7b5bc31a6cc104b2ddefe65a95bb/SHA256E-s30--32a7ec5a2905bbeda54a699ed797c96c1fea7b5bc31a6cc104b2ddefe65a95bb", O_RDONLY) = -1 ENOTDIR (Not a directory)
So, I think it would make sense for git-annex to notice when
a remote's .git is a file rather than a directory, and adjust the remote
accordingly, so it uses its actual git directory. That will solve
this situation.
"""]]