'Upload a pack to a remote repository.
:param path: Repository path (as bytestring)
:param update_refs: Function to determine changes to remote refs.
Receive dict with existing remote refs, returns dict with
changed refs (name -> sha, where sha=ZERO_SHA for deletions)
:param generate_pack_contents: Function that can return a sequence of
the shas of the objects to upload.
:param progress: Optional progress function
:param write_pack: Function called with (file, iterable of objects) to
write the objects returned by generate_pack_contents to the server.
:raises SendPackError: if server rejects the pack data
:raises UpdateRefsError: if the server supports report-status
and rejects ref updates
:return: new_refs dictionary containing the changes that were made
{refname: new_ref}, including deleted refs.'

def send_pack(self, path, update_refs, generate_pack_contents, progress=None, write_pack=write_pack_objects):

    url = self._get_url(path)
    (old_refs, server_capabilities) = self._discover_references('git-receive-pack', url)
    negotiated_capabilities = self._negotiate_receive_pack_capabilities(server_capabilities)
    if (CAPABILITY_REPORT_STATUS in negotiated_capabilities):
        self._report_status_parser = ReportStatusParser()
    new_refs = update_refs(dict(old_refs))
    if (new_refs is None):
        return old_refs
    if self.dumb:
        raise NotImplementedError(self.fetch_pack)
    req_data = BytesIO()
    req_proto = Protocol(None, req_data.write)
    (have, want) = self._handle_receive_pack_head(req_proto, negotiated_capabilities, old_refs, new_refs)
    if ((not want) and set(new_refs.items()).issubset(set(old_refs.items()))):
        return new_refs
    objects = generate_pack_contents(have, want)
    if (len(objects) > 0):
        write_pack(req_proto.write_file(), objects)
    resp = self._smart_request('git-receive-pack', url, data=req_data.getvalue())
    try:
        resp_proto = Protocol(resp.read, None)
        self._handle_receive_pack_tail(resp_proto, negotiated_capabilities, progress)
        return new_refs
    finally:
        resp.close()
