/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/git/remote.py

  • Committer: Gustav Hartvigsson
  • Date: 2021-01-09 21:36:27 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20210109213627-h1xwcutzy9m7a99b
Added 'Case Preserving Working Tree Use Cases' from Canonical Wiki

* Addod a page from the Canonical Bazaar wiki
  with information on the scmeatics of case
  perserving filesystems an a case insensitive
  filesystem works.
  
  * Needs re-work, but this will do as it is the
    same inforamoton as what was on the linked
    page in the currint documentation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""Remote dirs, repositories and branches."""
18
18
 
19
 
from __future__ import absolute_import
20
 
 
21
19
import gzip
 
20
from io import BytesIO
22
21
import re
23
22
 
24
23
from .. import (
47
46
    PermissionDenied,
48
47
    UninitializableFormat,
49
48
    )
 
49
from ..revision import NULL_REVISION
50
50
from ..revisiontree import RevisionTree
51
 
from ..sixish import text_type
52
51
from ..transport import (
53
52
    Transport,
54
53
    register_urlparse_netloc_protocol,
56
55
 
57
56
from . import (
58
57
    lazy_check_versions,
 
58
    is_github_url,
59
59
    user_agent_for_github,
60
60
    )
61
61
lazy_check_versions()
76
76
    NoSuchRef,
77
77
    )
78
78
from .mapping import (
 
79
    encode_git_path,
79
80
    mapping_registry,
80
81
    )
81
82
from .object_store import (
86
87
    )
87
88
from .repository import (
88
89
    GitRepository,
 
90
    GitRepositoryFormat,
89
91
    )
90
92
from .refs import (
91
93
    branch_name_to_ref,
114
116
    )
115
117
import os
116
118
import select
117
 
import tempfile
118
119
 
119
 
try:
120
 
    import urllib.parse as urlparse
121
 
    from urllib.parse import splituser, splitnport
122
 
except ImportError:
123
 
    import urlparse
124
 
    from urllib import splituser, splitnport
 
120
import urllib.parse as urlparse
 
121
from urllib.parse import splituser
125
122
 
126
123
# urlparse only supports a limited number of schemes by default
127
124
register_urlparse_netloc_protocol('git')
160
157
    :param url: Git URL
161
158
    :return: Tuple with host, port, username, path.
162
159
    """
163
 
    (scheme, netloc, loc, _, _) = urlparse.urlsplit(url)
164
 
    path = urlparse.unquote(loc)
 
160
    parsed_url = urlparse.urlparse(url)
 
161
    path = urlparse.unquote(parsed_url.path)
165
162
    if path.startswith("/~"):
166
163
        path = path[1:]
167
 
    (username, hostport) = splituser(netloc)
168
 
    (host, port) = splitnport(hostport, None)
169
 
    return (host, port, username, path)
 
164
    return ((parsed_url.hostname or '', parsed_url.port, parsed_url.username, path))
170
165
 
171
166
 
172
167
class RemoteGitError(BzrError):
197
192
                message.endswith(' not found.'))):
198
193
        return NotBranchError(url, message)
199
194
    if message == "HEAD failed to update":
200
 
        base_url, _ = urlutils.split_segment_parameters(url)
 
195
        base_url = urlutils.strip_segment_parameters(url)
201
196
        return HeadUpdateFailed(base_url)
202
197
    if message.startswith('access denied or repository not exported:'):
203
 
        extra, path = message.split(': ', 1)
204
 
        return PermissionDenied(path, extra)
 
198
        extra, path = message.split(':', 1)
 
199
        return PermissionDenied(path.strip(), extra)
205
200
    if message.endswith('You are not allowed to push code to this project.'):
206
201
        return PermissionDenied(url, message)
207
202
    if message.endswith(' does not appear to be a git repository'):
208
203
        return NotBranchError(url, message)
 
204
    if message == 'pre-receive hook declined':
 
205
        return PermissionDenied(url, message)
 
206
    if re.match('(.+) is not a valid repository name',
 
207
                message.splitlines()[0]):
 
208
        return NotBranchError(url, message)
 
209
    if message == (
 
210
            'GitLab: You are not allowed to push code to protected branches '
 
211
            'on this project.'):
 
212
        return PermissionDenied(url, message)
209
213
    m = re.match(r'Permission to ([^ ]+) denied to ([^ ]+)\.', message)
210
214
    if m:
