# HG changeset patch # User mpm@selenic.com # Date 1123001852 28800 # Node ID 0932bc2fb2bea21c935f92388a661b0087dd19f7 # Parent eef752151556d45783128473e937b52378e7903b# Parent f0446f6963d25bd78c8d9b6e4b7c13cd7c1ec36d Merge with BOS diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -832,13 +832,13 @@ def pull(ui, repo, source="default", **o return r -def push(ui, repo, dest="default-push"): +def push(ui, repo, dest="default-push", force=False): """push changes to the specified destination""" dest = ui.expandpath(dest) ui.status('pushing to %s\n' % (dest)) other = hg.repository(ui, dest) - r = repo.push(other) + r = repo.push(other, force) return r def rawcommit(ui, repo, *flist, **rc): @@ -1221,7 +1221,10 @@ table = { (pull, [('u', 'update', None, 'update working directory')], 'hg pull [-u] [SOURCE]'), - "^push": (push, [], 'hg push [DEST]'), + "^push": + (push, + [('f', 'force', None, 'force push')], + 'hg push [DEST]'), "rawcommit": (rawcommit, [('p', 'parent', [], 'parent'), diff --git a/mercurial/hg.py b/mercurial/hg.py --- a/mercurial/hg.py +++ b/mercurial/hg.py @@ -1059,17 +1059,22 @@ class localrepository: return nl - def findincoming(self, remote, base={}): + def findincoming(self, remote, base=None, heads=None): m = self.changelog.nodemap search = [] fetch = [] seen = {} seenbranch = {} + if base == None: + base = {} # assume we're closer to the tip than the root # and start by examining the heads self.ui.status("searching for changes\n") - heads = remote.heads() + + if not heads: + heads = remote.heads() + unknown = [] for h in heads: if h not in m: @@ -1171,9 +1176,11 @@ class localrepository: return fetch - def findoutgoing(self, remote): - base = {} - self.findincoming(remote, base) + def findoutgoing(self, remote, base=None, heads=None): + if base == None: + base = {} + self.findincoming(remote, base, heads) + remain = dict.fromkeys(self.changelog.nodemap) # prune everything remote has from the tree @@ -1213,12 +1220,27 @@ class localrepository: cg = remote.changegroup(fetch) return self.addchangegroup(cg) - def push(self, remote): + def push(self, remote, force=False): lock = remote.lock() - update = self.findoutgoing(remote) + + base = {} + heads = remote.heads() + inc = self.findincoming(remote, base, heads) + if not force and inc: + self.ui.warn("abort: unsynced remote changes!\n") + self.ui.status("(did you forget to sync? use push -f to force)\n") + return 1 + + update = self.findoutgoing(remote, base) if not update: self.ui.status("no changes found\n") return 1 + elif not force: + if len(heads) < len(self.changelog.heads()): + 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 cg = self.changegroup(update) return remote.addchangegroup(cg) @@ -1868,9 +1890,9 @@ class sshrepository: self.url = path self.ui = ui - m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', path) + m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))', path) if not m: - raise RepoError("couldn't parse destination %s\n" % path) + raise RepoError("couldn't parse destination %s" % path) self.user = m.group(2) self.host = m.group(3) @@ -1881,6 +1903,9 @@ class sshrepository: args = self.port and ("%s -p %s") % (args, self.port) or args path = self.path or "" + if not path: + raise RepoError("no remote repository path specified") + cmd = "ssh %s 'hg -R %s serve --stdio'" cmd = cmd % (args, path) @@ -1895,11 +1920,14 @@ class sshrepository: self.ui.status("remote: ", l) def __del__(self): - self.pipeo.close() - self.pipei.close() - for l in self.pipee: - self.ui.status("remote: ", l) - self.pipee.close() + try: + self.pipeo.close() + self.pipei.close() + for l in self.pipee: + self.ui.status("remote: ", l) + self.pipee.close() + except: + pass def dev(self): return -1 diff --git a/mercurial/util.py b/mercurial/util.py diff --git a/tests/test-merge5.out b/tests/test-merge5.out diff --git a/tests/test-push-warn b/tests/test-push-warn new file mode 100755 --- /dev/null +++ b/tests/test-push-warn @@ -0,0 +1,28 @@ +#!/bin/sh + +mkdir a +cd a +hg init +echo foo > t1 +hg add t1 +hg commit -m "1" -d "0 0" + +cd .. +hg clone a b + +cd a +echo foo > t2 +hg add t2 +hg commit -m "2" -d "0 0" + +cd ../b +echo foo > t3 +hg add t3 +hg commit -m "3" -d "0 0" + +hg push ../a +hg pull ../a +hg push ../a +hg up -m +hg commit -m "4" -d "0 0" +hg push ../a diff --git a/tests/test-push-warn.out b/tests/test-push-warn.out new file mode 100644 --- /dev/null +++ b/tests/test-push-warn.out @@ -0,0 +1,35 @@ ++ hg init ++ hg add t1 ++ hg commit -m 1 -d 0 0 ++ hg clone a b ++ hg add t2 ++ hg commit -m 2 -d 0 0 ++ hg add t3 ++ hg commit -m 3 -d 0 0 ++ hg push ../a +pushing to ../a +searching for changes +abort: unsynced remote changes! +(did you forget to sync? use push -f to force) ++ hg pull ../a +pulling from ../a +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files +(run 'hg update' to get a working copy) ++ hg push ../a +pushing to ../a +searching for changes +abort: push creates new remote branches! +(did you forget to merge? use push -f to force) ++ hg up -m ++ hg commit -m 4 -d 0 0 ++ hg push ../a +pushing to ../a +searching for changes +adding changesets +adding manifests +adding file changes +added 2 changesets with 2 changes to 2 files