Sync: Fix full submodule sync while shallow specified

Git allows to clone submodules as shallow clone [1]. On the other
hand, when repo synchronize a projcet with submodules inside, it
ignores the shallow parameter.

When a project contains submodules, project.py parses the .gitmodules
file for URL and path. This parsing does not consider the shallow
option. Consequently, this parameter is not propgated to newly
created Project instance for that submodule.

[1] https://git-scm.com/docs/gitmodules#Documentation/gitmodules.txt-submoduleltnamegtshallow

Change-Id: I54fc9c69ae1b8e3cda2801202e3f0c7693b718d2
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/454261
Tested-by: Albert Akmukhametov <alb.02057@gmail.com>
Commit-Queue: Albert Akmukhametov <alb.02057@gmail.com>
Reviewed-by: Josip Sokcevic <sokcevic@chromium.org>
Reviewed-by: Никита Сказкоподателев (Nask) <skazkopodatelev@gmail.com>
This commit is contained in:
Albert Akmukhametov 2025-02-17 17:04:42 +03:00 committed by LUCI
parent fc901b92bb
commit 4b94e773ef

View File

@ -2197,24 +2197,27 @@ class Project:
def get_submodules(gitdir, rev):
# Parse .gitmodules for submodule sub_paths and sub_urls.
sub_paths, sub_urls = parse_gitmodules(gitdir, rev)
sub_paths, sub_urls, sub_shallows = parse_gitmodules(gitdir, rev)
if not sub_paths:
return []
# Run `git ls-tree` to read SHAs of submodule object, which happen
# to be revision of submodule repository.
sub_revs = git_ls_tree(gitdir, rev, sub_paths)
submodules = []
for sub_path, sub_url in zip(sub_paths, sub_urls):
for sub_path, sub_url, sub_shallow in zip(
sub_paths, sub_urls, sub_shallows
):
try:
sub_rev = sub_revs[sub_path]
except KeyError:
# Ignore non-exist submodules.
continue
submodules.append((sub_rev, sub_path, sub_url))
submodules.append((sub_rev, sub_path, sub_url, sub_shallow))
return submodules
re_path = re.compile(r"^submodule\.(.+)\.path=(.*)$")
re_url = re.compile(r"^submodule\.(.+)\.url=(.*)$")
re_shallow = re.compile(r"^submodule\.(.+)\.shallow=(.*)$")
def parse_gitmodules(gitdir, rev):
cmd = ["cat-file", "blob", "%s:.gitmodules" % rev]
@ -2228,9 +2231,9 @@ class Project:
gitdir=gitdir,
)
except GitError:
return [], []
return [], [], []
if p.Wait() != 0:
return [], []
return [], [], []
gitmodules_lines = []
fd, temp_gitmodules_path = tempfile.mkstemp()
@ -2247,16 +2250,17 @@ class Project:
gitdir=gitdir,
)
if p.Wait() != 0:
return [], []
return [], [], []
gitmodules_lines = p.stdout.split("\n")
except GitError:
return [], []
return [], [], []
finally:
platform_utils.remove(temp_gitmodules_path)
names = set()
paths = {}
urls = {}
shallows = {}
for line in gitmodules_lines:
if not line:
continue
@ -2270,10 +2274,16 @@ class Project:
names.add(m.group(1))
urls[m.group(1)] = m.group(2)
continue
m = re_shallow.match(line)
if m:
names.add(m.group(1))
shallows[m.group(1)] = m.group(2)
continue
names = sorted(names)
return (
[paths.get(name, "") for name in names],
[urls.get(name, "") for name in names],
[shallows.get(name, "") for name in names],
)
def git_ls_tree(gitdir, rev, paths):
@ -2314,7 +2324,7 @@ class Project:
# If git repo does not exist yet, querying its submodules will
# mess up its states; so return here.
return result
for rev, path, url in self._GetSubmodules():
for rev, path, url, shallow in self._GetSubmodules():
name = self.manifest.GetSubprojectName(self, path)
(
relpath,
@ -2336,6 +2346,7 @@ class Project:
review=self.remote.review,
revision=self.remote.revision,
)
clone_depth = 1 if shallow.lower() == "true" else None
subproject = Project(
manifest=self.manifest,
name=name,
@ -2352,6 +2363,7 @@ class Project:
sync_s=self.sync_s,
sync_tags=self.sync_tags,
parent=self,
clone_depth=clone_depth,
is_derived=True,
)
result.append(subproject)