211
215
        return PermissionDenied(m.group(1), 'denied to %s' % m.group(2))
213
217
    return RemoteGitError(message)
214
218
 
215
219
 
 
220
def parse_git_hangup(url, e):
 
221
    """Parse the error lines from a git servers stderr on hangup.
 
222
 
 
223
    :param url: URL of the remote repository
 
224
    :param e: A HangupException
 
225
    """
 
226
    stderr_lines = getattr(e, 'stderr_lines', None)
 
227
    if not stderr_lines:
 
228
        return e
 
229
    if all(line.startswith(b'remote: ') for line in stderr_lines):
 
230
        stderr_lines = [
 
231
            line[len(b'remote: '):] for line in stderr_lines]
 
232
    interesting_lines = [
 
233
        line for line in stderr_lines
 
234
        if line and line.replace(b'=', b'')]
 
235
    if len(interesting_lines) == 1:
 
236
        interesting_line = interesting_lines[0]
 
237
        return parse_git_error(
 
238
            url, interesting_line.decode('utf-8', 'surrogateescape'))
 
239
    return RemoteGitError(
 
240
        b'\n'.join(stderr_lines).decode('utf-8', 'surrogateescape'))
 
241
 
 
242
 
216
243
class GitSmartTransport(Transport):
217
244
 
218
245
    def __init__(self, url, _client=None):
409
436
                write_error,
410
437
                format=(format.encode('ascii') if format else None),
411
438
                subdirs=subdirs,
412
 
                prefix=(prefix.encode('utf-8') if prefix else None))
 
439
                prefix=(encode_git_path(prefix) if prefix else None))
 
440
        except HangupException as e:
 
441
            raise parse_git_hangup(self.transport.external_url(), e)
413
442
        except GitProtocolError as e:
414
443
            raise parse_git_error(self.transport.external_url(), e)
415
444
        finally:
432
461
            self._refs = remote_refs_dict_to_container(
433
462
                result.refs, result.symrefs)
434
463
            return result
 
464
        except HangupException as e:
 
465
            raise parse_git_hangup(self.transport.external_url(), e)
435
466
        except GitProtocolError as e:
436
467
            raise parse_git_error(self.transport.external_url(), e)
437
468
        finally:
445
476
        else:
446
477
            pb = None
447
478
 
448
 
        def get_changed_refs_wrapper(refs):
449
 
            # TODO(jelmer): This drops symref information
450
 
            self._refs = remote_refs_dict_to_container(refs)
451
 
            return get_changed_refs(refs)
 
479
        def get_changed_refs_wrapper(remote_refs):
 
480
            if self._refs is not None:
 
481
                update_refs_container(self._refs, remote_refs)
 
482
            return get_changed_refs(remote_refs)
452
483
        try:
453
484
            return self._client.send_pack(
454
485
                self._client_path, get_changed_refs_wrapper,
455
486
                generate_pack_data, progress)
 
487
        except HangupException as e:
 
488
            raise parse_git_hangup(self.transport.external_url(), e)
456
489
        except GitProtocolError as e:
457
490
            raise parse_git_error(self.transport.external_url(), e)
458
491
        finally:
464
497
        refname = self._get_selected_ref(name, ref)
465
498
        if refname != b'HEAD' and refname in self.get_refs_container():
466
499
            raise AlreadyBranchError(self.user_url)
467
 
        if refname in self.get_refs_container():
468
 
            ref_chain, unused_sha = self.get_refs_container().follow(
469
 
                self._get_selected_ref(None))
470
 
            if ref_chain[0] == b'HEAD':
471
 
                refname = ref_chain[1]
 
500
        ref_chain, unused_sha = self.get_refs_container().follow(
 
501
            self._get_selected_ref(name))
 
502
        if ref_chain and ref_chain[0] == b'HEAD':
 
503
            refname = ref_chain[1]
472
504
        repo = self.open_repository()
473
505
        return RemoteGitBranch(self, repo, refname)
474
506
 
476
508
        refname = self._get_selected_ref(name)
477
509
 
478
510
        def get_changed_refs(old_refs):
479
 
            ret = dict(old_refs)
480
 
            if refname not in ret:
 
511
            ret = {}
 
512
            if refname not in old_refs:
481
513
                raise NotBranchError(self.user_url)
482
514
            ret[refname] = dulwich.client.ZERO_SHA
483
515
            return ret
484
516
 
485
517
        def generate_pack_data(have, want, ofs_delta=False):
