mirror of
https://gerrit.googlesource.com/git-repo
synced 2026-01-11 17:10:33 +00:00
Fix submodule initialization in interleaved sync mode
With the introduction of interleaved sync mode, the submodule activation logic broke because the 'has_submodules' attribute was no longer being populated when needed. With this change, each submodule is initialized when it enters the Sync_LocalHalf stage, whereas previously all submodules were initialized at once when the parent repository entered the Sync_LocalHalf stage. The init is now retried if it fails, as submodules may concurrently modify the parent’s git config, potentially causing contention when attempting to obtain a lock on it. This change makes the submodule activation logic more robust and less prone to breakage. Bug: 444366154 Change-Id: I25eca4ea2a6868219045cfa088988eb01ded47d2 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/509041 Reviewed-by: Gavin Mak <gavinmak@google.com> Tested-by: Kaushik Lingarkar <kaushikl@qti.qualcomm.com> Reviewed-by: Nasser Grainawi <nasser.grainawi@oss.qualcomm.com> Commit-Queue: Kaushik Lingarkar <kaushikl@qti.qualcomm.com> Reviewed-by: Scott Lee <ddoman@google.com>
This commit is contained in:
45
project.py
45
project.py
@@ -642,10 +642,6 @@ class Project:
|
||||
# project containing repo hooks.
|
||||
self.enabled_repo_hooks = []
|
||||
|
||||
# This will be updated later if the project has submodules and
|
||||
# if they will be synced.
|
||||
self.has_subprojects = False
|
||||
|
||||
def RelPath(self, local=True):
|
||||
"""Return the path for the project relative to a manifest.
|
||||
|
||||
@@ -1563,8 +1559,8 @@ class Project:
|
||||
# TODO(https://git-scm.com/docs/git-worktree#_bugs): Re-evaluate if
|
||||
# submodules can be init when using worktrees once its support is
|
||||
# complete.
|
||||
if self.has_subprojects and not self.use_git_worktrees:
|
||||
self._InitSubmodules()
|
||||
if self.parent and not self.use_git_worktrees:
|
||||
self._InitSubmodule()
|
||||
all_refs = self.bare_ref.all
|
||||
self.CleanPublishedCache(all_refs)
|
||||
revid = self.GetRevisionId(all_refs)
|
||||
@@ -2359,8 +2355,6 @@ class Project:
|
||||
)
|
||||
result.append(subproject)
|
||||
result.extend(subproject.GetDerivedSubprojects())
|
||||
if result:
|
||||
self.has_subprojects = True
|
||||
return result
|
||||
|
||||
def EnableRepositoryExtension(self, key, value="true", version=1):
|
||||
@@ -3030,16 +3024,39 @@ class Project:
|
||||
project=self.name,
|
||||
)
|
||||
|
||||
def _InitSubmodules(self, quiet=True):
|
||||
"""Initialize the submodules for the project."""
|
||||
def _InitSubmodule(self, quiet=True):
|
||||
"""Initialize the submodule."""
|
||||
cmd = ["submodule", "init"]
|
||||
if quiet:
|
||||
cmd.append("-q")
|
||||
if GitCommand(self, cmd).Wait() != 0:
|
||||
raise GitError(
|
||||
f"{self.name} submodule init",
|
||||
project=self.name,
|
||||
cmd.extend(["--", self.worktree])
|
||||
max_retries = 3
|
||||
base_delay_secs = 1
|
||||
jitter_ratio = 1 / 3
|
||||
for attempt in range(max_retries):
|
||||
git_cmd = GitCommand(
|
||||
None,
|
||||
cmd,
|
||||
cwd=self.parent.worktree,
|
||||
capture_stdout=True,
|
||||
capture_stderr=True,
|
||||
)
|
||||
if git_cmd.Wait() == 0:
|
||||
return
|
||||
error = git_cmd.stderr or git_cmd.stdout
|
||||
if "lock" in error:
|
||||
delay = base_delay_secs * (2**attempt)
|
||||
delay += random.uniform(0, delay * jitter_ratio)
|
||||
logger.warning(
|
||||
f"Attempt {attempt+1}/{max_retries}: "
|
||||
+ f"git {' '.join(cmd)} failed."
|
||||
+ f" Error: {error}."
|
||||
+ f" Sleeping {delay:.2f}s before retrying."
|
||||
)
|
||||
time.sleep(delay)
|
||||
else:
|
||||
break
|
||||
git_cmd.VerifyCommand()
|
||||
|
||||
def _Rebase(self, upstream, onto=None):
|
||||
cmd = ["rebase"]
|
||||
|
||||
Reference in New Issue
Block a user