Avoid fetching ghosts in Repo.fetch.
authorJelmer Vernooij <jelmer@jelmer.uk>
Sat, 17 Nov 2018 18:16:45 +0000 (18:16 +0000)
committerJelmer Vernooij <jelmer@jelmer.uk>
Sat, 17 Nov 2018 18:16:45 +0000 (18:16 +0000)
NEWS
dulwich/repo.py
dulwich/tests/test_repository.py

diff --git a/NEWS b/NEWS
index 2a316f654b5e344ea4f0662acd203634bccfd049..1579e6e4de06299db62bfe1379119388762ddb6e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
 0.19.9 2018-11-06
 
+ * Avoid fetching ghosts in ``Repo.fetch``.
+   (Jelmer Vernooij)
+
  * Fix encoding when reading README file in setup.py.
    (egor <egor@sourced.tech>, #668)
 
index de6871dbdcf13f41e846cd06827540c641ead92b..f66caf5078a228175676b87fc8868c4bd6e81f0c 100644 (file)
@@ -73,6 +73,7 @@ from dulwich.hooks import (
     )
 
 from dulwich.refs import (  # noqa: F401
+    ANNOTATED_TAG_SUFFIX,
     check_ref_format,
     RefsContainer,
     DictRefsContainer,
@@ -317,7 +318,22 @@ class BaseRepo(object):
         if depth not in (None, 0):
             raise NotImplementedError("depth not supported yet")
 
-        wants = determine_wants(self.get_refs())
+        refs = {}
+        for ref, sha in self.get_refs().items():
+            try:
+                obj = self.object_store[sha]
+            except KeyError:
+                warnings.warn(
+                    'ref %s points at non-present sha %s' % (
+                        ref.decode('utf-8', 'replace'), sha.decode('ascii')),
+                    UserWarning)
+                continue
+            else:
+                if isinstance(obj, Tag):
+                    refs[ref + ANNOTATED_TAG_SUFFIX] = obj.object[1]
+                refs[ref] = sha
+
+        wants = determine_wants(refs)
         if not isinstance(wants, list):
             raise TypeError("determine_wants() did not return a list")
 
index 6a2e0e73629f7d7c4344c2d2d5cf3f401b9c5c6f..832661cebbcedad2dc8c379ea47cb7b69ff7d0d9 100644 (file)
@@ -266,6 +266,33 @@ class RepositoryRootTests(TestCase):
                 r.get_walker(b'2a72d929692c41d8554c07f6301757ba18a65d91')],
             [b'2a72d929692c41d8554c07f6301757ba18a65d91'])
 
+    def test_fetch(self):
+        r = self.open_repo('a.git')
+        tmp_dir = self.mkdtemp()
+        self.addCleanup(shutil.rmtree, tmp_dir)
+        t = Repo.init(tmp_dir)
+        r.fetch(t)
+        self.assertIn(b'a90fa2d900a17e99b433217e988c4eb4a2e9a097', t)
+        self.assertIn(b'a90fa2d900a17e99b433217e988c4eb4a2e9a097', t)
+        self.assertIn(b'a90fa2d900a17e99b433217e988c4eb4a2e9a097', t)
+        self.assertIn(b'28237f4dc30d0d462658d6b937b08a0f0b6ef55a', t)
+        self.assertIn(b'b0931cadc54336e78a1d980420e3268903b57a50', t)
+
+    def test_fetch_ignores_missing_refs(self):
+        r = self.open_repo('a.git')
+        missing = b'1234566789123456789123567891234657373833'
+        r.refs[b'refs/heads/blah'] = missing
+        tmp_dir = self.mkdtemp()
+        self.addCleanup(shutil.rmtree, tmp_dir)
+        t = Repo.init(tmp_dir)
+        r.fetch(t)
+        self.assertIn(b'a90fa2d900a17e99b433217e988c4eb4a2e9a097', t)
+        self.assertIn(b'a90fa2d900a17e99b433217e988c4eb4a2e9a097', t)
+        self.assertIn(b'a90fa2d900a17e99b433217e988c4eb4a2e9a097', t)
+        self.assertIn(b'28237f4dc30d0d462658d6b937b08a0f0b6ef55a', t)
+        self.assertIn(b'b0931cadc54336e78a1d980420e3268903b57a50', t)
+        self.assertNotIn(missing, t)
+
     def test_clone(self):
         r = self.open_repo('a.git')
         tmp_dir = self.mkdtemp()