486
518
            return pack_objects_to_data([])
487
 
        self.send_pack(get_changed_refs, generate_pack_data)
 
519
        result = self.send_pack(get_changed_refs, generate_pack_data)
 
520
        if result is not None and not isinstance(result, dict):
 
521
            error = result.ref_status.get(refname)
 
522
            if error:
 
523
                raise RemoteGitError(error)
488
524
 
489
525
    @property
490
526
    def user_url(self):
548
584
 
549
585
    def push_branch(self, source, revision_id=None, overwrite=False,
550
586
                    remember=False, create_prefix=False, lossy=False,
551
 
                    name=None):
 
587
                    name=None, tag_selector=None):
552
588
        """Push the source branch into this ControlDir."""
553
589
        if revision_id is None:
554
590
            # No revision supplied by the user, default to the branch
555
591
            # revision
556
592
            revision_id = source.last_revision()
 
593
        else:
 
594
            if not source.repository.has_revision(revision_id):
 
595
                raise NoSuchRevision(source, revision_id)
557
596
 
558
597
        push_result = GitPushResult()
559
598
        push_result.workingtree_updated = None
563
602
        push_result.branch_push_result = None
564
603
        repo = self.find_repository()
565
604
        refname = self._get_selected_ref(name)
 
605
        try:
 
606
            ref_chain, old_sha = self.get_refs_container().follow(refname)
 
607
        except NotBranchError:
 
608
            actual_refname = refname
 
609
            old_sha = None
 
610
        else:
 
611
            if ref_chain:
 
612
                actual_refname = ref_chain[-1]
 
613
            else:
 
614
                actual_refname = refname
566
615
        if isinstance(source, GitBranch) and lossy:
567
616
            raise errors.LossyPushToSameVCS(source.controldir, self)
568
617
        source_store = get_object_store(source.repository)
 
618
        fetch_tags = source.get_config_stack().get('branch.fetch_tags')
 
619
        def get_changed_refs(remote_refs):
 
620
            if self._refs is not None:
 
621
                update_refs_container(self._refs, remote_refs)
 
622
            ret = {}
 
623
            # TODO(jelmer): Unpeel if necessary
 
624
            push_result.new_original_revid = revision_id
 
625
            if lossy:
 
626
                new_sha = source_store._lookup_revision_sha1(revision_id)
 
627
            else:
 
628
                try:
 
629
                    new_sha = repo.lookup_bzr_revision_id(revision_id)[0]
 
630
                except errors.NoSuchRevision:
 
631
                    raise errors.NoRoundtrippingSupport(
 
632
                        source, self.open_branch(name=name, nascent_ok=True))
 
633
            if not overwrite:
 
634
                old_sha = remote_refs.get(actual_refname)
 
635
                if remote_divergence(old_sha, new_sha, source_store):
 
636
                    raise DivergedBranches(
 
637
                        source, self.open_branch(name, nascent_ok=True))
 
638
            ret[actual_refname] = new_sha
 
639
            if fetch_tags:
 
640
                for tagname, revid in source.tags.get_tag_dict().items():
 
641
                    if tag_selector and not tag_selector(tagname):
 
642
                        continue
 
643
                    if lossy:
 
644
                        try:
 
645
                            new_sha = source_store._lookup_revision_sha1(revid)
 
646
                        except KeyError:
 
647
                            if source.repository.has_revision(revid):
 
648
                                raise
 
649
                    else:
 
650
                        try:
 
651
                            new_sha = repo.lookup_bzr_revision_id(revid)[0]
 
652
                        except errors.NoSuchRevision:
 
653
                            continue
 
654
                        else:
 
655
                            if not source.repository.has_revision(revid):
 
656
                                continue
 
657
                    ret[tag_name_to_ref(tagname)] = new_sha
 
658
            return ret
569
659
        with source_store.lock_read():
570
 
            def get_changed_refs(refs):
571
 
                self._refs = remote_refs_dict_to_container(refs)
572
 
                ret = dict(refs)
573
 
                # TODO(jelmer): Unpeel if necessary
574
 
                push_result.new_original_revid = revision_id
 
660
            def generate_pack_data(have, want, progress=None,
 
661
                                   ofs_delta=True):
 
662
                git_repo = getattr(source.repository, '_git', None)
 
663
                if git_repo:
 
664
                    shallow = git_repo.get_shallow()
 
665
                else:
 
666
                    shallow = None
575
667
                if lossy:
