sync: reuse status HEAD in the bloat scan

The shallow-project bloat check already needs dirty state. Request
branch metadata in that same porcelain-v2 snapshot and use branch.oid
instead of launching a separate rev-parse, with the existing calls
retained as a fallback.

Bug: 543851900
Bug: 553599402
Change-Id: I3e7068c2e14c025a53adf92bfe8483b876cfda9d
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/632145
Tested-by: Gavin Mak <gavinmak@google.com>
Reviewed-by: Brian Gan <brgan@google.com>
Commit-Queue: Gavin Mak <gavinmak@google.com>
This commit is contained in:
Gavin Mak authored and gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com committed 2026-09-21 13:39:21 -07:00
1 parent c9448f986e
commit aaadd5da35
2 files changed
+52 -2

No files matched your search

+15 -2
View File
@@ -1614,10 +1614,23 @@ later is required to fix a server side protocol bug.
# Only check dirty or locally modified projects. These can't be
# freshly cloned and will accumulate garbage.
try:
is_dirty = project.IsDirty(consider_untracked=True)
status = project._GetStatusSnapshot(
untracked_files="normal", branch=True
)
if status is not None:
is_dirty = status.is_dirty(consider_untracked=True)
head_rev = status.branch_oid
else:
is_dirty = project.IsDirty(consider_untracked=True)
head_rev = project.work_git.rev_parse(HEAD)
if head_rev is None:
# Porcelain v2 reports an unborn branch as "(initial)". The
# legacy rev-parse path failed here and skipped the bloat
# calculation, so preserve that behavior.
return None
manifest_rev = project.GetRevisionId(project.bare_ref.all)
head_rev = project.work_git.rev_parse(HEAD)
has_local_commits = manifest_rev != head_rev
if not (is_dirty or has_local_commits):
+37
View File
@@ -30,6 +30,7 @@ import pytest
import command
from error import GitError
from error import RepoExitError
import git_status
import manifest_xml
from project import SyncNetworkHalfResult
from subcmds import sync
@@ -989,6 +990,42 @@ class CheckForBloatedProjects(unittest.TestCase):
self.cmd.git_event_log = mock.MagicMock()
self.cmd._bloated_projects = []
def test_one_project_reuses_status_head_oid(self) -> None:
"""The bloat scan gets dirty state and HEAD from one snapshot."""
status = git_status.StatusSnapshot()
status.branch_oid = "local"
self.project._GetStatusSnapshot.return_value = status
self.project.GetRevisionId.return_value = "manifest"
self.project.bare_git.count_objects.return_value = (
"packs: 0\nsize-pack: 0\nsize-garbage: 0\n"
)
with mock.patch.object(
sync.Sync,
"get_parallel_context",
return_value={"projects": [self.project]},
):
self.assertIsNone(self.cmd._CheckOneBloatedProject(0))
self.project.IsDirty.assert_not_called()
self.project.work_git.rev_parse.assert_not_called()
self.project.bare_git.count_objects.assert_called_once_with("-v")
def test_one_unborn_project_skips_bloat_check(self) -> None:
"""A porcelain initial branch behaves like failed rev-parse HEAD."""
status = git_status.StatusSnapshot()
status.index_changes["staged"] = git_status.StatusEntry("staged", "M")
self.project._GetStatusSnapshot.return_value = status
with mock.patch.object(
sync.Sync,
"get_parallel_context",
return_value={"projects": [self.project]},
):
self.assertIsNone(self.cmd._CheckOneBloatedProject(0))
self.project.GetRevisionId.assert_not_called()
self.project.bare_git.count_objects.assert_not_called()
@mock.patch("subcmds.sync.git_require")
def test_git_version_unsupported(self, mock_git_require):
"""Test that it returns early if git version is unsupported."""