Просмотр исходного кода

Fix AssertionError when accessing ref names with binary hash length

Fixes #2040
Jelmer Vernooij 3 недель назад
Родитель
Сommit
618eab6b71
3 измененных файлов с 30 добавлено и 7 удалено
  1. 3 0
      NEWS
  2. 16 7
      dulwich/repo.py
  3. 11 0
      tests/test_repository.py

+ 3 - 0
NEWS

@@ -1,5 +1,8 @@
 0.25.1	UNRELEASED
 
+ * Fix AssertionError when accessing ref names with length matching binary
+   hash length (e.g., 32 bytes for SHA-256). (Jelmer Vernooij, #2040)
+
  * Add ``parse_commit_broken`` function to parse broken commits.
    (Valentin Lorentz, Jelmer Vernooij)
 

+ 16 - 7
dulwich/repo.py

@@ -1197,18 +1197,27 @@ class BaseRepo:
         """
         if not isinstance(name, bytes):
             raise TypeError(f"'name' must be bytestring, not {type(name).__name__:.80}")
-        if len(name) in (20, 32, 40, 64):  # Support both SHA1 and SHA256
+        # If it looks like a ref name, only try refs
+        if name == b"HEAD" or name.startswith(b"refs/"):
+            try:
+                return self.object_store[self.refs[Ref(name)]]
+            except (RefFormatError, KeyError):
+                pass
+        # Otherwise, try as object ID if length matches
+        if len(name) in (
+            self.object_store.object_format.oid_length,
+            self.object_store.object_format.hex_length,
+        ):
             try:
-                # Try as ObjectID/RawObjectID
                 return self.object_store[
-                    ObjectID(name) if len(name) == 40 else RawObjectID(name)
+                    ObjectID(name)
+                    if len(name) == self.object_store.object_format.hex_length
+                    else RawObjectID(name)
                 ]
             except (KeyError, ValueError):
                 pass
-        try:
-            return self.object_store[self.refs[Ref(name)]]
-        except RefFormatError as exc:
-            raise KeyError(name) from exc
+        # If nothing worked, raise KeyError
+        raise KeyError(name)
 
     def __contains__(self, name: bytes) -> bool:
         """Check if a specific Git object or ref is present.

+ 11 - 0
tests/test_repository.py

@@ -292,6 +292,17 @@ class RepositoryRootTests(TestCase):
 
         self.assertRaises(ValueError, r.__delitem__, b"notrefs/foo")
 
+    def test_getitem_32_byte_ref(self) -> None:
+        """Test that accessing a ref name that's 32 bytes long works (issue #2040)."""
+        r = self.open_repo("a.git")
+        # Create a ref with exactly 32 bytes
+        ref_name = b"refs/heads/feat-backend-refactor"
+        self.assertEqual(len(ref_name), 32)
+        r[ref_name] = b"a90fa2d900a17e99b433217e988c4eb4a2e9a097"
+        # This should not raise AssertionError
+        obj = r[ref_name]
+        self.assertEqual(obj.id, b"a90fa2d900a17e99b433217e988c4eb4a2e9a097")
+
     def test_get_refs(self) -> None:
         r = self.open_repo("a.git")
         self.assertEqual(