576
 
                    new_sha = source_store._lookup_revision_sha1(revision_id)
 
668
                    return source_store.generate_lossy_pack_data(
 
669
                        have, want, shallow=shallow,
 
670
                        progress=progress, ofs_delta=ofs_delta)
 
671
                elif shallow:
 
672
                    return source_store.generate_pack_data(
 
673
                        have, want, shallow=shallow,
 
674
                        progress=progress, ofs_delta=ofs_delta)
577
675
                else:
578
 
                    try:
579
 
                        new_sha = repo.lookup_bzr_revision_id(revision_id)[0]
580
 
                    except errors.NoSuchRevision:
581
 
                        raise errors.NoRoundtrippingSupport(
582
 
                            source, self.open_branch(name=name, nascent_ok=True))
583
 
                if not overwrite:
584
 
                    if remote_divergence(ret.get(refname), new_sha,
585
 
                                         source_store):
586
 
                        raise DivergedBranches(
587
 
                            source, self.open_branch(name, nascent_ok=True))
588
 
                ret[refname] = new_sha
589
 
                return ret
590
 
            if lossy:
591
 
                generate_pack_data = source_store.generate_lossy_pack_data
592
 
            else:
593
 
                generate_pack_data = source_store.generate_pack_data
594
 
            new_refs = self.send_pack(get_changed_refs, generate_pack_data)
 
676
                    return source_store.generate_pack_data(
 
677
                        have, want, progress=progress, ofs_delta=ofs_delta)
 
678
            dw_result = self.send_pack(get_changed_refs, generate_pack_data)
 
679
            if not isinstance(dw_result, dict):
 
680
                new_refs = dw_result.refs
 
681
                error = dw_result.ref_status.get(actual_refname)
 
682
                if error:
 
683
                    raise RemoteGitError(error)
 
684
                for ref, error in dw_result.ref_status.items():
 
685
                    if error:
 
686
                        trace.warning('unable to open ref %s: %s',
 
687
                                      ref, error)
 
688
            else:  # dulwich < 0.20.4
 
689
                new_refs = dw_result
595
690
        push_result.new_revid = repo.lookup_foreign_revision_id(
596
 
            new_refs[refname])
597
 
        try:
598
 
            old_remote = self._refs[refname]
599
 
        except KeyError:
600
 
            old_remote = ZERO_SHA
601
 
        push_result.old_revid = repo.lookup_foreign_revision_id(old_remote)
602
 
        self._refs = remote_refs_dict_to_container(new_refs)
 
691
            new_refs[actual_refname])
 
692
        if old_sha is not None:
 
693
            push_result.old_revid = repo.lookup_foreign_revision_id(old_sha)
 
694
        else:
 
695
            push_result.old_revid = NULL_REVISION
 
696
        if self._refs is not None:
 
697
            update_refs_container(self._refs, new_refs)
603
698
        push_result.target_branch = self.open_branch(name)
604
 
        if old_remote != ZERO_SHA:
 
699
        if old_sha is not None:
605
700
            push_result.branch_push_result = GitBranchPushResult()
606
701
            push_result.branch_push_result.source_branch = source
