--- a/doc/hgrc.5.txt Wed Feb 22 01:06:17 2006 -0500
+++ b/doc/hgrc.5.txt Wed Feb 22 08:11:52 2006 +0100
@@ -247,6 +247,9 @@
remote command to use for clone/push/pull operations. Default is 'hg'.
ssh;;
command to use for SSH connections. Default is 'ssh'.
+ timeout;;
+ The timeout used when a lock is held (in seconds), a negative value
+ means no timeout. Default is 600.
username;;
The committer of a changeset created when running "commit".
Typically a person's name and email address, e.g. "Fred Widget
--- a/mercurial/commands.py Wed Feb 22 01:06:17 2006 -0500
+++ b/mercurial/commands.py Wed Feb 22 08:11:52 2006 +0100
@@ -1800,7 +1800,7 @@
return r
-def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
+def push(ui, repo, dest="default-push", **opts):
"""push changes to the specified destination
Push changes from the local repository to the given destination.
@@ -1825,13 +1825,16 @@
dest = ui.expandpath(dest, repo.root)
ui.status('pushing to %s\n' % (dest))
- if ssh:
- ui.setconfig("ui", "ssh", ssh)
- if remotecmd:
- ui.setconfig("ui", "remotecmd", remotecmd)
+ if opts['ssh']:
+ ui.setconfig("ui", "ssh", opts['ssh'])
+ if opts['remotecmd']:
+ ui.setconfig("ui", "remotecmd", opts['remotecmd'])
other = hg.repository(ui, dest)
- r = repo.push(other, force)
+ revs = None
+ if opts['rev']:
+ revs = [repo.lookup(rev) for rev in opts['rev']]
+ r = repo.push(other, opts['force'], revs=revs)
return r
def rawcommit(ui, repo, *flist, **rc):
@@ -2505,14 +2508,15 @@
('r', 'rev', [], _('a specific revision you would like to pull')),
('', 'remotecmd', '',
_('specify hg command to run on the remote side'))],
- _('hg pull [-u] [-e FILE] [-r rev] [--remotecmd FILE] [SOURCE]')),
+ _('hg pull [-u] [-e FILE] [-r rev]... [--remotecmd FILE] [SOURCE]')),
"^push":
(push,
[('f', 'force', None, _('force push')),
('e', 'ssh', '', _('specify ssh command to use')),
+ ('r', 'rev', [], _('a specific revision you would like to push')),
('', 'remotecmd', '',
_('specify hg command to run on the remote side'))],
- _('hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]')),
+ _('hg push [-f] [-e FILE] [-r rev]... [--remotecmd FILE] [DEST]')),
"rawcommit":
(rawcommit,
[('p', 'parent', [], _('parent')),
--- a/mercurial/localrepo.py Wed Feb 22 01:06:17 2006 -0500
+++ b/mercurial/localrepo.py Wed Feb 22 08:11:52 2006 +0100
@@ -235,8 +235,7 @@
if os.path.exists(self.join("journal")):
self.ui.status(_("rolling back interrupted transaction\n"))
transaction.rollback(self.opener, self.join("journal"))
- self.manifest = manifest.manifest(self.opener)
- self.changelog = changelog.changelog(self.opener)
+ self.reload()
return True
else:
self.ui.warn(_("no interrupted transaction available\n"))
@@ -250,10 +249,20 @@
self.ui.status(_("rolling back last transaction\n"))
transaction.rollback(self.opener, self.join("undo"))
util.rename(self.join("undo.dirstate"), self.join("dirstate"))
- self.dirstate.read()
+ self.reload()
+ self.wreload()
else:
self.ui.warn(_("no undo information available\n"))
+ def wreload(self):
+ self.dirstate.read()
+
+ def reload(self):
+ self.changelog.load()
+ self.manifest.load()
+ self.tagscache = None
+ self.nodetagscache = None
+
def do_lock(self, lockname, wait, releasefn=None, acquirefn=None):
try:
l = lock.lock(self.join(lockname), 0, releasefn)
@@ -261,18 +270,25 @@
if not wait:
raise inst
self.ui.warn(_("waiting for lock held by %s\n") % inst.args[0])
- l = lock.lock(self.join(lockname), wait, releasefn)
+ try:
+ # default to 600 seconds timeout
+ l = lock.lock(self.join(lockname),
+ int(self.ui.config("ui", "timeout") or 600),
+ releasefn)
+ except lock.LockHeld, inst:
+ raise util.Abort(_("timeout while waiting for "
+ "lock held by %s") % inst.args[0])
if acquirefn:
acquirefn()
return l
def lock(self, wait=1):
- return self.do_lock("lock", wait)
+ return self.do_lock("lock", wait, acquirefn=self.reload)
def wlock(self, wait=1):
return self.do_lock("wlock", wait,
self.dirstate.write,
- self.dirstate.read)
+ self.wreload)
def checkfilemerge(self, filename, text, filelog, manifest1, manifest2):
"determine whether a new filenode is needed"
@@ -950,8 +966,8 @@
cg = remote.changegroupsubset(fetch, heads, 'pull')
return self.addchangegroup(cg)
- def push(self, remote, force=False):
- l = remote.lock()
+ def push(self, remote, force=False, revs=None):
+ lock = remote.lock()
base = {}
heads = remote.heads()
@@ -962,17 +978,25 @@
return 1
update = self.findoutgoing(remote, base)
- if not update:
+ if revs is not None:
+ msng_cl, bases, heads = self.changelog.nodesbetween(update, revs)
+ else:
+ bases, heads = update, self.changelog.heads()
+
+ if not bases:
self.ui.status(_("no changes found\n"))
return 1
elif not force:
- if len(heads) < len(self.changelog.heads()):
+ if len(bases) < len(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, 'push')
+ if revs is None:
+ cg = self.changegroup(update, 'push')
+ else:
+ cg = self.changegroupsubset(update, revs, 'push')
return remote.addchangegroup(cg)
def changegroupsubset(self, bases, heads, source):
--- a/mercurial/lock.py Wed Feb 22 01:06:17 2006 -0500
+++ b/mercurial/lock.py Wed Feb 22 08:11:52 2006 +0100
@@ -16,10 +16,10 @@
pass
class lock(object):
- def __init__(self, file, wait=1, releasefn=None):
+ def __init__(self, file, timeout=-1, releasefn=None):
self.f = file
self.held = 0
- self.wait = wait
+ self.timeout = timeout
self.releasefn = releasefn
self.lock()
@@ -27,13 +27,16 @@
self.release()
def lock(self):
+ timeout = self.timeout
while 1:
try:
self.trylock()
return 1
except LockHeld, inst:
- if self.wait:
+ if timeout != 0:
time.sleep(1)
+ if timeout > 0:
+ timeout -= 1
continue
raise inst
--- a/mercurial/revlog.py Wed Feb 22 01:06:17 2006 -0500
+++ b/mercurial/revlog.py Wed Feb 22 08:11:52 2006 +0100
@@ -13,7 +13,7 @@
from node import *
from i18n import gettext as _
from demandload import demandload
-demandload(globals(), "binascii errno heapq mdiff sha struct zlib")
+demandload(globals(), "binascii errno heapq mdiff os sha struct zlib")
def hash(text, p1, p2):
"""generate a hash from the given text and its parent hashes
@@ -187,15 +187,33 @@
self.indexfile = indexfile
self.datafile = datafile
self.opener = opener
+
+ self.indexstat = None
self.cache = None
self.chunkcache = None
+ self.load()
+ def load(self):
try:
- i = self.opener(self.indexfile).read()
+ f = self.opener(self.indexfile)
except IOError, inst:
if inst.errno != errno.ENOENT:
raise
i = ""
+ else:
+ try:
+ st = os.fstat(f.fileno())
+ except AttributeError, inst:
+ st = None
+ else:
+ oldst = self.indexstat
+ if (oldst and st.st_dev == oldst.st_dev
+ and st.st_ino == oldst.st_ino
+ and st.st_mtime == oldst.st_mtime
+ and st.st_ctime == oldst.st_ctime):
+ return
+ self.indexstat = st
+ i = f.read()
if i and i[:4] != "\0\0\0\0":
raise RevlogError(_("incompatible revlog signature on %s") %
--- a/tests/test-archive Wed Feb 22 01:06:17 2006 -0500
+++ b/tests/test-archive Wed Feb 22 08:11:52 2006 +0100
@@ -18,8 +18,7 @@
echo "allowzip = true" >> .hg/hgrc
echo "allowgz = true" >> .hg/hgrc
echo "allowbz2 = true" >> .hg/hgrc
-serverpid=`mktemp`
-hg serve -p 20059 -d --pid-file=$serverpid
+hg serve -p 20059 -d --pid-file=hg.pid
TIP=`hg id -v | cut -f1 -d' '`
QTIP=`hg id -q`
@@ -35,5 +34,4 @@
http_proxy= python getarchive.py "$TIP" zip > archive.zip
unzip -t archive.zip | sed "s/$QTIP/TIP/"
-kill `cat $serverpid`
-rm $serverpid
+kill `cat hg.pid`
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-clone-pull-corruption Wed Feb 22 08:11:52 2006 +0100
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# Corrupt an hg repo with a pull started during an aborted commit
+#
+
+# Create two repos, so that one of them can pull from the other one.
+hg init source
+cd source
+touch foo
+hg add foo
+hg ci -m 'add foo'
+hg clone . ../corrupted
+echo >> foo
+hg ci -m 'change foo'
+
+# Add a hook to wait 5 seconds and then abort the commit
+cd ../corrupted
+echo '[hooks]' >> .hg/hgrc
+echo 'pretxncommit = sleep 5; exit 1' >> .hg/hgrc
+
+# start a commit...
+touch bar
+hg add bar
+hg ci -m 'add bar' &
+
+# ... and start a pull while the commit is still running
+sleep 1
+hg pull ../source 2>/dev/null
+
+# see what happened
+wait
+hg verify
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-clone-pull-corruption.out Wed Feb 22 08:11:52 2006 +0100
@@ -0,0 +1,15 @@
+pulling from ../source
+abort: pretxncommit hook exited with status 1
+transaction abort!
+rollback completed
+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)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 2 changesets, 2 total revisions
--- a/tests/test-pull Wed Feb 22 01:06:17 2006 -0500
+++ b/tests/test-pull Wed Feb 22 08:11:52 2006 +0100
@@ -7,8 +7,7 @@
hg addremove
hg commit -m 1
hg verify
-serverpid=`mktemp`
-hg serve -p 20059 -d --pid-file=$serverpid
+hg serve -p 20059 -d --pid-file=hg.pid
cd ..
hg clone http://localhost:20059/ copy
@@ -19,5 +18,4 @@
hg manifest
hg pull
-kill `cat $serverpid`
-rm $serverpid
+kill `cat ../test/hg.pid`
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-pull-pull-corruption Wed Feb 22 08:11:52 2006 +0100
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# Corrupt an hg repo with two pulls.
+#
+
+# create one repo with a long history
+hg init source1
+cd source1
+touch foo
+hg add foo
+for i in 1 2 3 4 5 6 7 8 9 10; do
+ echo $i >> foo
+ hg ci -m $i
+done
+cd ..
+
+# create one repo with a shorter history
+hg clone -r 0 source1 source2
+cd source2
+echo a >> foo
+hg ci -m a
+cd ..
+
+# create a third repo to pull both other repos into it
+hg init corrupted
+cd corrupted
+# use a hook to make the second pull start while the first one is still running
+echo '[hooks]' >> .hg/hgrc
+echo 'prechangegroup = sleep 5' >> .hg/hgrc
+
+# start a pull...
+hg pull ../source1 &
+
+# ... and start another pull before the first one has finished
+sleep 1
+hg pull ../source2 2>/dev/null
+
+# see the result
+wait
+hg verify
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-pull-pull-corruption.out Wed Feb 22 08:11:52 2006 +0100
@@ -0,0 +1,24 @@
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
+pulling from ../source2
+pulling from ../source1
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 10 changesets with 10 changes to 1 files
+(run 'hg update' to get a working copy)
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files (+1 heads)
+(run 'hg update' to get a working copy)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 11 changesets, 11 total revisions
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-push-r Wed Feb 22 08:11:52 2006 +0100
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+hg init test
+cd test
+cat >>afile <<EOF
+0
+EOF
+hg add afile
+hg commit -m "0.0"
+cat >>afile <<EOF
+1
+EOF
+hg commit -m "0.1"
+cat >>afile <<EOF
+2
+EOF
+hg commit -m "0.2"
+cat >>afile <<EOF
+3
+EOF
+hg commit -m "0.3"
+hg update -C 0
+cat >>afile <<EOF
+1
+EOF
+hg commit -m "1.1"
+cat >>afile <<EOF
+2
+EOF
+hg commit -m "1.2"
+cat >fred <<EOF
+a line
+EOF
+cat >>afile <<EOF
+3
+EOF
+hg add fred
+hg commit -m "1.3"
+hg mv afile adifferentfile
+hg commit -m "1.3m"
+hg update -C 3
+hg mv afile anotherfile
+hg commit -m "0.3m"
+hg debugindex .hg/data/afile.i
+hg debugindex .hg/data/adifferentfile.i
+hg debugindex .hg/data/anotherfile.i
+hg debugindex .hg/data/fred.i
+hg debugindex .hg/00manifest.i
+hg verify
+cd ..
+for i in 0 1 2 3 4 5 6 7 8; do
+ mkdir test-"$i"
+ hg --cwd test-"$i" init
+ hg -R test push -r "$i" test-"$i"
+ cd test-"$i"
+ hg verify
+ cd ..
+done
+cd test-8
+hg pull ../test-7
+hg verify
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-push-r.out Wed Feb 22 08:11:52 2006 +0100
@@ -0,0 +1,135 @@
+ rev offset length base linkrev nodeid p1 p2
+ 0 0 3 0 0 362fef284ce2 000000000000 000000000000
+ 1 3 5 1 1 125144f7e028 362fef284ce2 000000000000
+ 2 8 7 2 2 4c982badb186 125144f7e028 000000000000
+ 3 15 9 3 3 19b1fc555737 4c982badb186 000000000000
+ rev offset length base linkrev nodeid p1 p2
+ 0 0 75 0 7 905359268f77 000000000000 000000000000
+ rev offset length base linkrev nodeid p1 p2
+ 0 0 75 0 8 905359268f77 000000000000 000000000000
+ rev offset length base linkrev nodeid p1 p2
+ 0 0 8 0 6 12ab3bcc5ea4 000000000000 000000000000
+ rev offset length base linkrev nodeid p1 p2
+ 0 0 48 0 0 43eadb1d2d06 000000000000 000000000000
+ 1 48 48 1 1 8b89697eba2c 43eadb1d2d06 000000000000
+ 2 96 48 2 2 626a32663c2f 8b89697eba2c 000000000000
+ 3 144 48 3 3 f54c32f13478 626a32663c2f 000000000000
+ 4 192 58 3 6 de68e904d169 626a32663c2f 000000000000
+ 5 250 68 3 7 3b45cc2ab868 de68e904d169 000000000000
+ 6 318 54 6 8 24d86153a002 f54c32f13478 000000000000
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+4 files, 9 changesets, 7 total revisions
+pushing to test-0
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 1 changesets, 1 total revisions
+pushing to test-1
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 2 changesets with 2 changes to 1 files
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 2 changesets, 2 total revisions
+pushing to test-2
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 3 changesets with 3 changes to 1 files
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 3 changesets, 3 total revisions
+pushing to test-3
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 4 changesets with 4 changes to 1 files
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 4 changesets, 4 total revisions
+pushing to test-4
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 2 changesets with 2 changes to 1 files
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 2 changesets, 2 total revisions
+pushing to test-5
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 3 changesets with 3 changes to 1 files
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 3 changesets, 3 total revisions
+pushing to test-6
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 4 changesets with 5 changes to 2 files
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+2 files, 4 changesets, 5 total revisions
+pushing to test-7
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 5 changesets with 6 changes to 3 files
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+3 files, 5 changesets, 6 total revisions
+pushing to test-8
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 5 changesets with 5 changes to 2 files
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+2 files, 5 changesets, 5 total revisions
+pulling from ../test-7
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 4 changesets with 2 changes to 3 files (+1 heads)
+(run 'hg update' to get a working copy)
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+4 files, 9 changesets, 7 total revisions