summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorGavin Mak <gavinmak@google.com>2026-08-25 08:57:34 -0700
committergerrit-scoped@luci-project-accounts.iam.gserviceaccount.com <gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com>2026-09-21 13:40:01 -0700
commitf6f5946422097f2559cf3bc39a69d5fddc838ab8 (patch)
tree907c50c76bf1a0fc0d5d755913947c154ed09fe0 /tests
parent6321b26685ff9bdf5858e574dc4967761990ce5b (diff)
downloadgit-repo-f6f5946422097f2559cf3bc39a69d5fddc838ab8.tar.gz
project: avoid unnecessary sync revision enumeration
Skip the detached-history walk when its count will not be printed, ask rev-list --count for upstream gain, and cap the published-but-unmerged existence probe at one commit. These preserve the decisions while reducing traversal and output work. Bug: 553599402 Change-Id: I30f769c9aa5269428ece15ffcb45c50993d7c4b8 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/634004 Commit-Queue: Gavin Mak <gavinmak@google.com> Tested-by: Gavin Mak <gavinmak@google.com> Reviewed-by: Brian Gan <brgan@google.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/test_project.py97
1 files changed, 95 insertions, 2 deletions
diff --git a/tests/test_project.py b/tests/test_project.py
index ab20105fd..d02dabf3b 100644
--- a/tests/test_project.py
+++ b/tests/test_project.py
@@ -2248,6 +2248,97 @@ class StatelessSyncTests(unittest.TestCase):
2248 ) 2248 )
2249 proj._CopyAndLinkFiles.assert_called_once_with() 2249 proj._CopyAndLinkFiles.assert_called_once_with()
2250 2250
2251 def test_sync_local_half_skips_unused_detached_history_walk(self) -> None:
2252 """Non-verbose detached sync does not enumerate discarded commits."""
2253 with utils_for_test.TempGitTree() as tempdir:
2254 proj = self._get_project(tempdir)
2255 proj._InitWorkTree = mock.MagicMock()
2256 proj.CleanPublishedCache = mock.MagicMock()
2257 proj.GetRevisionId = mock.MagicMock(return_value="new")
2258 proj._Checkout = mock.MagicMock()
2259 proj._CopyAndLinkFiles = mock.MagicMock()
2260 proj.IsRebaseInProgress = mock.MagicMock(return_value=False)
2261 proj.IsCherryPickInProgress = mock.MagicMock(return_value=False)
2262 proj._revlist = mock.MagicMock()
2263 proj.bare_ref = mock.MagicMock()
2264 proj.bare_ref.all = {"HEAD": "old"}
2265 proj.bare_ref.head = "old"
2266 proj.work_git = mock.MagicMock()
2267 proj.work_git.GetHead.return_value = "old"
2268
2269 syncbuf = project.SyncBuffer(proj.config)
2270 proj.Sync_LocalHalf(syncbuf, verbose=False)
2271
2272 proj._revlist.assert_not_called()
2273 proj._Checkout.assert_called_once_with(
2274 "new", force_checkout=False, quiet=True
2275 )
2276
2277 def test_sync_local_half_verbose_detached_uses_count(self) -> None:
2278 """Verbose detached sync queries commit count with --count."""
2279 with utils_for_test.TempGitTree() as tempdir:
2280 proj = self._get_project(tempdir)
2281 proj._InitWorkTree = mock.MagicMock()
2282 proj.CleanPublishedCache = mock.MagicMock()
2283 proj.GetRevisionId = mock.MagicMock(return_value="new")
2284 proj._Checkout = mock.MagicMock()
2285 proj._CopyAndLinkFiles = mock.MagicMock()
2286 proj.IsRebaseInProgress = mock.MagicMock(return_value=False)
2287 proj.IsCherryPickInProgress = mock.MagicMock(return_value=False)
2288 proj._revlist = mock.MagicMock(return_value=["3"])
2289 proj.bare_ref = mock.MagicMock()
2290 proj.bare_ref.all = {"HEAD": "old"}
2291 proj.bare_ref.head = "old"
2292 proj.work_git = mock.MagicMock()
2293 proj.work_git.GetHead.return_value = "old"
2294
2295 syncbuf = mock.MagicMock()
2296 syncbuf.detach_head = False
2297 proj.Sync_LocalHalf(syncbuf, verbose=True)
2298
2299 proj._revlist.assert_called_once_with("--count", "^new", "HEAD")
2300 syncbuf.info.assert_called_once_with(
2301 proj, "discarding %d commits", 3
2302 )
2303
2304 def test_sync_local_half_uses_count_and_limit_for_published_branch(
2305 self,
2306 ) -> None:
2307 """Published sync uses --count for gain and -1 for probe."""
2308 with utils_for_test.TempGitTree() as tempdir:
2309 proj = self._get_project(tempdir)
2310 proj._InitWorkTree = mock.MagicMock()
2311 proj.CleanPublishedCache = mock.MagicMock()
2312 proj.GetRevisionId = mock.MagicMock(return_value="new")
2313 proj._CopyAndLinkFiles = mock.MagicMock()
2314 proj.IsRebaseInProgress = mock.MagicMock(return_value=False)
2315 proj.IsCherryPickInProgress = mock.MagicMock(return_value=False)
2316 proj._revlist = mock.MagicMock(side_effect=[["2"], ["pub-sha"]])
2317 proj.bare_ref = mock.MagicMock()
2318 proj.bare_ref.all = {"refs/heads/topic": "old"}
2319 proj.bare_ref.head = "refs/heads/topic"
2320 proj.work_git = mock.MagicMock()
2321 proj.work_git.GetHead.return_value = "refs/heads/topic"
2322 proj.work_git.merge_base.side_effect = project.GitError("diverged")
2323 branch = mock.MagicMock()
2324 branch.name = "topic"
2325 branch.LocalMerge = "refs/remotes/origin/main"
2326 proj.GetBranch = mock.MagicMock(return_value=branch)
2327 proj.WasPublished = mock.MagicMock(return_value="pub-sha")
2328
2329 syncbuf = mock.MagicMock()
2330 syncbuf.detach_head = False
2331 proj.Sync_LocalHalf(syncbuf, force_rebase=False)
2332
2333 self.assertEqual(
2334 proj._revlist.call_args_list,
2335 [
2336 mock.call("--count", "^HEAD", "new"),
2337 mock.call("-1", "^new", "pub-sha"),
2338 ],
2339 )
2340 syncbuf.fail.assert_called_once()
2341
2251 def test_sync_network_half_stateless_skips_if_stash(self): 2342 def test_sync_network_half_stateless_skips_if_stash(self):
2252 """Test stateless sync skips if stash exists.""" 2343 """Test stateless sync skips if stash exists."""
2253 with utils_for_test.TempGitTree() as tempdir: 2344 with utils_for_test.TempGitTree() as tempdir:
@@ -3351,9 +3442,11 @@ class ReprojectCmdTests(unittest.TestCase):
3351 def _revlist(*args: Any, **kwargs: Any) -> List[str]: 3442 def _revlist(*args: Any, **kwargs: Any) -> List[str]:
3352 if kwargs.get("format"): 3443 if kwargs.get("format"):
3353 return list(local_changes) 3444 return list(local_changes)
3354 if args[0] == project.not_rev(project.HEAD): 3445 if project.not_rev(project.HEAD) in args:
3446 if "--count" in args:
3447 return [str(len(upstream_gain))]
3355 return list(upstream_gain) 3448 return list(upstream_gain)
3356 if args[1] == self.PUB_ID: 3449 if self.PUB_ID in args:
3357 return [self.PUB_ID] 3450 return [self.PUB_ID]
3358 return [] 3451 return []
3359 3452