607
702
            push_result.branch_push_result.target_branch = (
637
732
 
638
733
    def _idx_load_or_generate(self, path):
639
734
        if not os.path.exists(path):
640
 
            pb = ui.ui_factory.nested_progress_bar()
641
 
            try:
 
735
            with ui.ui_factory.nested_progress_bar() as pb:
642
736
                def report_progress(cur, total):
643
737
                    pb.update("generating index", cur, total)
644
 
                self.data.create_index(path,
645
 
                                       progress=report_progress)
646
 
            finally:
647
 
                pb.finished()
 
738
                self.data.create_index(path, progress=report_progress)
648
739
        return load_pack_index(path)
649
740
 
650
741
    def __del__(self):
660
751
 
661
752
    def __init__(self, transport, *args, **kwargs):
662
753
        self.transport = transport
663
 
        super(BzrGitHttpClient, self).__init__(
664
 
            transport.external_url(), *args, **kwargs)
 
754
        url = urlutils.URL.from_string(transport.external_url())
 
755
        url.user = url.quoted_user = None
 
756
        url.password = url.quoted_password = None
 
757
        url = urlutils.strip_segment_parameters(str(url))
 
758
        super(BzrGitHttpClient, self).__init__(url, *args, **kwargs)
665
759
 
666
760
    def _http_request(self, url, headers=None, data=None,
667
761
                      allow_compression=False):
676
770
            `redirect_location` properties, and `read` is a consumable read
677
771
            method for the response data.
678
772
        """
679
 
        from breezy.transport.http._urllib2_wrappers import Request
680
 
        headers['User-agent'] = user_agent_for_github()
 
773
        if is_github_url(url):
 
774
            headers['User-agent'] = user_agent_for_github()
681
775
        headers["Pragma"] = "no-cache"
682
776
        if allow_compression:
683
777
            headers["Accept-Encoding"] = "gzip"
684
778
        else:
685
779
            headers["Accept-Encoding"] = "identity"
686
780
 
687
 
        request = Request(
 
781
        response = self.transport.request(
688
782
            ('GET' if data is None else 'POST'),
689
 
            url, data, headers,
690
 
            accepted_errors=[200, 404])
691
 
        request.follow_redirections = True
692
 
 
693
 
        response = self.transport._perform(request)
694
 
 
695
 
        if response.code == 404:
 
783
            url,
 
784
            body=data,
 
785
            headers=headers, retries=8)
 
786
 
 
787
        if response.status == 404:
696
788
            raise NotGitRepository()
697
 
        elif response.code != 200:
 
789
        elif response.status != 200:
698
790
            raise GitProtocolError("unexpected http resp %d for %s" %
699
 
                                   (response.code, url))
 
791
                                   (response.status, url))
700
792
 
701
793
        # TODO: Optimization available by adding `preload_content=False` to the
702
794
        # request and just passing the `read` method on instead of going via
704
796
        # before issuing the next to still allow for connection reuse from the
705
797
        # pool.
706
798
        if response.getheader("Content-Encoding") == "gzip":
707
 
            read = gzip.GzipFile(fileobj=response).read
 
799
            read = gzip.GzipFile(fileobj=BytesIO(response.read())).read
708
800
        else:
709
801
            read = response.read
710
802
 
712
804
 
713
805
            def __init__(self, response):
714
806
                self._response = response
715
 
                self.status = response.code
 
807
                self.status = response.status
716
808
                self.content_type = response.getheader("Content-Type")
717
 
                self.redirect_location = response.geturl()
 
809
                self.redirect_location = response._actual.geturl()
718
810
 
719
811
            def readlines(self):
720
812
                return self._response.readlines()
721
813
 
722
814
            def close(self):
723
 
                self._response.close()
 
815
                pass
724
816
 
725
817
        return WrapResponse(response), read
726
818
 
727
819
 
 
820
def _git_url_and_path_from_transport(external_url):
 
821
    url = urlutils.strip_segment_parameters(external_url)
 
822
    return urlparse.urlsplit(url)
 
823
 
 
824
 
728
825
class RemoteGitControlDirFormat(GitControlDirFormat):
729
826
    """The .git directory control format."""
730
827
 
737
834
    def get_branch_format(self):
738
835
        return RemoteGitBranchFormat()
739
836
 
 
837
    @property
 
838
    def repository_format(self):
 
839
        return GitRepositoryFormat()
 
840
 
740
841
    def is_initializable(self):
741
842
        return False
742
843
 
747
848
        """Open this directory.
748
849
 
749
850
        """
750
 
        # we dont grok readonly - git isn't integrated with transport.
751
 
        url = transport.base
752
 
        if url.startswith('readonly+'):
753
 
            url = url[len('readonly+'):]
754
 
        scheme = urlparse.urlsplit(transport.external_url())[0]
 
851
        split_url = _git_url_and_path_from_transport(transport.external_url())
755
852
        if isinstance(transport, GitSmartTransport):
756
853
            client = transport._get_client()
757
 
            client_path = transport._get_path()
758
 
        elif scheme in ("http", "https"):
 
854
        elif split_url.scheme in ("http", "https"):
759
855
            client = BzrGitHttpClient(transport)
760
 
            client_path, _ = urlutils.split_segment_parameters(transport._path)
761
 
        elif scheme == 'file':
 
856
        elif split_url.scheme in ('file', ):
762
857
            client = dulwich.client.LocalGitClient()
763
 
            client_path = transport.local_abspath('.')
764
858
        else:
765
859
            raise NotBranchError(transport.base)
766
860
        if not _found:
767
861
            pass  # TODO(jelmer): Actually probe for something
768
 
        return RemoteGitDir(transport, self, client, client_path)
 
862
        return RemoteGitDir(transport, self, client, split_url.path)
769
863
 
770
864
    def get_format_description(self):
771
865
        return "Remote Git Repository"
797
891
        """
798
892
        commit = self._repository.lookup_bzr_revision_id(
799
893
            self.get_revision_id())[0]
 
894
        import tempfile
800
895
        f = tempfile.SpooledTemporaryFile()
801
896
        # git-upload-archive(1) generaly only supports refs. So let's see if we
802
897
        # can find one.
816
911
        f.seek(0)
817
912
        return osutils.file_iterator(f)
818
913
 
819
 
    def is_versioned(self, path, file_id=None):
 
914
    def is_versioned(self, path):
820
915
        raise GitSmartRemoteNotSupported(self.is_versioned, self)
821
916
 
822
917
    def has_filename(self, path):
823
918
        raise GitSmartRemoteNotSupported(self.has_filename, self)
824
919
 
825
 
    def get_file_text(self, path, file_id=None):
 
920
    def get_file_text(self, path):
826
921
        raise GitSmartRemoteNotSupported(self.get_file_text, self)
827
922
 
 
923
    def list_files(self, include_root=False, from_dir=None, recursive=True):
 
924
        raise GitSmartRemoteNotSupported(self.list_files, self)
 
925
 
828
926
 
829
927
class RemoteGitRepository(GitRepository):
830
928
 
 
929
    supports_random_access = False
 
930
 
831
931
    @property
832
932
    def user_url(self):
833
933
        return self.control_url
848
948
 
849
949
    def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref,
850
950
                      progress=None):
 
