summaryrefslogtreecommitdiffstats
path: root/subcmds/sync.py
diff options
context:
space:
mode:
authorkimhappy <hwanhee.kim@laplacian.cc>2026-08-27 03:04:10 +0900
committergerrit-scoped@luci-project-accounts.iam.gserviceaccount.com <gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com>2026-08-27 16:22:43 -0700
commit3a6e25af7537181aae251951b8aabe7748c3aee5 (patch)
tree5000ea657357c0c50fa4176aa48775e7d41d6a86 /subcmds/sync.py
parent41c2597509e3e2228688668fbfb2d8bcfb5891b1 (diff)
downloadgit-repo-3a6e25af7537181aae251951b8aabe7748c3aee5.tar.gz
sync: check out submodules at the parent's new revision
Interleaved sync processes projects in hierarchical levels, so a submodule is only handled after the project holding its gitlink has been fetched and checked out. Its revision, however, is still the one read before that parent was fetched, so the submodule is synced to the revision of the previous sync and only catches up on the next one. Read the gitlinks again right before a level is dispatched. The parent is done by then, so its submodules are fetched and checked out at the revision the parent now points at. Sibling submodules are spread over several levels, so the gitlinks read for one level are carried over to the next ones and every project is only read once per pass. Bug: 550074864 Change-Id: I30395b8a16a9154f60972e1f408a066af64ba77c Signed-off-by: kimhappy <hwanhee.kim@laplacian.cc> Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/621662 Reviewed-by: Gavin Mak <gavinmak@google.com> Reviewed-by: Brian Gan <brgan@google.com>
Diffstat (limited to 'subcmds/sync.py')
-rw-r--r--subcmds/sync.py47
1 files changed, 46 insertions, 1 deletions
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 6a8853088..af123995a 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -28,7 +28,7 @@ import subprocess
28import sys 28import sys
29import tempfile 29import tempfile
30import time 30import time
31from typing import List, NamedTuple, Optional, Set, Tuple, Union 31from typing import Dict, List, NamedTuple, Optional, Set, Tuple, Union
32import urllib.error 32import urllib.error
33import urllib.parse 33import urllib.parse
34import urllib.request 34import urllib.request
@@ -156,6 +156,46 @@ def _SafeCheckoutOrder(checkouts: List[Project]) -> List[List[Project]]:
156 return res 156 return res
157 157
158 158
159def _RefreshDerivedRevisions(
160 projects: List[Project],
161 submodule_revisions: Optional[Dict[Project, Dict[str, str]]] = None,
162) -> None:
163 """Re-resolve the gitlinks of the discovered submodules in |projects|.
164
165 The revision of a discovered submodule is read from its parent when the
166 manifest is loaded, so it is stale as soon as the parent gets fetched. It
167 has to be resolved again once the parent is up-to-date, and before the
168 submodule itself is fetched and checked out.
169
170 Args:
171 projects: The projects whose discovered submodules to resolve.
172 submodule_revisions: Gitlinks already read, keyed by the project
173 holding them. Passing the same dict for project sets that follow
174 the same fetches, e.g. the levels of one checkout order, keeps a
175 project from being read more than once.
176 """
177 if submodule_revisions is None:
178 submodule_revisions = {}
179
180 subprojects_by_parent = collections.defaultdict(list)
181 for project in projects:
182 if project.Derived and project.parent:
183 subprojects_by_parent[project.parent].append(project)
184
185 for parent, subprojects in subprojects_by_parent.items():
186 revisions = submodule_revisions.get(parent)
187 if revisions is None:
188 revisions = parent.GetSubmoduleRevisions()
189 if revisions is None:
190 # Leave the submodules of a parent we cannot read alone.
191 continue
192 submodule_revisions[parent] = revisions
193 for subproject in subprojects:
194 rev = revisions.get(subproject.gitlink_path)
195 if rev:
196 subproject.SetRevision(rev, revisionId=rev)
197
198
159def _chunksize(projects: int, jobs: int) -> int: 199def _chunksize(projects: int, jobs: int) -> int:
160 """Calculate chunk size for the given number of projects and jobs.""" 200 """Calculate chunk size for the given number of projects and jobs."""
161 return min(max(1, projects // jobs), WORKER_BATCH_SIZE) 201 return min(max(1, projects // jobs), WORKER_BATCH_SIZE)
@@ -2977,12 +3017,17 @@ later is required to fix a server side protocol bug.
2977 # projects in one level can be processed in 3017 # projects in one level can be processed in
2978 # parallel, but we must wait for a level to complete 3018 # parallel, but we must wait for a level to complete
2979 # before starting the next. 3019 # before starting the next.
3020 submodule_revisions = {}
2980 for level_projects in _SafeCheckoutOrder( 3021 for level_projects in _SafeCheckoutOrder(
2981 projects_to_sync 3022 projects_to_sync
2982 ): 3023 ):
2983 if not level_projects: 3024 if not level_projects:
2984 continue 3025 continue
2985 3026
3027 _RefreshDerivedRevisions(
3028 level_projects, submodule_revisions
3029 )
3030
2986 objdir_project_map = collections.defaultdict( 3031 objdir_project_map = collections.defaultdict(
2987 list 3032 list
2988 ) 3033 )