Kaynağa Gözat

Merge branch 'fix-porcelain-fetch' of https://github.com/dandersson/dulwich

Jelmer Vernooij 7 yıl önce
ebeveyn
işleme
d69aa03b16
3 değiştirilmiş dosya ile 46 ekleme ve 20 silme
  1. 2 0
      NEWS
  2. 20 20
      dulwich/porcelain.py
  3. 24 0
      dulwich/tests/test_porcelain.py

+ 2 - 0
NEWS

@@ -19,6 +19,8 @@
 
   * Fix tutorial tests on Python 3. (Jelmer Vernooij, #573)
 
+  * Fix remote refs created by `porcelain.fetch`. (Daniel Andersson, #623)
+
 0.19.2	2018-04-07
 
  BUG FIXES

+ 20 - 20
dulwich/porcelain.py

@@ -318,22 +318,10 @@ def clone(source, target=None, bare=False, checkout=None,
         r = Repo.init_bare(target)
     else:
         r = Repo.init(target)
+
+    reflog_message = b'clone: from ' + source.encode('utf-8')
     try:
-        fetch_result = client.fetch(
-            host_path, r, determine_wants=r.object_store.determine_wants_all,
-            progress=errstream.write)
-        ref_message = b"clone: from " + source.encode('utf-8')
-        r.refs.import_refs(
-            b'refs/remotes/' + origin,
-            {n[len(b'refs/heads/'):]: v for (n, v) in fetch_result.refs.items()
-                if n.startswith(b'refs/heads/')},
-            message=ref_message)
-        r.refs.import_refs(
-            b'refs/tags',
-            {n[len(b'refs/tags/'):]: v for (n, v) in fetch_result.refs.items()
-                if n.startswith(b'refs/tags/') and
-                not n.endswith(ANNOTATED_TAG_SUFFIX)},
-            message=ref_message)
+        fetch_result = fetch(r, host_path, origin, message=reflog_message)
         target_config = r.get_config()
         if not isinstance(source, bytes):
             source = source.encode(DEFAULT_ENCODING)
@@ -345,7 +333,7 @@ def clone(source, target=None, bare=False, checkout=None,
         # TODO(jelmer): Support symref capability,
         # https://github.com/jelmer/dulwich/issues/485
         try:
-            head = r[fetch_result.refs[b"HEAD"]]
+            head = r[fetch_result[b'HEAD']]
         except KeyError:
             head = None
         else:
@@ -1070,7 +1058,7 @@ def branch_list(repo):
 
 
 def fetch(repo, remote_location, remote_name=b'origin', outstream=sys.stdout,
-          errstream=default_bytes_err_stream, **kwargs):
+          errstream=default_bytes_err_stream, message=None, **kwargs):
     """Fetch objects from a remote server.
 
     :param repo: Path to the repository
@@ -1078,14 +1066,26 @@ def fetch(repo, remote_location, remote_name=b'origin', outstream=sys.stdout,
     :param remote_name: Name for remote server
     :param outstream: Output stream (defaults to stdout)
     :param errstream: Error stream (defaults to stderr)
+    :param message: Reflog message (defaults to b"fetch: from <remote_name>")
     :return: Dictionary with refs on the remote
     """
+    if message is None:
+        message = b'fetch: from ' + remote_location.encode("utf-8")
     with open_repo_closing(repo) as r:
         client, path = get_transport_and_path(
-                remote_location, config=r.get_config_stack(), **kwargs)
+            remote_location, config=r.get_config_stack(), **kwargs)
         fetch_result = client.fetch(path, r, progress=errstream.write)
-        ref_name = b'refs/remotes/' + remote_name
-        r.refs.import_refs(ref_name, strip_peeled_refs(fetch_result.refs))
+        stripped_refs = strip_peeled_refs(fetch_result.refs)
+        branches = {
+            n[len(b'refs/heads/'):]: v for (n, v) in stripped_refs.items()
+            if n.startswith(b'refs/heads/')}
+        r.refs.import_refs(
+            b'refs/remotes/' + remote_name, branches, message=message)
+        tags = {
+            n[len(b'refs/tags/'):]: v for (n, v) in stripped_refs.items()
+            if n.startswith(b'refs/tags/') and
+            not n.endswith(ANNOTATED_TAG_SUFFIX)}
+        r.refs.import_refs(b'refs/tags', tags, message=message)
     return fetch_result.refs
 
 

+ 24 - 0
dulwich/tests/test_porcelain.py

@@ -1094,6 +1094,10 @@ class FetchTests(PorcelainTestCase):
         porcelain.fetch(target_path, self.repo.path,
                         outstream=outstream, errstream=errstream)
 
+        # Assert that fetch updated the local image of the remote
+        self.assert_correct_remote_refs(
+            target_repo.get_refs(), self.repo.get_refs())
+
         # Check the target repo for pushed changes
         with Repo(target_path) as r:
             self.assertTrue(self.repo[b'HEAD'].id in r)
@@ -1135,12 +1139,32 @@ class FetchTests(PorcelainTestCase):
         porcelain.fetch(target_path, self.repo.path, remote_name=remote_name,
                         outstream=outstream, errstream=errstream)
 
+        # Assert that fetch updated the local image of the remote
+        self.assert_correct_remote_refs(
+            target_repo.get_refs(), self.repo.get_refs())
+
         # Check the target repo for pushed changes, as well as updates
         # for the refs
         with Repo(target_path) as r:
             self.assertTrue(self.repo[b'HEAD'].id in r)
             self.assertNotEqual(self.repo.get_refs(), target_refs)
 
+    def assert_correct_remote_refs(
+            self, local_refs, remote_refs, remote_name=b'origin'):
+        """Assert that known remote refs corresponds to actual remote refs."""
+        local_ref_prefix = b'refs/heads'
+        remote_ref_prefix = b'refs/remotes/' + remote_name
+
+        locally_known_remote_refs = {
+            k[len(remote_ref_prefix) + 1:]: v for k, v in local_refs.items()
+            if k.startswith(remote_ref_prefix)}
+
+        normalized_remote_refs = {
+            k[len(local_ref_prefix) + 1:]: v for k, v in remote_refs.items()
+            if k.startswith(local_ref_prefix)}
+
+        self.assertEqual(locally_known_remote_refs, normalized_remote_refs)
+
 
 class RepackTests(PorcelainTestCase):