Mercurial > hg-git
diff git_handler.py @ 230:51e4d6ebbc40
rework pushing to support --rev and --force options
author | Abderrahim Kitouni <a.kitouni@gmail.com> |
---|---|
date | Thu, 30 Jul 2009 22:09:53 +0100 |
parents | f2c2061aacd1 |
children | bdaec2a079ce |
line wrap: on
line diff
--- a/git_handler.py Tue Jul 28 23:12:38 2009 +0100 +++ b/git_handler.py Thu Jul 30 22:09:53 2009 +0100 @@ -1,6 +1,7 @@ import os, sys, math, urllib, re import toposort +from dulwich.errors import HangupException from dulwich.index import commit_tree from dulwich.objects import Blob, Commit, Tag, Tree, format_timezone from dulwich.pack import create_delta, apply_delta @@ -122,9 +123,9 @@ self.update_references() self.save_map() - def push(self, remote): + def push(self, remote, revs, force): self.export_commits() - changed_refs = self.upload_pack(remote) + changed_refs = self.upload_pack(remote, revs, force) remote_name = self.remote_name(remote) if remote_name and changed_refs: @@ -479,70 +480,54 @@ ## PACK UPLOADING AND FETCHING - def upload_pack(self, remote): + def upload_pack(self, remote, revs, force): client, path = self.get_transport_and_path(remote) - changed = self.get_changed_refs + def changed(refs): + to_push = revs or set(self.local_heads().values() + self.tags.values()) + if not to_push and refs.keys()[0] == 'capabilities^{}': + to_push = [self.repo.lookup('tip')] + return self.get_changed_refs(refs, to_push, force) + genpack = self.git.object_store.generate_pack_contents try: self.ui.status(_("creating and sending data\n")) changed_refs = client.send_pack(path, changed, genpack) return changed_refs - except: - # TODO: remove try/except or do something useful here - raise - - # TODO: for now, we'll just push all heads that match remote heads - # * we should have specified push, tracking branches and --all - # takes a dict of refs:shas from the server and returns what should be - # pushed up - def get_changed_refs(self, refs): - keys = refs.keys() + except HangupException: + raise hgutil.Abort("the remote end hung up unexpectedly") - changed = {} - if not keys: - return None + def get_changed_refs(self, refs, revs, force): + new_refs = refs.copy() + for rev in revs: + ctx = self.repo[rev] + heads = [t for t in ctx.tags() if t in self.local_heads()] + tags = [t for t in ctx.tags() if t in self.tags] - # TODO: this is a huge hack - if keys[0] == 'capabilities^{}': - # nothing on the server yet - first push - if not 'master' in self.repo.tags(): - tip = self.repo.lookup('tip') - changed['refs/heads/master'] = self.map_git_get(hex(tip)) - - for tag, sha in self.tags.iteritems(): - tag_name = 'refs/tags/' + tag - if tag_name not in refs: - changed[tag_name] = self.map_git_get(sha) + if not (heads or tags): + raise hgutil.Abort("revision %s cannot be pushed since" + " it doesn't have a ref" % ctx) - for ref_name in keys: - parts = ref_name.split('/') - if parts[0] == 'refs' and parts[1] == 'heads': - # strip off 'refs/heads' - head = "/".join([v for v in parts[2:]]) - try: - local_ref = self.repo.lookup(head) - remote_ref = self.map_hg_get(refs[ref_name]) - if remote_ref: - remotectx = self.repo[remote_ref] - localctx = self.repo[local_ref] - if remotectx.ancestor(localctx) == remotectx: - # fast forward push - changed[ref_name] = self.map_git_get(hex(local_ref)) - else: - # XXX: maybe abort completely - self.ui.warn('not pushing branch %s, please merge\n'% head) - except RepoError: #pragma: no cover - # remote_ref is not here - pass + for r in heads + tags: + if r in heads: + ref = 'refs/heads/'+r + else: + ref = 'refs/tags/'+r - # Also push any local branches not on the server yet - for head in self.local_heads(): - ref = 'refs/heads/' + head - if not ref in refs: - node = self.repo.lookup(head) - changed[ref] = self.map_git_get(hex(node)) + if ref not in refs: + new_refs[ref] = self.map_git_get(ctx.hex()) + elif new_refs[ref] in self._map_git: + rctx = self.repo[self.map_hg_get(new_refs[ref])] + if rctx.ancestor(ctx) == rctx or force: + new_refs[ref] = self.map_git_get(ctx.hex()) + else: + raise hgutil.Abort("pushing %s overwrites %s" + % (ref, ctx)) + else: + raise hgutil.Abort("%s changed on the server, please pull " + "and merge before pushing" % ref) - return changed + return new_refs + def fetch_pack(self, remote_name): client, path = self.get_transport_and_path(remote_name) @@ -551,6 +536,8 @@ f, commit = self.git.object_store.add_pack() try: return client.fetch_pack(path, determine_wants, graphwalker, f.write, self.ui.status) + except HangupException: + raise hgutil.Abort("the remote end hung up unexpectedly") finally: commit() @@ -562,7 +549,7 @@ # Create a local Git branch name for each # Mercurial bookmark. for key in heads: - self.git.refs['refs/heads/' + key] = heads[key] + self.git.refs['refs/heads/' + key] = self.map_git_get(heads[key]) def export_hg_tags(self): for tag, sha in self.repo.tags().iteritems(): @@ -573,7 +560,7 @@ def local_heads(self): try: bms = bookmarks.parse(self.repo) - return dict([(bm, self.map_git_get(hex(bms[bm]))) for bm in bms]) + return dict([(bm, hex(bms[bm])) for bm in bms]) except AttributeError: #pragma: no cover return {}