sync: tell apart same-path submanifest projects

Interleaved sync remembers which projects are done and which ones are
still pending by Project.relpath, and lists failing projects by it as
well. That path is relative to the project's own (sub)manifest though,
so once several manifests are synced together two projects can share
it, and the sets no longer tell them apart.

The damage is done when a project turns up in a later pass, e.g. a
submodule that is only derived once its parent has been synced: its
path is already recorded as finished, so it is left out of every pass
that follows and never synced, while sync still reports success. With
an outer manifest holding

  <project name="a" path="a" sync-s="true"/>

where a carries a submodule at b, and a submanifest at sub/ holding

  <project name="sub-ab" path="a/b"/>

a fresh `repo sync` checks out sub/a/b but never a/b. Failing projects
are reported under the same ambiguous path, and the stall detection
merges them too.

Use RelPath(local=opt.this_manifest_only) instead, which is unique
within the set of projects being synced and is what GetProjects() and
the other subcommands already use.

Spotted during the review of I30395b8a16a9154f60972e1f408a066af64ba77c.

Change-Id: I5fa694b968774667be6060d9722cb57acbd2b579
Signed-off-by: kimhappy <hwanhee.kim@laplacian.cc>
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/622641
Reviewed-by: Gavin Mak <gavinmak@google.com>
Reviewed-by: Brian Gan <brgan@google.com>
This commit is contained in:
kimhappy authored and gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com committed 2026-09-01 19:13:52 -07:00
1 parent 0039e39000
commit c63a2f92fa
2 files changed
+120 -6

No files matched your search

+9 -4
View File
@@ -301,7 +301,8 @@ class _SyncResult(NamedTuple):
Attributes:
project_index (int): The index of the project in the shared list.
relpath (str): The project's relative path from the repo client top.
relpath (str): The project's path relative to the tree being synced.
Unlike Project.relpath, it is unique across submanifests.
remote_fetched (bool): True if the remote was actually queried.
fetch_success (bool): True if the fetch operation was successful.
fetch_errors (List[Exception]): The Exceptions from a failed fetch.
@@ -2869,7 +2870,7 @@ later is required to fix a server side protocol bug.
return _SyncResult(
project_index=project_index,
relpath=project.relpath,
relpath=project.RelPath(local=opt.this_manifest_only),
fetch_success=fetch_success,
remote_fetched=remote_fetched,
checkout_success=checkout_success,
@@ -3017,6 +3018,10 @@ later is required to fix a server side protocol bug.
self._interleaved_err_checkout = False
self._interleaved_err_checkout_results = []
# Project.relpath is relative to its own (sub)manifest, so it does not
# tell apart projects of different manifests being synced together.
_RelPath = lambda p: p.RelPath(local=opt.this_manifest_only)
err_event = multiprocessing.Event()
finished_relpaths = set()
project_list = list(all_projects)
@@ -3053,13 +3058,13 @@ later is required to fix a server side protocol bug.
projects_to_sync = [
p
for p in project_list
if p.relpath not in finished_relpaths
if _RelPath(p) not in finished_relpaths
]
if not projects_to_sync:
break
pending_relpaths = {
p.relpath for p in projects_to_sync
_RelPath(p) for p in projects_to_sync
}
if previously_pending_relpaths == pending_relpaths:
stalled_projects_str = "\n".join(