951
        import tempfile
851
952
        fd, path = tempfile.mkstemp(suffix=".pack")
852
953
        try:
853
954
            self.fetch_pack(determine_wants, graph_walker,
898
999
        ref = tag_name_to_ref(name)
899
1000
 
900
1001
        def get_changed_refs(old_refs):
901
 
            ret = dict(old_refs)
902
 
            if sha == dulwich.client.ZERO_SHA and ref not in ret:
 
1002
            ret = {}
 
1003
            if sha == dulwich.client.ZERO_SHA and ref not in old_refs:
903
1004
                raise NoSuchTag(name)
904
1005
            ret[ref] = sha
905
1006
            return ret
906
1007
 
907
1008
        def generate_pack_data(have, want, ofs_delta=False):
908
1009
            return pack_objects_to_data([])
909
 
        self.repository.send_pack(get_changed_refs, generate_pack_data)
 
1010
        result = self.repository.send_pack(
 
1011
            get_changed_refs, generate_pack_data)
 
1012
        if result and not isinstance(result, dict):
 
1013
            error = result.ref_status.get(ref)
 
1014
            if error:
 
1015
                raise RemoteGitError(error)
910
1016
 
911
1017
 
912
1018
class RemoteGitBranch(GitBranch):
976
1082
            if peeled is None:
977
1083
                # Let's just hope it's a commit
978
1084
                peeled = unpeeled
979
 
            if not isinstance(tag_name, text_type):
 
1085
            if not isinstance(tag_name, str):
980
1086
                raise TypeError(tag_name)
981
1087
            yield (ref_name, tag_name, peeled, unpeeled)
982
1088
 
990
1096
            return {self.ref: sha}
991
1097
        def generate_pack_data(have, want, ofs_delta=False):
992
1098
            return pack_objects_to_data([])
993
 
        self.repository.send_pack(get_changed_refs, generate_pack_data)
 
1099
        result = self.repository.send_pack(
 
1100
            get_changed_refs, generate_pack_data)
 
1101
        if result is not None and not isinstance(result, dict):
 
1102
            error = result.ref_status.get(self.ref)
 
1103
            if error:
 
1104
                raise RemoteGitError(error)
994
1105
        self._sha = sha
995
1106
 
996
1107
 
1007
1118
    ret = DictRefsContainer(base)
1008
1119
    ret._peeled = peeled
1009
1120
    return ret
 
1121
 
 
1122
 
 
1123
def update_refs_container(container, refs_dict):
 
1124
    peeled = {}
 
1125
    base = {}
 
1126
    for k, v in refs_dict.items():
 
1127
        if is_peeled(k):
 
1128
            peeled[k[:-3]] = v
 
1129
        else:
 
1130
            base[k] = v
 
1131
    container._peeled = peeled
 
1132
    container._refs.update(base)