فهرست منبع

dumb: Ensure to fetch HEAD ref or basic clone is failing

Git objects could be fetched when using porcelain.clone but the
default branch could not be set as HEAD reference was missing.
Antoine Lambert 1 ماه پیش
والد
کامیت
0eb5ca9909
4فایلهای تغییر یافته به همراه30 افزوده شده و 2 حذف شده
  1. 4 2
      dulwich/client.py
  2. 11 0
      dulwich/dumb.py
  3. 9 0
      tests/compat/test_dumb.py
  4. 6 0
      tests/test_client.py

+ 4 - 2
dulwich/client.py

@@ -2813,9 +2813,9 @@ class AbstractHttpGitClient(GitClient):
             wants = determine_wants(refs)
         if wants is not None:
             wants = [cid for cid in wants if cid != ZERO_SHA]
-        if not wants:
+        if not wants and not self.dumb:
             return FetchPackResult(refs, symrefs, agent)
-        if self.dumb:
+        elif self.dumb:
             # Use dumb HTTP protocol
             from .dumb import DumbRemoteHTTPRepo
 
@@ -2829,6 +2829,8 @@ class AbstractHttpGitClient(GitClient):
                 )
             )
 
+            symrefs[b"HEAD"] = dumb_repo.get_head()
+
             # Write pack data
             if pack_data:
                 from .pack import write_pack_data

+ 11 - 0
dulwich/dumb.py

@@ -398,6 +398,17 @@ class DumbRemoteHTTPRepo(BaseRepo):
 
         return dict(self._refs)
 
+    def get_head(self) -> Ref:
+        head_resp_bytes = self._fetch_url("HEAD")
+        head_split = head_resp_bytes.replace(b"\n", b"").split(b" ")
+        head_target = head_split[1] if len(head_split) > 1 else head_split[0]
+        # handle HEAD legacy format containing a commit id instead of a ref name
+        for ref_name, ret_target in self.get_refs().items():
+            if ret_target == head_target:
+                head_target = ref_name
+                break
+        return head_target
+
     def get_peeled(self, ref: Ref) -> ObjectID:
         """Get the peeled value of a ref."""
         # For dumb HTTP, we don't have peeled refs readily available

+ 9 - 0
tests/compat/test_dumb.py

@@ -29,6 +29,7 @@ from http.server import HTTPServer, SimpleHTTPRequestHandler
 from unittest import skipUnless
 
 from dulwich.client import HttpGitClient
+from dulwich.porcelain import clone
 from dulwich.repo import Repo
 from tests.compat.utils import (
     CompatTestCase,
@@ -144,6 +145,14 @@ class DumbHTTPClientTests(CompatTestCase):
         self.server.start()
         self.addCleanup(self.server.stop)
 
+    @skipUnless(
+        sys.platform != "win32", "git clone from Python HTTPServer fails on Windows"
+    )
+    def test_clone_dumb(self):
+        dest_path = os.path.join(self.temp_dir, "cloned")
+        repo = clone(self.server.url, dest_path)
+        assert b"HEAD" in repo
+
     def test_clone_from_dumb_http(self):
         """Test cloning from a dumb HTTP server."""
         dest_path = os.path.join(self.temp_dir, "cloned")

+ 6 - 0
tests/test_client.py

@@ -1305,6 +1305,7 @@ class HttpGitClientTests(TestCase):
         info_refs_content = (
             b"0123456789abcdef0123456789abcdef01234567\trefs/heads/master\n"
         )
+        head_content = b"ref: refs/heads/master"
 
         # Create a blob object for testing
         blob_content = b"Hello, dumb HTTP!"
@@ -1316,6 +1317,11 @@ class HttpGitClientTests(TestCase):
         blob_compressed = zlib.compress(blob_obj_data)
 
         responses = {
+            "/HEAD": {
+                "status": 200,
+                "content": head_content,
+                "content_type": "text/plain",
+            },
             "/git-upload-pack": {
                 "status": 404,
                 "content": b"Not Found",