mirror of
https://gerrit.googlesource.com/git-repo
synced 2026-06-03 00:19:52 +00:00
project: Avoid skipping fetches for shallow clones without .git/shallow
When optimizing fetches for projects with immutable revisions, the fetch should not be skipped if the project is configured for a shallow clone (depth > 0) but the .git/shallow file is missing. The absence of the .git/shallow file means the repository is not a shallow clone, or the shallow clone is incomplete, so a fetch is necessary to ensure the revision is present. Bug: 503081454 Change-Id: Ic3549612bcd69050a926652ee4e522c79ad8124c Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/573821 Tested-by: Becky Siegel <beckysiegel@google.com> Reviewed-by: Gavin Mak <gavinmak@google.com> Commit-Queue: Becky Siegel <beckysiegel@google.com>
This commit is contained in:
@@ -1495,6 +1495,10 @@ class Project:
|
|||||||
and self._CheckForImmutableRevision(
|
and self._CheckForImmutableRevision(
|
||||||
use_superproject=use_superproject
|
use_superproject=use_superproject
|
||||||
)
|
)
|
||||||
|
and (
|
||||||
|
not depth
|
||||||
|
or os.path.exists(os.path.join(self.gitdir, "shallow"))
|
||||||
|
)
|
||||||
):
|
):
|
||||||
remote_fetched = True
|
remote_fetched = True
|
||||||
try:
|
try:
|
||||||
@@ -2616,6 +2620,9 @@ class Project:
|
|||||||
if is_sha1 or tag_name is not None:
|
if is_sha1 or tag_name is not None:
|
||||||
if self._CheckForImmutableRevision(
|
if self._CheckForImmutableRevision(
|
||||||
use_superproject=use_superproject
|
use_superproject=use_superproject
|
||||||
|
) and (
|
||||||
|
not depth
|
||||||
|
or os.path.exists(os.path.join(self.gitdir, "shallow"))
|
||||||
):
|
):
|
||||||
if verbose:
|
if verbose:
|
||||||
print(
|
print(
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
@@ -683,3 +684,113 @@ class StatelessSyncTests(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertTrue(res.success)
|
self.assertTrue(res.success)
|
||||||
self.assertFalse(getattr(proj, "stateless_prune_needed", False))
|
self.assertFalse(getattr(proj, "stateless_prune_needed", False))
|
||||||
|
|
||||||
|
|
||||||
|
class SyncOptimizationTests(unittest.TestCase):
|
||||||
|
"""Tests for sync optimization logic involving shallow clones."""
|
||||||
|
|
||||||
|
def _get_project(self, tempdir, depth=None):
|
||||||
|
manifest = mock.MagicMock()
|
||||||
|
manifest.manifestProject.depth = depth
|
||||||
|
manifest.manifestProject.dissociate = False
|
||||||
|
manifest.manifestProject.clone_filter = None
|
||||||
|
manifest.is_multimanifest = False
|
||||||
|
manifest.manifestProject.config.GetBoolean.return_value = False
|
||||||
|
manifest.IsMirror = False
|
||||||
|
|
||||||
|
remote = mock.MagicMock()
|
||||||
|
remote.name = "origin"
|
||||||
|
remote.url = "http://"
|
||||||
|
|
||||||
|
proj = project.Project(
|
||||||
|
manifest=manifest,
|
||||||
|
name="test-project",
|
||||||
|
remote=remote,
|
||||||
|
gitdir=os.path.join(tempdir, "gitdir"),
|
||||||
|
objdir=os.path.join(tempdir, "objdir"),
|
||||||
|
worktree=tempdir,
|
||||||
|
relpath="test-project",
|
||||||
|
revisionExpr="0123456789abcdef0123456789abcdef01234567",
|
||||||
|
revisionId=None,
|
||||||
|
)
|
||||||
|
proj._CheckForImmutableRevision = mock.MagicMock(return_value=True)
|
||||||
|
proj.DeleteWorktree = mock.MagicMock()
|
||||||
|
proj._InitGitDir = mock.MagicMock()
|
||||||
|
proj._InitRemote = mock.MagicMock()
|
||||||
|
proj._InitMRef = mock.MagicMock()
|
||||||
|
return proj
|
||||||
|
|
||||||
|
def test_sync_network_half_shallow_missing_fetches(self):
|
||||||
|
"""Test Sync_NetworkHalf fetches if shallow file is missing."""
|
||||||
|
with utils_for_test.TempGitTree() as tempdir:
|
||||||
|
proj = self._get_project(tempdir, depth=1)
|
||||||
|
# Ensure gitdir does not exist to simulate new project
|
||||||
|
if os.path.exists(proj.gitdir):
|
||||||
|
shutil.rmtree(proj.gitdir)
|
||||||
|
shallow_path = os.path.join(proj.gitdir, "shallow")
|
||||||
|
if os.path.exists(shallow_path):
|
||||||
|
os.unlink(shallow_path)
|
||||||
|
|
||||||
|
proj._RemoteFetch = mock.MagicMock(return_value=True)
|
||||||
|
|
||||||
|
res = proj.Sync_NetworkHalf(optimized_fetch=True)
|
||||||
|
|
||||||
|
self.assertTrue(res.success)
|
||||||
|
proj._RemoteFetch.assert_called_once()
|
||||||
|
|
||||||
|
def test_sync_network_half_shallow_exists_skips(self):
|
||||||
|
"""Test Sync_NetworkHalf skips fetch if shallow file exists."""
|
||||||
|
with utils_for_test.TempGitTree() as tempdir:
|
||||||
|
proj = self._get_project(tempdir, depth=1)
|
||||||
|
os.makedirs(proj.gitdir, exist_ok=True)
|
||||||
|
os.makedirs(proj.objdir, exist_ok=True)
|
||||||
|
with open(os.path.join(proj.gitdir, "shallow"), "w") as f:
|
||||||
|
f.write("")
|
||||||
|
|
||||||
|
proj._RemoteFetch = mock.MagicMock()
|
||||||
|
|
||||||
|
res = proj.Sync_NetworkHalf(optimized_fetch=True)
|
||||||
|
|
||||||
|
self.assertTrue(res.success)
|
||||||
|
proj._RemoteFetch.assert_not_called()
|
||||||
|
|
||||||
|
def test_remote_fetch_shallow_missing_fetches(self):
|
||||||
|
"""Test _RemoteFetch fetches if shallow file is missing."""
|
||||||
|
with utils_for_test.TempGitTree() as tempdir:
|
||||||
|
proj = self._get_project(tempdir, depth=1)
|
||||||
|
shallow_path = os.path.join(proj.gitdir, "shallow")
|
||||||
|
if os.path.exists(shallow_path):
|
||||||
|
os.unlink(shallow_path)
|
||||||
|
|
||||||
|
with mock.patch("project.GitCommand") as mock_git_cmd:
|
||||||
|
mock_cmd_instance = mock.MagicMock()
|
||||||
|
mock_cmd_instance.Wait.return_value = 0
|
||||||
|
mock_git_cmd.return_value = mock_cmd_instance
|
||||||
|
|
||||||
|
res = proj._RemoteFetch(
|
||||||
|
current_branch_only=True,
|
||||||
|
depth=1,
|
||||||
|
use_superproject=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertTrue(res)
|
||||||
|
mock_git_cmd.assert_called()
|
||||||
|
|
||||||
|
def test_remote_fetch_shallow_exists_skips(self):
|
||||||
|
"""Test _RemoteFetch skips fetch if shallow file exists."""
|
||||||
|
with utils_for_test.TempGitTree() as tempdir:
|
||||||
|
proj = self._get_project(tempdir, depth=1)
|
||||||
|
os.makedirs(proj.gitdir, exist_ok=True)
|
||||||
|
os.makedirs(proj.objdir, exist_ok=True)
|
||||||
|
with open(os.path.join(proj.gitdir, "shallow"), "w") as f:
|
||||||
|
f.write("")
|
||||||
|
|
||||||
|
with mock.patch("project.GitCommand") as mock_git_cmd:
|
||||||
|
res = proj._RemoteFetch(
|
||||||
|
current_branch_only=True,
|
||||||
|
depth=1,
|
||||||
|
use_superproject=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertTrue(res)
|
||||||
|
mock_git_cmd.assert_not_called()
|
||||||
|
|||||||
Reference in New Issue
Block a user