--- a/mercurial/localrepo.py Thu Jun 15 13:27:57 2006 -0700
+++ b/mercurial/localrepo.py Thu Jun 15 16:37:23 2006 -0700
@@ -15,6 +15,8 @@
demandload(globals(), "revlog")
class localrepository(object):
+ capabilities = ()
+
def __del__(self):
self.transhandle = None
def __init__(self, parentui, path=None, create=0):
@@ -1105,8 +1107,20 @@
return self.addchangegroup(cg, 'pull')
def push(self, remote, force=False, revs=None):
- lock = remote.lock()
+ # there are two ways to push to remote repo:
+ #
+ # addchangegroup assumes local user can lock remote
+ # repo (local filesystem, old ssh servers).
+ #
+ # unbundle assumes local user cannot lock remote repo (new ssh
+ # servers, http servers).
+ if 'unbundle' in remote.capabilities:
+ self.push_unbundle(remote, force, revs)
+ else:
+ self.push_addchangegroup(remote, force, revs)
+
+ def prepush(self, remote, force, revs):
base = {}
remote_heads = remote.heads()
inc = self.findincoming(remote, base, remote_heads, force=force)
@@ -1114,7 +1128,7 @@
self.ui.warn(_("abort: unsynced remote changes!\n"))
self.ui.status(_("(did you forget to sync?"
" use push -f to force)\n"))
- return 1
+ return None, 1
update, updated_heads = self.findoutgoing(remote, base, remote_heads)
if revs is not None:
@@ -1124,7 +1138,7 @@
if not bases:
self.ui.status(_("no changes found\n"))
- return 1
+ return None, 1
elif not force:
# FIXME we don't properly detect creation of new heads
# in the push -r case, assume the user knows what he's doing
@@ -1133,13 +1147,35 @@
self.ui.warn(_("abort: push creates new remote branches!\n"))
self.ui.status(_("(did you forget to merge?"
" use push -f to force)\n"))
- return 1
+ return None, 1
if revs is None:
cg = self.changegroup(update, 'push')
else:
cg = self.changegroupsubset(update, revs, 'push')
- return remote.addchangegroup(cg, 'push')
+ return cg, remote_heads
+
+ def push_addchangegroup(self, remote, force, revs):
+ lock = remote.lock()
+
+ ret = self.prepush(remote, force, revs)
+ if ret[0] is not None:
+ cg, remote_heads = ret
+ return remote.addchangegroup(cg, 'push')
+ return ret[1]
+
+ def push_unbundle(self, remote, force, revs):
+ # local repo finds heads on server, finds out what revs it
+ # must push. once revs transferred, if server finds it has
+ # different heads (someone else won commit/push race), server
+ # aborts.
+
+ ret = self.prepush(remote, force, revs)
+ if ret[0] is not None:
+ cg, remote_heads = ret
+ if force: remote_heads = ['force']
+ return remote.unbundle(cg, remote_heads, 'push')
+ return ret[1]
def changegroupsubset(self, bases, heads, source):
"""This function generates a changegroup consisting of all the nodes