Skip to content

Commit 66685f0

Browse files
committed
Use 'gitfile' in submodule checkouts
This change takes another step towards ensuring Git can understand repo's submodules to some extent. Replace the old '.git' symlink with gitfile[1] pointing to the bare checkout of the submodule. This is required for Git's 'recurse submodules' opts to work with repo's submodules as '.git' is expected to be writable by Git when recursing over submodules. [1] https://git-scm.com/docs/gitrepository-layout#_description Change-Id: I52d15451768ee7bd6db289f4d2b3be5907370d42 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/446181 Tested-by: Kaushik Lingarkar <[email protected]> Reviewed-by: Josip Sokcevic <[email protected]> Reviewed-by: Mike Frysinger <[email protected]> Reviewed-by: Nasser Grainawi <[email protected]>
1 parent cf9a2a2 commit 66685f0

File tree

1 file changed

+42
-7
lines changed

1 file changed

+42
-7
lines changed

project.py

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3430,20 +3430,21 @@ def _InitWorkTree(self, force_sync=False, submodules=False):
34303430
self._InitGitWorktree()
34313431
self._CopyAndLinkFiles()
34323432
else:
3433+
# Remove old directory symbolic links for submodules.
3434+
if self.parent and platform_utils.islink(dotgit):
3435+
platform_utils.remove(dotgit)
3436+
init_dotgit = True
3437+
34333438
if not init_dotgit:
34343439
# See if the project has changed.
3435-
if os.path.realpath(self.gitdir) != os.path.realpath(dotgit):
3436-
platform_utils.remove(dotgit)
3440+
self._removeBadGitDirLink(dotgit)
34373441

34383442
if init_dotgit or not os.path.exists(dotgit):
3439-
os.makedirs(self.worktree, exist_ok=True)
3440-
platform_utils.symlink(
3441-
os.path.relpath(self.gitdir, self.worktree), dotgit
3442-
)
3443+
self._createDotGit(dotgit)
34433444

34443445
if init_dotgit:
34453446
_lwrite(
3446-
os.path.join(dotgit, HEAD), "%s\n" % self.GetRevisionId()
3447+
os.path.join(self.gitdir, HEAD), f"{self.GetRevisionId()}\n"
34473448
)
34483449

34493450
# Finish checking out the worktree.
@@ -3465,6 +3466,40 @@ def _InitWorkTree(self, force_sync=False, submodules=False):
34653466
self._SyncSubmodules(quiet=True)
34663467
self._CopyAndLinkFiles()
34673468

3469+
def _createDotGit(self, dotgit):
3470+
"""Initialize .git path.
3471+
3472+
For submodule projects, create a '.git' file using the gitfile
3473+
mechanism, and for the rest, create a symbolic link.
3474+
"""
3475+
os.makedirs(self.worktree, exist_ok=True)
3476+
if self.parent:
3477+
_lwrite(
3478+
dotgit,
3479+
f"gitdir: {os.path.relpath(self.gitdir, self.worktree)}\n",
3480+
)
3481+
else:
3482+
platform_utils.symlink(
3483+
os.path.relpath(self.gitdir, self.worktree), dotgit
3484+
)
3485+
3486+
def _removeBadGitDirLink(self, dotgit):
3487+
"""Verify .git is initialized correctly, otherwise delete it."""
3488+
if self.parent and os.path.isfile(dotgit):
3489+
with open(dotgit) as fp:
3490+
setting = fp.read()
3491+
if not setting.startswith("gitdir:"):
3492+
raise GitError(
3493+
f"'.git' in {self.worktree} must start with 'gitdir:'",
3494+
project=self.name,
3495+
)
3496+
gitdir = setting.split(":", 1)[1].strip()
3497+
dotgit_path = os.path.normpath(os.path.join(self.worktree, gitdir))
3498+
else:
3499+
dotgit_path = os.path.realpath(dotgit)
3500+
if os.path.realpath(self.gitdir) != dotgit_path:
3501+
platform_utils.remove(dotgit)
3502+
34683503
@classmethod
34693504
def _MigrateOldWorkTreeGitDir(cls, dotgit, project=None):
34703505
"""Migrate the old worktree .git/ dir style to a symlink.

0 commit comments

Comments
 (0)