sync: trim preciousObjects work

Only set preciousObjects when objdir differs from gitdir, check actual
objdir sharing in _GetPreciousObjectsState, and skip post-sync
preciousObjects scans on unshared --use-local-gitdirs projects.

Bug: 543101585
Change-Id: I5077aed128f22cf19f520c7866cfd62f0c2724be
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/652266
Tested-by: Gavin Mak <gavinmak@google.com>
Commit-Queue: Gavin Mak <gavinmak@google.com>
Reviewed-by: Brian Gan <brgan@google.com>
This commit is contained in:
Gavin Mak authored and gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com committed 2026-11-12 14:51:41 -08:00
1 parent c85e5ff8a5
commit c9cfb541aa
3 files changed
+60 -13

No files matched your search

+1 -1
View File
@@ -4490,7 +4490,7 @@ class Project:
if tmp_gitdir:
platform_utils.rename(tmp_gitdir, self.gitdir)
tmp_gitdir = None
if not init_obj_dir:
if not init_obj_dir and self.objdir != self.gitdir:
# The project might be shared (obj_dir already initialized), but
# such information is not available here. Instead of passing it,
# set it as shared, and rely to be unset down the execution
+22 -12
View File
@@ -1563,22 +1563,20 @@ later is required to fix a server side protocol bug.
if len(projects) == 1:
return False
if len(projects) > 1:
# Objects are potentially shared with another project.
if project.UseAlternates:
return False
# Objects are shared when another project uses the same objdir.
# See the logic in Project.Sync_NetworkHalf regarding UseAlternates.
# - When False, shared projects share (via symlink)
# .repo/project-objects/{PROJECT_NAME}.git as the one-and-only
# objects directory. All objects are precious, since there is no
# project with a complete set of refs.
# - When False and projects share .repo/project-objects/{NAME}.git
# as the one-and-only objects directory, all objects are precious
# since no project has a complete set of refs. Projects with
# distinct local .git directories (--use-local-gitdirs) do not
# share objects even when their manifest names match.
# - When True, shared projects share (via info/alternates)
# .repo/project-objects/{PROJECT_NAME}.git as an alternate object
# store, which is written only on the first clone of the project,
# and is not written subsequently. (When Sync_NetworkHalf sees
# that it exists, it makes sure that the alternates file points
# there, and uses a project-local .git/objects directory for all
# syncs going forward.
# We do not support switching between the options. The environment
# variable is present for testing and migration only.
return not project.UseAlternates
# and is not written subsequently.
return sum(1 for p in projects if p.objdir == project.objdir) > 1
return False
@@ -1649,6 +1647,18 @@ later is required to fix a server side protocol bug.
if not opt.auto_gc:
# Just repair preciousObjects state, and return.
for project in projects:
if (
project.manifest.UseLocalGitDirs is True
and not project.parent
and getattr(project, "gitdir", None) == project.objdir
and len(
project.manifest.GetProjectsWithName(
project.name, all_manifests=True
)
)
== 1
):
continue
cls._SetPreciousObjectsState(project, opt)
return
+37
View File
@@ -1374,6 +1374,20 @@ class GetPreciousObjectsState(unittest.TestCase):
self.cmd._GetPreciousObjectsState(self.project, self.opt)
)
def test_duplicate_name_distinct_objdirs(self) -> None:
"""Duplicate-name projects with distinct local objdirs aren't shared."""
other = mock.MagicMock(
use_git_worktrees=False, UseAlternates=False, objdir="b/.git"
)
self.project.objdir = "a/.git"
self.project.manifest.GetProjectsWithName.return_value = [
self.project,
other,
]
self.assertFalse(
self.cmd._GetPreciousObjectsState(self.project, self.opt)
)
class KeyboardInterruptTest(unittest.TestCase):
"""Tests for KeyboardInterrupt handling in Sync operations."""
@@ -1626,6 +1640,29 @@ class GCProjectsTest(unittest.TestCase):
mock_set_state.assert_called_once_with(self.project, self.opt)
self.assertFalse(self.project.bare_git.gc.called)
def test_GCProjects_skip_unshared_local_gitdirs(self) -> None:
"""Unshared --use-local-gitdirs projects skip preciousObjects scan."""
self.opt.auto_gc = False
self.project.parent = None
self.project.gitdir = "work/.git"
self.project.objdir = "work/.git"
self.project.manifest.UseLocalGitDirs = True
self.project.manifest.GetProjectsWithName.return_value = [self.project]
dup = mock.MagicMock()
dup.name = "dup"
dup.parent = None
dup.gitdir = "dup1/.git"
dup.objdir = "dup1/.git"
dup.manifest.UseLocalGitDirs = True
dup.manifest.GetProjectsWithName.return_value = [dup, mock.MagicMock()]
with mock.patch.object(
sync.Sync, "_SetPreciousObjectsState"
) as mock_set_state:
self.cmd._GCProjects([self.project, dup], self.opt, mock.Mock())
mock_set_state.assert_called_once_with(dup, self.opt)
@mock.patch.object(progress, "Progress")
def test_GCProjects_sequential(self, mock_progress):
"""Test sequential GC (jobs < 2)."""