# HG changeset patch # User Matt Mackall # Date 1380649499 25200 # Node ID 5c0dc243fe5b921589688633a6d2fbe4756d5d1c # Parent b00ba31313c39b38a6e724c1162787ed75fa66a5# Parent 1aaefba2a3a9dc8b37d29b9c437876407e87c16f merge with stable diff -r 1aaefba2a3a9 -r 5c0dc243fe5b contrib/check-code.py --- a/contrib/check-code.py Tue Oct 01 00:12:34 2013 +0900 +++ b/contrib/check-code.py Tue Oct 01 10:44:59 2013 -0700 @@ -61,11 +61,13 @@ (r'pushd|popd', "don't use 'pushd' or 'popd', use 'cd'"), (r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"), (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"), + (r'(?'"), (r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"), (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"), (r'printf.*[^\\]\\([1-9]|0\d)', "don't use 'printf \NNN', use Python"), @@ -160,6 +162,9 @@ "tuple parameter unpacking not available in Python 3+"), (r'lambda\s*\(.*,.*\)', "tuple parameter unpacking not available in Python 3+"), + (r'import (.+,[^.]+\.[^.]+|[^.]+\.[^.]+,)', + '2to3 can\'t always rewrite "import qux, foo.bar", ' + 'use "import foo.bar" on its own line instead.'), (r'(?[1=2] usage: mercurial/9mail -f from to [cc] + exit usage +} + +from=() +cc=() +to=() + +switch($1){ +case -f + from=$2 +case * + usage +} + +to=($3) +if(~ $#* 4) + cc=(-C $4) + +upasname=$from +upas/marshal $cc $to + diff -r 1aaefba2a3a9 -r 5c0dc243fe5b contrib/plan9/hgrc.d/9diff.rc --- a/contrib/plan9/hgrc.d/9diff.rc Tue Oct 01 00:12:34 2013 +0900 +++ b/contrib/plan9/hgrc.d/9diff.rc Tue Oct 01 10:44:59 2013 -0700 @@ -4,4 +4,4 @@ extdiff = [extdiff] -9diff = 9diff -cm $parent $child $root +9diff = /bin/mercurial/9diff -cm $parent $child $root diff -r 1aaefba2a3a9 -r 5c0dc243fe5b contrib/plan9/hgrc.d/9mail.rc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/plan9/hgrc.d/9mail.rc Tue Oct 01 10:44:59 2013 -0700 @@ -0,0 +1,4 @@ +# The 9mail to support patchbomb and other email wrappers +[email] +method = /bin/mercurial/9mail + diff -r 1aaefba2a3a9 -r 5c0dc243fe5b hgext/convert/subversion.py --- a/hgext/convert/subversion.py Tue Oct 01 00:12:34 2013 +0900 +++ b/hgext/convert/subversion.py Tue Oct 01 10:44:59 2013 -0700 @@ -2,7 +2,8 @@ # # Copyright(C) 2007 Daniel Holth et al -import os, re, sys, tempfile, urllib, urllib2, xml.dom.minidom +import os, re, sys, tempfile, urllib, urllib2 +import xml.dom.minidom import cPickle as pickle from mercurial import strutil, scmutil, util, encoding diff -r 1aaefba2a3a9 -r 5c0dc243fe5b hgext/factotum.py --- a/hgext/factotum.py Tue Oct 01 00:12:34 2013 +0900 +++ b/hgext/factotum.py Tue Oct 01 10:44:59 2013 -0700 @@ -101,7 +101,7 @@ user, passwd = auth.get('username'), auth.get('password') if not user or not passwd: if not prefix: - prefix = '*' + prefix = realm.split(' ')[0].lower() params = 'service=%s prefix=%s' % (_service, prefix) if user: params = '%s user=%s' % (params, user) diff -r 1aaefba2a3a9 -r 5c0dc243fe5b hgext/histedit.py --- a/hgext/histedit.py Tue Oct 01 00:12:34 2013 +0900 +++ b/hgext/histedit.py Tue Oct 01 10:44:59 2013 -0700 @@ -419,10 +419,6 @@ if revs: revs = [repo.lookup(rev) for rev in revs] - # hexlify nodes from outgoing, because we're going to parse - # parent[0] using revsingle below, and if the binary hash - # contains special revset characters like ":" the revset - # parser can choke. outgoing = discovery.findcommonoutgoing(repo, other, revs, force=force) if not outgoing.missing: raise util.Abort(_('no outgoing ancestors')) @@ -519,7 +515,6 @@ if goal == 'continue': (parentctxnode, rules, keep, topmost, replacements) = readstate(repo) - currentparent, wantnull = repo.dirstate.parents() parentctx = repo[parentctxnode] parentctx, repl = bootstrapcontinue(ui, repo, parentctx, rules, opts) replacements.extend(repl) diff -r 1aaefba2a3a9 -r 5c0dc243fe5b hgext/largefiles/__init__.py --- a/hgext/largefiles/__init__.py Tue Oct 01 00:12:34 2013 +0900 +++ b/hgext/largefiles/__init__.py Tue Oct 01 10:44:59 2013 -0700 @@ -105,16 +105,26 @@ command. ''' -from mercurial import commands +from mercurial import commands, localrepo, extensions import lfcommands import reposetup -import uisetup +import uisetup as uisetupmod testedwith = 'internal' reposetup = reposetup.reposetup -uisetup = uisetup.uisetup + +def featuresetup(ui, supported): + for name, module in extensions.extensions(ui): + if __name__ == module.__name__: + # don't die on seeing a repo with the largefiles requirement + supported |= set(['largefiles']) + return + +def uisetup(ui): + localrepo.localrepository.featuresetupfuncs.add(featuresetup) + uisetupmod.uisetup(ui) commands.norepo += " lfconvert" diff -r 1aaefba2a3a9 -r 5c0dc243fe5b hgext/largefiles/overrides.py --- a/hgext/largefiles/overrides.py Tue Oct 01 00:12:34 2013 +0900 +++ b/hgext/largefiles/overrides.py Tue Oct 01 10:44:59 2013 -0700 @@ -315,7 +315,7 @@ lfdirstate.normal(lfile) lfdirstate.write() if mod: - raise util.Abort(_('uncommitted local changes')) + raise util.Abort(_('uncommitted changes')) # XXX handle removed differently if not opts['clean']: for lfile in unsure + modified + added: @@ -717,7 +717,6 @@ ui.debug('--update and --rebase are not compatible, ignoring ' 'the update flag\n') del opts['rebase'] - cmdutil.bailifchanged(repo) origpostincoming = commands.postincoming def _dummy(*args, **kwargs): pass @@ -947,7 +946,7 @@ modified, added, removed, deleted = repo.status()[:4] repo.lfstatus = False if modified or added or removed or deleted: - raise util.Abort(_('outstanding uncommitted changes')) + raise util.Abort(_('uncommitted changes')) # Fetch doesn't use cmdutil.bailifchanged so override it to add the check def overridefetch(orig, ui, repo, *pats, **opts): @@ -955,7 +954,7 @@ modified, added, removed, deleted = repo.status()[:4] repo.lfstatus = False if modified or added or removed or deleted: - raise util.Abort(_('outstanding uncommitted changes')) + raise util.Abort(_('uncommitted changes')) return orig(ui, repo, *pats, **opts) def overrideforget(orig, ui, repo, *pats, **opts): diff -r 1aaefba2a3a9 -r 5c0dc243fe5b hgext/largefiles/reposetup.py --- a/hgext/largefiles/reposetup.py Tue Oct 01 00:12:34 2013 +0900 +++ b/hgext/largefiles/reposetup.py Tue Oct 01 10:44:59 2013 -0700 @@ -10,8 +10,7 @@ import copy import os -from mercurial import context, error, manifest, match as match_, util, \ - discovery +from mercurial import error, manifest, match as match_, util, discovery from mercurial import node as node_ from mercurial.i18n import _ from mercurial import localrepo @@ -92,14 +91,8 @@ else: # some calls in this function rely on the old version of status self.lfstatus = False - if isinstance(node1, context.changectx): - ctx1 = node1 - else: - ctx1 = self[node1] - if isinstance(node2, context.changectx): - ctx2 = node2 - else: - ctx2 = self[node2] + ctx1 = self[node1] + ctx2 = self[node2] working = ctx2.rev() is None parentworking = working and ctx1 == self['.'] @@ -414,6 +407,14 @@ wlock.release() def push(self, remote, force=False, revs=None, newbranch=False): + if remote.local(): + missing = set(self.requirements) - remote.local().supported + if missing: + msg = _("required features are not" + " supported in the destination:" + " %s") % (', '.join(sorted(missing))) + raise util.Abort(msg) + outgoing = discovery.findcommonoutgoing(repo, remote.peer(), force=force) if outgoing.missing: diff -r 1aaefba2a3a9 -r 5c0dc243fe5b hgext/largefiles/uisetup.py --- a/hgext/largefiles/uisetup.py Tue Oct 01 00:12:34 2013 +0900 +++ b/hgext/largefiles/uisetup.py Tue Oct 01 10:44:59 2013 -0700 @@ -9,7 +9,7 @@ '''setup for largefiles extension: uisetup''' from mercurial import archival, cmdutil, commands, extensions, filemerge, hg, \ - httppeer, localrepo, merge, scmutil, sshpeer, wireproto, revset + httppeer, merge, scmutil, sshpeer, wireproto, revset from mercurial.i18n import _ from mercurial.hgweb import hgweb_mod, webcommands from mercurial.subrepo import hgsubrepo @@ -152,9 +152,6 @@ sshpeer.sshpeer._callstream = proto.sshrepocallstream httppeer.httppeer._callstream = proto.httprepocallstream - # don't die on seeing a repo with the largefiles requirement - localrepo.localrepository.supported |= set(['largefiles']) - # override some extensions' stuff as well for name, module in extensions.extensions(): if name == 'fetch': diff -r 1aaefba2a3a9 -r 5c0dc243fe5b hgext/mq.py --- a/hgext/mq.py Tue Oct 01 00:12:34 2013 +0900 +++ b/hgext/mq.py Tue Oct 01 10:44:59 2013 -0700 @@ -57,15 +57,19 @@ make them behave as if --keep-changes were passed, and non-conflicting local changes will be tolerated and preserved. If incompatible options such as -f/--force or --exact are passed, this setting is ignored. + +This extension used to provide a strip command. This command now lives +in the strip extension. ''' from mercurial.i18n import _ from mercurial.node import bin, hex, short, nullid, nullrev from mercurial.lock import release from mercurial import commands, cmdutil, hg, scmutil, util, revset -from mercurial import repair, extensions, error, phases, bookmarks +from mercurial import extensions, error, phases from mercurial import patch as patchmod from mercurial import localrepo +from mercurial import subrepo import os, re, errno, shutil commands.norepo += " qclone" @@ -76,6 +80,22 @@ command = cmdutil.command(cmdtable) testedwith = 'internal' +# force load strip extension formely included in mq and import some utility +try: + stripext = extensions.find('strip') +except KeyError: + # note: load is lazy so we could avoid the try-except, + # but I (marmoute) prefer this explicite code. + class dummyui(object): + def debug(self, msg): + pass + stripext = extensions.load(dummyui(), 'strip', '') + +strip = stripext.strip +checksubstate = stripext.checksubstate +checklocalchanges = stripext.checklocalchanges + + # Patch names looks like unix-file names. # They must be joinable with queue directory and result in the patch path. normname = util.normpath @@ -282,15 +302,11 @@ phase = phases.secret if phase is not None: backup = repo.ui.backupconfig('phases', 'new-commit') - # Marking the repository as committing an mq patch can be used - # to optimize operations like branchtags(). - repo._committingpatch = True try: if phase is not None: repo.ui.setconfig('phases', 'new-commit', phase) return repo.commit(*args, **kwargs) finally: - repo._committingpatch = False if phase is not None: repo.ui.restoreconfig(backup) @@ -606,7 +622,7 @@ # apply failed, strip away that rev and merge. hg.clean(repo, head) - self.strip(repo, [n], update=False, backup='strip') + strip(self.ui, repo, [n], update=False, backup='strip') ctx = repo[rev] ret = hg.merge(repo, rev) @@ -631,6 +647,14 @@ return (0, n) def qparents(self, repo, rev=None): + """return the mq handled parent or p1 + + In some case where mq get himself in being the parent of a merge the + paappropriate parent may be p2. + (eg: an in progress merge started with mq disabled) + + If no parent are managed by mq, p1 is returned. + """ if rev is None: (p1, p2) = repo.dirstate.parents() if p2 == nullid: @@ -800,6 +824,14 @@ p1, p2 = repo.dirstate.parents() repo.setparents(p1, merge) + if all_files and '.hgsubstate' in all_files: + wctx = repo['.'] + mctx = actx = repo[None] + overwrite = False + mergedsubstate = subrepo.submerge(repo, wctx, mctx, actx, + overwrite) + files += mergedsubstate.keys() + match = scmutil.matchfiles(repo, files or []) oldtip = repo['tip'] n = newcommit(repo, None, message, ph.user, ph.date, match=match, @@ -940,23 +972,6 @@ return top, patch return None, None - def checksubstate(self, repo, baserev=None): - '''return list of subrepos at a different revision than substate. - Abort if any subrepos have uncommitted changes.''' - inclsubs = [] - wctx = repo[None] - if baserev: - bctx = repo[baserev] - else: - bctx = wctx.parents()[0] - for s in sorted(wctx.substate): - if wctx.sub(s).dirty(True): - raise util.Abort( - _("uncommitted changes in subrepository %s") % s) - elif s not in bctx.substate or bctx.sub(s).dirty(): - inclsubs.append(s) - return inclsubs - def putsubstate2changes(self, substatestate, changes): for files in changes[:3]: if '.hgsubstate' in files: @@ -969,18 +984,14 @@ else: # modified changes[0].append('.hgsubstate') - def localchangesfound(self, refresh=True): + def checklocalchanges(self, repo, force=False, refresh=True): + excsuffix = '' if refresh: - raise util.Abort(_("local changes found, refresh first")) - else: - raise util.Abort(_("local changes found")) - - def checklocalchanges(self, repo, force=False, refresh=True): - cmdutil.checkunfinished(repo) - m, a, r, d = repo.status()[:4] - if (m or a or r or d) and not force: - self.localchangesfound(refresh) - return m, a, r, d + excsuffix = ', refresh first' + # plain versions for i18n tool to detect them + _("local changes found, refresh first") + _("local changed subrepos found, refresh first") + return checklocalchanges(repo, force, excsuffix) _reserved = ('series', 'status', 'guards', '.', '..') def checkreservedname(self, name): @@ -1021,7 +1032,7 @@ diffopts = self.diffopts({'git': opts.get('git')}) if opts.get('checkname', True): self.checkpatchname(patchfn) - inclsubs = self.checksubstate(repo) + inclsubs = checksubstate(repo) if inclsubs: inclsubs.append('.hgsubstate') substatestate = repo.dirstate['.hgsubstate'] @@ -1111,22 +1122,6 @@ finally: release(wlock) - def strip(self, repo, revs, update=True, backup="all", force=None): - wlock = lock = None - try: - wlock = repo.wlock() - lock = repo.lock() - - if update: - self.checklocalchanges(repo, force=force, refresh=False) - urev = self.qparents(repo, revs[0]) - hg.clean(repo, urev) - repo.dirstate.write() - - repair.strip(self.ui, repo, revs, backup) - finally: - release(lock, wlock) - def isapplied(self, patch): """returns (index, rev, patch)""" for i, a in enumerate(self.applied): @@ -1435,7 +1430,7 @@ tobackup = set(a + m + r) & tobackup if keepchanges and tobackup: - self.localchangesfound() + raise util.Abort(_("local changes found, refresh first")) self.backup(repo, tobackup) for f in a: @@ -1449,7 +1444,9 @@ for patch in reversed(self.applied[start:end]): self.ui.status(_("popping %s\n") % patch.name) del self.applied[start:end] - self.strip(repo, [rev], update=False, backup='strip') + strip(self.ui, repo, [rev], update=False, backup='strip') + for s, state in repo['.'].substate.items(): + repo['.'].sub(s).get(state) if self.applied: self.ui.write(_("now at: %s\n") % self.applied[-1].name) else: @@ -1493,7 +1490,7 @@ cparents = repo.changelog.parents(top) patchparent = self.qparents(repo, top) - inclsubs = self.checksubstate(repo, hex(patchparent)) + inclsubs = checksubstate(repo, hex(patchparent)) if inclsubs: inclsubs.append('.hgsubstate') substatestate = repo.dirstate['.hgsubstate'] @@ -1650,8 +1647,7 @@ repo.setparents(*cparents) self.applied.pop() self.applieddirty = True - self.strip(repo, [top], update=False, - backup='strip') + strip(self.ui, repo, [top], update=False, backup='strip') except: # re-raises repo.dirstate.invalidate() raise @@ -1823,7 +1819,7 @@ update = True else: update = False - self.strip(repo, [rev], update=update, backup='strip') + strip(self.ui, repo, [rev], update=update, backup='strip') if qpp: self.ui.warn(_("saved queue repository parents: %s %s\n") % (short(qpp[0]), short(qpp[1]))) @@ -2304,7 +2300,7 @@ if qbase: ui.note(_('stripping applied patches from destination ' 'repository\n')) - repo.mq.strip(repo, [qbase], update=False, backup=None) + strip(ui, repo, [qbase], update=False, backup=None) if not opts.get('noupdate'): ui.note(_('updating destination repository\n')) hg.update(repo, repo.changelog.tip()) @@ -2919,158 +2915,6 @@ q.savedirty() return 0 -@command("strip", - [ - ('r', 'rev', [], _('strip specified revision (optional, ' - 'can specify revisions without this ' - 'option)'), _('REV')), - ('f', 'force', None, _('force removal of changesets, discard ' - 'uncommitted changes (no backup)')), - ('b', 'backup', None, _('bundle only changesets with local revision' - ' number greater than REV which are not' - ' descendants of REV (DEPRECATED)')), - ('', 'no-backup', None, _('no backups')), - ('', 'nobackup', None, _('no backups (DEPRECATED)')), - ('n', '', None, _('ignored (DEPRECATED)')), - ('k', 'keep', None, _("do not modify working copy during strip")), - ('B', 'bookmark', '', _("remove revs only reachable from given" - " bookmark"))], - _('hg strip [-k] [-f] [-n] [-B bookmark] [-r] REV...')) -def strip(ui, repo, *revs, **opts): - """strip changesets and all their descendants from the repository - - The strip command removes the specified changesets and all their - descendants. If the working directory has uncommitted changes, the - operation is aborted unless the --force flag is supplied, in which - case changes will be discarded. - - If a parent of the working directory is stripped, then the working - directory will automatically be updated to the most recent - available ancestor of the stripped parent after the operation - completes. - - Any stripped changesets are stored in ``.hg/strip-backup`` as a - bundle (see :hg:`help bundle` and :hg:`help unbundle`). They can - be restored by running :hg:`unbundle .hg/strip-backup/BUNDLE`, - where BUNDLE is the bundle file created by the strip. Note that - the local revision numbers will in general be different after the - restore. - - Use the --no-backup option to discard the backup bundle once the - operation completes. - - Strip is not a history-rewriting operation and can be used on - changesets in the public phase. But if the stripped changesets have - been pushed to a remote repository you will likely pull them again. - - Return 0 on success. - """ - backup = 'all' - if opts.get('backup'): - backup = 'strip' - elif opts.get('no_backup') or opts.get('nobackup'): - backup = 'none' - - cl = repo.changelog - revs = list(revs) + opts.get('rev') - revs = set(scmutil.revrange(repo, revs)) - - if opts.get('bookmark'): - mark = opts.get('bookmark') - marks = repo._bookmarks - if mark not in marks: - raise util.Abort(_("bookmark '%s' not found") % mark) - - # If the requested bookmark is not the only one pointing to a - # a revision we have to only delete the bookmark and not strip - # anything. revsets cannot detect that case. - uniquebm = True - for m, n in marks.iteritems(): - if m != mark and n == repo[mark].node(): - uniquebm = False - break - if uniquebm: - rsrevs = repo.revs("ancestors(bookmark(%s)) - " - "ancestors(head() and not bookmark(%s)) - " - "ancestors(bookmark() and not bookmark(%s))", - mark, mark, mark) - revs.update(set(rsrevs)) - if not revs: - del marks[mark] - marks.write() - ui.write(_("bookmark '%s' deleted\n") % mark) - - if not revs: - raise util.Abort(_('empty revision set')) - - descendants = set(cl.descendants(revs)) - strippedrevs = revs.union(descendants) - roots = revs.difference(descendants) - - update = False - # if one of the wdir parent is stripped we'll need - # to update away to an earlier revision - for p in repo.dirstate.parents(): - if p != nullid and cl.rev(p) in strippedrevs: - update = True - break - - rootnodes = set(cl.node(r) for r in roots) - - q = repo.mq - if q.applied: - # refresh queue state if we're about to strip - # applied patches - if cl.rev(repo.lookup('qtip')) in strippedrevs: - q.applieddirty = True - start = 0 - end = len(q.applied) - for i, statusentry in enumerate(q.applied): - if statusentry.node in rootnodes: - # if one of the stripped roots is an applied - # patch, only part of the queue is stripped - start = i - break - del q.applied[start:end] - q.savedirty() - - revs = sorted(rootnodes) - if update and opts.get('keep'): - wlock = repo.wlock() - try: - urev = repo.mq.qparents(repo, revs[0]) - uctx = repo[urev] - - # only reset the dirstate for files that would actually change - # between the working context and uctx - descendantrevs = repo.revs("%s::." % uctx.rev()) - changedfiles = [] - for rev in descendantrevs: - # blindly reset the files, regardless of what actually changed - changedfiles.extend(repo[rev].files()) - - # reset files that only changed in the dirstate too - dirstate = repo.dirstate - dirchanges = [f for f in dirstate if dirstate[f] != 'n'] - changedfiles.extend(dirchanges) - - repo.dirstate.rebuild(urev, uctx.manifest(), changedfiles) - repo.dirstate.write() - update = False - finally: - wlock.release() - - if opts.get('bookmark'): - if mark == repo._bookmarkcurrent: - bookmarks.setcurrent(repo, None) - del marks[mark] - marks.write() - ui.write(_("bookmark '%s' deleted\n") % mark) - - repo.mq.strip(repo, revs, backup=backup, update=update, - force=opts.get('force')) - - return 0 @command("qselect", [('n', 'none', None, _('disable all guards')), diff -r 1aaefba2a3a9 -r 5c0dc243fe5b hgext/notify.py --- a/hgext/notify.py Tue Oct 01 00:12:34 2013 +0900 +++ b/hgext/notify.py Tue Oct 01 10:44:59 2013 -0700 @@ -133,9 +133,13 @@ ''' +import email, socket, time +# On python2.4 you have to import this by name or they fail to +# load. This was not a problem on Python 2.7. +import email.Parser from mercurial.i18n import _ from mercurial import patch, cmdutil, templater, util, mail -import email.Parser, email.Errors, fnmatch, socket, time +import fnmatch testedwith = 'internal' diff -r 1aaefba2a3a9 -r 5c0dc243fe5b hgext/patchbomb.py --- a/hgext/patchbomb.py Tue Oct 01 00:12:34 2013 +0900 +++ b/hgext/patchbomb.py Tue Oct 01 10:44:59 2013 -0700 @@ -46,8 +46,12 @@ ''' import os, errno, socket, tempfile, cStringIO -import email.MIMEMultipart, email.MIMEBase -import email.Utils, email.Encoders, email.Generator +import email +# On python2.4 you have to import these by name or they fail to +# load. This was not a problem on Python 2.7. +import email.Generator +import email.MIMEMultipart + from mercurial import cmdutil, commands, hg, mail, patch, util from mercurial import scmutil from mercurial.i18n import _ diff -r 1aaefba2a3a9 -r 5c0dc243fe5b hgext/progress.py --- a/hgext/progress.py Tue Oct 01 00:12:34 2013 +0900 +++ b/hgext/progress.py Tue Oct 01 10:44:59 2013 -0700 @@ -239,6 +239,13 @@ # this one are also closed if topic in self.topics: self.topics = self.topics[:self.topics.index(topic)] + # reset the last topic to the one we just unwound to, + # so that higher-level topics will be stickier than + # lower-level topics + if self.topics: + self.lasttopic = self.topics[-1] + else: + self.lasttopic = None else: if topic not in self.topics: self.starttimes[topic] = now diff -r 1aaefba2a3a9 -r 5c0dc243fe5b hgext/rebase.py --- a/hgext/rebase.py Tue Oct 01 00:12:34 2013 +0900 +++ b/hgext/rebase.py Tue Oct 01 10:44:59 2013 -0700 @@ -769,7 +769,6 @@ 'the update flag\n') movemarkfrom = repo['.'].node() - cmdutil.bailifchanged(repo) revsprepull = len(repo) origpostincoming = commands.postincoming def _dummy(*args, **kwargs): diff -r 1aaefba2a3a9 -r 5c0dc243fe5b hgext/strip.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hgext/strip.py Tue Oct 01 10:44:59 2013 -0700 @@ -0,0 +1,217 @@ +"""strip changesets and their descendents from history + +This extension allows to strip changesets and all their descendants from the +repository. See the command help for details. +""" +from mercurial.i18n import _ +from mercurial.node import nullid +from mercurial.lock import release +from mercurial import cmdutil, hg, scmutil, util +from mercurial import repair, bookmarks + +cmdtable = {} +command = cmdutil.command(cmdtable) +testedwith = 'internal' + +def checksubstate(repo, baserev=None): + '''return list of subrepos at a different revision than substate. + Abort if any subrepos have uncommitted changes.''' + inclsubs = [] + wctx = repo[None] + if baserev: + bctx = repo[baserev] + else: + bctx = wctx.parents()[0] + for s in sorted(wctx.substate): + if wctx.sub(s).dirty(True): + raise util.Abort( + _("uncommitted changes in subrepository %s") % s) + elif s not in bctx.substate or bctx.sub(s).dirty(): + inclsubs.append(s) + return inclsubs + +def checklocalchanges(repo, force=False, excsuffix=''): + cmdutil.checkunfinished(repo) + m, a, r, d = repo.status()[:4] + if not force: + if (m or a or r or d): + _("local changes found") # i18n tool detection + raise util.Abort(_("local changes found" + excsuffix)) + if checksubstate(repo): + _("local changed subrepos found") # i18n tool detection + raise util.Abort(_("local changed subrepos found" + excsuffix)) + return m, a, r, d + +def strip(ui, repo, revs, update=True, backup="all", force=None): + wlock = lock = None + try: + wlock = repo.wlock() + lock = repo.lock() + + if update: + checklocalchanges(repo, force=force) + urev, p2 = repo.changelog.parents(revs[0]) + if p2 != nullid and p2 in [x.node for x in repo.mq.applied]: + urev = p2 + hg.clean(repo, urev) + repo.dirstate.write() + + repair.strip(ui, repo, revs, backup) + finally: + release(lock, wlock) + + +@command("strip", + [ + ('r', 'rev', [], _('strip specified revision (optional, ' + 'can specify revisions without this ' + 'option)'), _('REV')), + ('f', 'force', None, _('force removal of changesets, discard ' + 'uncommitted changes (no backup)')), + ('b', 'backup', None, _('bundle only changesets with local revision' + ' number greater than REV which are not' + ' descendants of REV (DEPRECATED)')), + ('', 'no-backup', None, _('no backups')), + ('', 'nobackup', None, _('no backups (DEPRECATED)')), + ('n', '', None, _('ignored (DEPRECATED)')), + ('k', 'keep', None, _("do not modify working copy during strip")), + ('B', 'bookmark', '', _("remove revs only reachable from given" + " bookmark"))], + _('hg strip [-k] [-f] [-n] [-B bookmark] [-r] REV...')) +def stripcmd(ui, repo, *revs, **opts): + """strip changesets and all their descendants from the repository + + The strip command removes the specified changesets and all their + descendants. If the working directory has uncommitted changes, the + operation is aborted unless the --force flag is supplied, in which + case changes will be discarded. + + If a parent of the working directory is stripped, then the working + directory will automatically be updated to the most recent + available ancestor of the stripped parent after the operation + completes. + + Any stripped changesets are stored in ``.hg/strip-backup`` as a + bundle (see :hg:`help bundle` and :hg:`help unbundle`). They can + be restored by running :hg:`unbundle .hg/strip-backup/BUNDLE`, + where BUNDLE is the bundle file created by the strip. Note that + the local revision numbers will in general be different after the + restore. + + Use the --no-backup option to discard the backup bundle once the + operation completes. + + Strip is not a history-rewriting operation and can be used on + changesets in the public phase. But if the stripped changesets have + been pushed to a remote repository you will likely pull them again. + + Return 0 on success. + """ + backup = 'all' + if opts.get('backup'): + backup = 'strip' + elif opts.get('no_backup') or opts.get('nobackup'): + backup = 'none' + + cl = repo.changelog + revs = list(revs) + opts.get('rev') + revs = set(scmutil.revrange(repo, revs)) + + if opts.get('bookmark'): + mark = opts.get('bookmark') + marks = repo._bookmarks + if mark not in marks: + raise util.Abort(_("bookmark '%s' not found") % mark) + + # If the requested bookmark is not the only one pointing to a + # a revision we have to only delete the bookmark and not strip + # anything. revsets cannot detect that case. + uniquebm = True + for m, n in marks.iteritems(): + if m != mark and n == repo[mark].node(): + uniquebm = False + break + if uniquebm: + rsrevs = repo.revs("ancestors(bookmark(%s)) - " + "ancestors(head() and not bookmark(%s)) - " + "ancestors(bookmark() and not bookmark(%s))", + mark, mark, mark) + revs.update(set(rsrevs)) + if not revs: + del marks[mark] + marks.write() + ui.write(_("bookmark '%s' deleted\n") % mark) + + if not revs: + raise util.Abort(_('empty revision set')) + + descendants = set(cl.descendants(revs)) + strippedrevs = revs.union(descendants) + roots = revs.difference(descendants) + + update = False + # if one of the wdir parent is stripped we'll need + # to update away to an earlier revision + for p in repo.dirstate.parents(): + if p != nullid and cl.rev(p) in strippedrevs: + update = True + break + + rootnodes = set(cl.node(r) for r in roots) + + q = getattr(repo, 'mq', None) + if q is not None and q.applied: + # refresh queue state if we're about to strip + # applied patches + if cl.rev(repo.lookup('qtip')) in strippedrevs: + q.applieddirty = True + start = 0 + end = len(q.applied) + for i, statusentry in enumerate(q.applied): + if statusentry.node in rootnodes: + # if one of the stripped roots is an applied + # patch, only part of the queue is stripped + start = i + break + del q.applied[start:end] + q.savedirty() + + revs = sorted(rootnodes) + if update and opts.get('keep'): + wlock = repo.wlock() + try: + urev, p2 = repo.changelog.parents(revs[0]) + if (util.safehasattr(repo, 'mq') and p2 != nullid + and p2 in [x.node for x in repo.mq.applied]): + urev = p2 + uctx = repo[urev] + + # only reset the dirstate for files that would actually change + # between the working context and uctx + descendantrevs = repo.revs("%s::." % uctx.rev()) + changedfiles = [] + for rev in descendantrevs: + # blindly reset the files, regardless of what actually changed + changedfiles.extend(repo[rev].files()) + + # reset files that only changed in the dirstate too + dirstate = repo.dirstate + dirchanges = [f for f in dirstate if dirstate[f] != 'n'] + changedfiles.extend(dirchanges) + + repo.dirstate.rebuild(urev, uctx.manifest(), changedfiles) + repo.dirstate.write() + update = False + finally: + wlock.release() + + if opts.get('bookmark'): + if mark == repo._bookmarkcurrent: + bookmarks.setcurrent(repo, None) + del marks[mark] + marks.write() + ui.write(_("bookmark '%s' deleted\n") % mark) + + strip(ui, repo, revs, backup=backup, update=update, force=opts.get('force')) + + return 0 diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/branchmap.py --- a/mercurial/branchmap.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/branchmap.py Tue Oct 01 10:44:59 2013 -0700 @@ -198,20 +198,7 @@ self.tipnode = cl.node(tiprev) self.tiprev = tiprev - # There may be branches that cease to exist when the last commit in the - # branch was stripped. This code filters them out. Note that the - # branch that ceased to exist may not be in newbranches because - # newbranches is the set of candidate heads, which when you strip the - # last commit in a branch will be the parent branch. - droppednodes = [] - for branch in self.keys(): - nodes = [head for head in self[branch] - if cl.hasnode(head)] - if not nodes: - droppednodes.extend(nodes) - del self[branch] - if ((not self.validfor(repo)) or (self.tipnode in droppednodes)): - + if not self.validfor(repo): # cache key are not valid anymore self.tipnode = nullid self.tiprev = nullrev diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/bundlerepo.py --- a/mercurial/bundlerepo.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/bundlerepo.py Tue Oct 01 10:44:59 2013 -0700 @@ -120,7 +120,7 @@ chain.append(iterrev) iterrev = self.index[iterrev][3] if text is None: - text = revlog.revlog.revision(self, iterrev) + text = self.baserevision(iterrev) while chain: delta = self._chunk(chain.pop()) @@ -130,6 +130,12 @@ self._cache = (node, rev, text) return text + def baserevision(self, nodeorrev): + # Revlog subclasses may override 'revision' method to modify format of + # content retrieved from revlog. To use bundlerevlog with such class one + # needs to override 'baserevision' and make more specific call here. + return revlog.revlog.revision(self, nodeorrev) + def addrevision(self, text, transaction, link, p1=None, p2=None, d=None): raise NotImplementedError def addgroup(self, revs, linkmapper, transaction): @@ -146,12 +152,21 @@ bundlerevlog.__init__(self, opener, self.indexfile, bundle, linkmapper) + def baserevision(self, nodeorrev): + # Although changelog doesn't override 'revision' method, some extensions + # may replace this class with another that does. Same story with + # manifest and filelog classes. + return changelog.changelog.revision(self, nodeorrev) + class bundlemanifest(bundlerevlog, manifest.manifest): def __init__(self, opener, bundle, linkmapper): manifest.manifest.__init__(self, opener) bundlerevlog.__init__(self, opener, self.indexfile, bundle, linkmapper) + def baserevision(self, nodeorrev): + return manifest.manifest.revision(self, nodeorrev) + class bundlefilelog(bundlerevlog, filelog.filelog): def __init__(self, opener, path, bundle, linkmapper, repo): filelog.filelog.__init__(self, opener, path) @@ -159,6 +174,9 @@ linkmapper) self._repo = repo + def baserevision(self, nodeorrev): + return filelog.filelog.revision(self, nodeorrev) + def _file(self, f): self._repo.file(f) diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/cmdutil.py --- a/mercurial/cmdutil.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/cmdutil.py Tue Oct 01 10:44:59 2013 -0700 @@ -84,7 +84,7 @@ raise util.Abort(_('outstanding uncommitted merge')) modified, added, removed, deleted = repo.status()[:4] if modified or added or removed or deleted: - raise util.Abort(_("outstanding uncommitted changes")) + raise util.Abort(_('uncommitted changes')) ctx = repo[None] for s in sorted(ctx.substate): if ctx.sub(s).dirty(): @@ -1172,12 +1172,34 @@ 'filenames')) # The slow path checks files modified in every changeset. - for i in sorted(revs): - ctx = change(i) - matches = filter(match, ctx.files()) - if matches: - fncache[i] = matches - wanted.add(i) + # This is really slow on large repos, so compute the set lazily. + class lazywantedset(object): + def __init__(self): + self.set = set() + self.revs = set(revs) + + # No need to worry about locality here because it will be accessed + # in the same order as the increasing window below. + def __contains__(self, value): + if value in self.set: + return True + elif not value in self.revs: + return False + else: + self.revs.discard(value) + ctx = change(value) + matches = filter(match, ctx.files()) + if matches: + fncache[value] = matches + self.set.add(value) + return True + return False + + def discard(self, value): + self.revs.discard(value) + self.set.discard(value) + + wanted = lazywantedset() class followfilter(object): def __init__(self, onlyfirst=False): diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/commands.py --- a/mercurial/commands.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/commands.py Tue Oct 01 10:44:59 2013 -0700 @@ -12,7 +12,8 @@ import hg, scmutil, util, revlog, copies, error, bookmarks import patch, help, encoding, templatekw, discovery import archival, changegroup, cmdutil, hbisect -import sshserver, hgweb, hgweb.server, commandserver +import sshserver, hgweb, commandserver +from hgweb import server as hgweb_server import merge as mergemod import minirst, revset, fileset import dagparser, context, simplemerge, graphmod @@ -1923,6 +1924,7 @@ util.writefile('.debugfsinfo', '') ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no')) ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no')) + ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no')) ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo') and 'yes' or 'no')) os.unlink('.debugfsinfo') @@ -4525,6 +4527,8 @@ ret = hg.update(repo, checkout) except util.Abort, inst: ui.warn(_("not updating: %s\n") % str(inst)) + if inst.hint: + ui.warn(_("(%s)\n") % inst.hint) return 0 if not ret and not checkout: if bookmarks.update(repo, [movemarkfrom], repo['.'].node()): @@ -5182,7 +5186,7 @@ class service(object): def init(self): util.setsignalhandler() - self.httpd = hgweb.server.create_server(ui, app) + self.httpd = hgweb_server.create_server(ui, app) if opts['port'] and not ui.verbose: return @@ -5846,7 +5850,7 @@ if check: c = repo[None] if c.dirty(merge=False, branch=False, missing=True): - raise util.Abort(_("uncommitted local changes")) + raise util.Abort(_("uncommitted changes")) if rev is None: rev = repo[repo[None].branch()].rev() mergemod._checkunknown(repo, repo[None], repo[rev]) diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/context.py --- a/mercurial/context.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/context.py Tue Oct 01 10:44:59 2013 -0700 @@ -16,11 +16,197 @@ propertycache = util.propertycache -class changectx(object): +class basectx(object): + """A basectx object represents the common logic for its children: + changectx: read-only context that is already present in the repo, + workingctx: a context that represents the working directory and can + be committed, + memctx: a context that represents changes in-memory and can also + be committed.""" + def __new__(cls, repo, changeid='', *args, **kwargs): + if isinstance(changeid, basectx): + return changeid + + o = super(basectx, cls).__new__(cls) + + o._repo = repo + o._rev = nullrev + o._node = nullid + + return o + + def __str__(self): + return short(self.node()) + + def __int__(self): + return self.rev() + + def __repr__(self): + return "<%s %s>" % (type(self).__name__, str(self)) + + def __eq__(self, other): + try: + return type(self) == type(other) and self._rev == other._rev + except AttributeError: + return False + + def __ne__(self, other): + return not (self == other) + + def __contains__(self, key): + return key in self._manifest + + def __getitem__(self, key): + return self.filectx(key) + + def __iter__(self): + for f in sorted(self._manifest): + yield f + + @propertycache + def substate(self): + return subrepo.state(self, self._repo.ui) + + def rev(self): + return self._rev + def node(self): + return self._node + def hex(self): + return hex(self.node()) + def manifest(self): + return self._manifest + def phasestr(self): + return phases.phasenames[self.phase()] + def mutable(self): + return self.phase() > phases.public + + def obsolete(self): + """True if the changeset is obsolete""" + return self.rev() in obsmod.getrevs(self._repo, 'obsolete') + + def extinct(self): + """True if the changeset is extinct""" + return self.rev() in obsmod.getrevs(self._repo, 'extinct') + + def unstable(self): + """True if the changeset is not obsolete but it's ancestor are""" + return self.rev() in obsmod.getrevs(self._repo, 'unstable') + + def bumped(self): + """True if the changeset try to be a successor of a public changeset + + Only non-public and non-obsolete changesets may be bumped. + """ + return self.rev() in obsmod.getrevs(self._repo, 'bumped') + + def divergent(self): + """Is a successors of a changeset with multiple possible successors set + + Only non-public and non-obsolete changesets may be divergent. + """ + return self.rev() in obsmod.getrevs(self._repo, 'divergent') + + def troubled(self): + """True if the changeset is either unstable, bumped or divergent""" + return self.unstable() or self.bumped() or self.divergent() + + def troubles(self): + """return the list of troubles affecting this changesets. + + Troubles are returned as strings. possible values are: + - unstable, + - bumped, + - divergent. + """ + troubles = [] + if self.unstable(): + troubles.append('unstable') + if self.bumped(): + troubles.append('bumped') + if self.divergent(): + troubles.append('divergent') + return troubles + + def parents(self): + """return contexts for each parent changeset""" + return self._parents + + def p1(self): + return self._parents[0] + + def p2(self): + if len(self._parents) == 2: + return self._parents[1] + return changectx(self._repo, -1) + + def _fileinfo(self, path): + if '_manifest' in self.__dict__: + try: + return self._manifest[path], self._manifest.flags(path) + except KeyError: + raise error.ManifestLookupError(self._node, path, + _('not found in manifest')) + if '_manifestdelta' in self.__dict__ or path in self.files(): + if path in self._manifestdelta: + return (self._manifestdelta[path], + self._manifestdelta.flags(path)) + node, flag = self._repo.manifest.find(self._changeset[0], path) + if not node: + raise error.ManifestLookupError(self._node, path, + _('not found in manifest')) + + return node, flag + + def filenode(self, path): + return self._fileinfo(path)[0] + + def flags(self, path): + try: + return self._fileinfo(path)[1] + except error.LookupError: + return '' + + def sub(self, path): + return subrepo.subrepo(self, path) + + def match(self, pats=[], include=None, exclude=None, default='glob'): + r = self._repo + return matchmod.match(r.root, r.getcwd(), pats, + include, exclude, default, + auditor=r.auditor, ctx=self) + + def diff(self, ctx2=None, match=None, **opts): + """Returns a diff generator for the given contexts and matcher""" + if ctx2 is None: + ctx2 = self.p1() + if ctx2 is not None: + ctx2 = self._repo[ctx2] + diffopts = patch.diffopts(self._repo.ui, opts) + return patch.diff(self._repo, ctx2.node(), self.node(), + match=match, opts=diffopts) + + @propertycache + def _dirs(self): + return scmutil.dirs(self._manifest) + + def dirs(self): + return self._dirs + + def dirty(self): + return False + +class changectx(basectx): """A changecontext object makes access to data related to a particular - changeset convenient.""" + changeset convenient. It represents a read-only context already presnt in + the repo.""" def __init__(self, repo, changeid=''): """changeid is a revision number, node, or tag""" + + # since basectx.__new__ already took care of copying the object, we + # don't need to do anything in __init__, so we just exit here + if isinstance(changeid, basectx): + return + if changeid == '': changeid = '.' self._repo = repo @@ -114,30 +300,12 @@ raise error.RepoLookupError( _("unknown revision '%s'") % changeid) - def __str__(self): - return short(self.node()) - - def __int__(self): - return self.rev() - - def __repr__(self): - return "" % str(self) - def __hash__(self): try: return hash(self._rev) except AttributeError: return id(self) - def __eq__(self, other): - try: - return self._rev == other._rev - except AttributeError: - return False - - def __ne__(self, other): - return not (self == other) - def __nonzero__(self): return self._rev != nullrev @@ -160,33 +328,11 @@ p = p[:-1] return [changectx(self._repo, x) for x in p] - @propertycache - def substate(self): - return subrepo.state(self, self._repo.ui) - - def __contains__(self, key): - return key in self._manifest - - def __getitem__(self, key): - return self.filectx(key) - - def __iter__(self): - for f in sorted(self._manifest): - yield f - def changeset(self): return self._changeset - def manifest(self): - return self._manifest def manifestnode(self): return self._changeset[0] - def rev(self): - return self._rev - def node(self): - return self._node - def hex(self): - return hex(self._node) def user(self): return self._changeset[1] def date(self): @@ -207,25 +353,9 @@ return self._repo.nodebookmarks(self._node) def phase(self): return self._repo._phasecache.phase(self._repo, self._rev) - def phasestr(self): - return phases.phasenames[self.phase()] - def mutable(self): - return self.phase() > phases.public def hidden(self): return self._rev in repoview.filterrevs(self._repo, 'visible') - def parents(self): - """return contexts for each parent changeset""" - return self._parents - - def p1(self): - return self._parents[0] - - def p2(self): - if len(self._parents) == 2: - return self._parents[1] - return changectx(self._repo, -1) - def children(self): """return contexts for each child changeset""" c = self._repo.changelog.children(self._node) @@ -239,80 +369,6 @@ for d in self._repo.changelog.descendants([self._rev]): yield changectx(self._repo, d) - def obsolete(self): - """True if the changeset is obsolete""" - return self.rev() in obsmod.getrevs(self._repo, 'obsolete') - - def extinct(self): - """True if the changeset is extinct""" - return self.rev() in obsmod.getrevs(self._repo, 'extinct') - - def unstable(self): - """True if the changeset is not obsolete but it's ancestor are""" - return self.rev() in obsmod.getrevs(self._repo, 'unstable') - - def bumped(self): - """True if the changeset try to be a successor of a public changeset - - Only non-public and non-obsolete changesets may be bumped. - """ - return self.rev() in obsmod.getrevs(self._repo, 'bumped') - - def divergent(self): - """Is a successors of a changeset with multiple possible successors set - - Only non-public and non-obsolete changesets may be divergent. - """ - return self.rev() in obsmod.getrevs(self._repo, 'divergent') - - def troubled(self): - """True if the changeset is either unstable, bumped or divergent""" - return self.unstable() or self.bumped() or self.divergent() - - def troubles(self): - """return the list of troubles affecting this changesets. - - Troubles are returned as strings. possible values are: - - unstable, - - bumped, - - divergent. - """ - troubles = [] - if self.unstable(): - troubles.append('unstable') - if self.bumped(): - troubles.append('bumped') - if self.divergent(): - troubles.append('divergent') - return troubles - - def _fileinfo(self, path): - if '_manifest' in self.__dict__: - try: - return self._manifest[path], self._manifest.flags(path) - except KeyError: - raise error.ManifestLookupError(self._node, path, - _('not found in manifest')) - if '_manifestdelta' in self.__dict__ or path in self.files(): - if path in self._manifestdelta: - return (self._manifestdelta[path], - self._manifestdelta.flags(path)) - node, flag = self._repo.manifest.find(self._changeset[0], path) - if not node: - raise error.ManifestLookupError(self._node, path, - _('not found in manifest')) - - return node, flag - - def filenode(self, path): - return self._fileinfo(path)[0] - - def flags(self, path): - try: - return self._fileinfo(path)[1] - except error.LookupError: - return '' - def filectx(self, path, fileid=None, filelog=None): """get a file context from this changeset""" if fileid is None: @@ -353,83 +409,15 @@ if match.bad(fn, _('no such file in rev %s') % self) and match(fn): yield fn - def sub(self, path): - return subrepo.subrepo(self, path) - - def match(self, pats=[], include=None, exclude=None, default='glob'): - r = self._repo - return matchmod.match(r.root, r.getcwd(), pats, - include, exclude, default, - auditor=r.auditor, ctx=self) - - def diff(self, ctx2=None, match=None, **opts): - """Returns a diff generator for the given contexts and matcher""" - if ctx2 is None: - ctx2 = self.p1() - if ctx2 is not None and not isinstance(ctx2, changectx): - ctx2 = self._repo[ctx2] - diffopts = patch.diffopts(self._repo.ui, opts) - return patch.diff(self._repo, ctx2.node(), self.node(), - match=match, opts=diffopts) - - @propertycache - def _dirs(self): - return scmutil.dirs(self._manifest) - - def dirs(self): - return self._dirs - - def dirty(self): - return False - -class filectx(object): - """A filecontext object makes access to data related to a particular - filerevision convenient.""" - def __init__(self, repo, path, changeid=None, fileid=None, - filelog=None, changectx=None): - """changeid can be a changeset revision, node, or tag. - fileid can be a file revision or node.""" - self._repo = repo - self._path = path - - assert (changeid is not None - or fileid is not None - or changectx is not None), \ - ("bad args: changeid=%r, fileid=%r, changectx=%r" - % (changeid, fileid, changectx)) - - if filelog is not None: - self._filelog = filelog - - if changeid is not None: - self._changeid = changeid - if changectx is not None: - self._changectx = changectx - if fileid is not None: - self._fileid = fileid - - @propertycache - def _changectx(self): - try: - return changectx(self._repo, self._changeid) - except error.RepoLookupError: - # Linkrev may point to any revision in the repository. When the - # repository is filtered this may lead to `filectx` trying to build - # `changectx` for filtered revision. In such case we fallback to - # creating `changectx` on the unfiltered version of the reposition. - # This fallback should not be an issue because `changectx` from - # `filectx` are not used in complex operations that care about - # filtering. - # - # This fallback is a cheap and dirty fix that prevent several - # crashes. It does not ensure the behavior is correct. However the - # behavior was not correct before filtering either and "incorrect - # behavior" is seen as better as "crash" - # - # Linkrevs have several serious troubles with filtering that are - # complicated to solve. Proper handling of the issue here should be - # considered when solving linkrev issue are on the table. - return changectx(self._repo.unfiltered(), self._changeid) +class basefilectx(object): + """A filecontext object represents the common logic for its children: + filectx: read-only access to a filerevision that is already present + in the repo, + workingfilectx: a filecontext that represents files from the working + directory, + memfilectx: a filecontext that represents files in-memory.""" + def __new__(cls, repo, path, *args, **kwargs): + return super(basefilectx, cls).__new__(cls) @propertycache def _filelog(self): @@ -468,10 +456,10 @@ return False def __str__(self): - return "%s@%s" % (self.path(), short(self.node())) + return "%s@%s" % (self.path(), self._changectx) def __repr__(self): - return "" % str(self) + return "<%s %s>" % (type(self).__name__, str(self)) def __hash__(self): try: @@ -481,7 +469,7 @@ def __eq__(self, other): try: - return (self._path == other._path + return (type(self) == type(other) and self._path == other._path and self._filenode == other._filenode) except AttributeError: return False @@ -489,12 +477,6 @@ def __ne__(self, other): return not (self == other) - def filectx(self, fileid): - '''opens an arbitrary revision of the file without - opening a new filelog''' - return filectx(self._repo, self._path, fileid=fileid, - filelog=self._filelog) - def filerev(self): return self._filerev def filenode(self): @@ -510,7 +492,7 @@ def node(self): return self._changectx.node() def hex(self): - return hex(self.node()) + return self._changectx.hex() def user(self): return self._changectx.user() def date(self): @@ -532,12 +514,8 @@ def changectx(self): return self._changectx - def data(self): - return self._filelog.read(self._filenode) def path(self): return self._path - def size(self): - return self._filelog.size(self._filerev) def isbinary(self): try: @@ -560,31 +538,6 @@ return True - def renamed(self): - """check if file was actually renamed in this changeset revision - - If rename logged in file revision, we report copy for changeset only - if file revisions linkrev points back to the changeset in question - or both changeset parents contain different file revisions. - """ - - renamed = self._filelog.renamed(self._filenode) - if not renamed: - return renamed - - if self.rev() == self.linkrev(): - return renamed - - name = self.path() - fnode = self._filenode - for p in self._changectx.parents(): - try: - if fnode == p.filenode(name): - return None - except error.LookupError: - pass - return renamed - def parents(self): p = self._path fl = self._filelog @@ -606,12 +559,6 @@ return p[1] return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog) - def children(self): - # hard for renames - c = self._filelog.children(self._filenode) - return [filectx(self._repo, self._path, fileid=x, - filelog=self._filelog) for x in c] - def annotate(self, follow=False, linenumber=None, diffopts=None): '''returns a list of tuples of (ctx, line) for each line in the file, where ctx is the filectx of the node where @@ -783,15 +730,100 @@ self._copycache[sc2] = copies.pathcopies(c2) return self._copycache[sc2] -class workingctx(changectx): - """A workingctx object makes access to data related to - the current working directory convenient. - date - any valid date string or (unixtime, offset), or None. - user - username string, or None. - extra - a dictionary of extra values, or None. - changes - a list of file lists as returned by localrepo.status() - or None to use the repository status. - """ +class filectx(basefilectx): + """A filecontext object makes access to data related to a particular + filerevision convenient.""" + def __init__(self, repo, path, changeid=None, fileid=None, + filelog=None, changectx=None): + """changeid can be a changeset revision, node, or tag. + fileid can be a file revision or node.""" + self._repo = repo + self._path = path + + assert (changeid is not None + or fileid is not None + or changectx is not None), \ + ("bad args: changeid=%r, fileid=%r, changectx=%r" + % (changeid, fileid, changectx)) + + if filelog is not None: + self._filelog = filelog + + if changeid is not None: + self._changeid = changeid + if changectx is not None: + self._changectx = changectx + if fileid is not None: + self._fileid = fileid + + @propertycache + def _changectx(self): + try: + return changectx(self._repo, self._changeid) + except error.RepoLookupError: + # Linkrev may point to any revision in the repository. When the + # repository is filtered this may lead to `filectx` trying to build + # `changectx` for filtered revision. In such case we fallback to + # creating `changectx` on the unfiltered version of the reposition. + # This fallback should not be an issue because `changectx` from + # `filectx` are not used in complex operations that care about + # filtering. + # + # This fallback is a cheap and dirty fix that prevent several + # crashes. It does not ensure the behavior is correct. However the + # behavior was not correct before filtering either and "incorrect + # behavior" is seen as better as "crash" + # + # Linkrevs have several serious troubles with filtering that are + # complicated to solve. Proper handling of the issue here should be + # considered when solving linkrev issue are on the table. + return changectx(self._repo.unfiltered(), self._changeid) + + def filectx(self, fileid): + '''opens an arbitrary revision of the file without + opening a new filelog''' + return filectx(self._repo, self._path, fileid=fileid, + filelog=self._filelog) + + def data(self): + return self._filelog.read(self._filenode) + def size(self): + return self._filelog.size(self._filerev) + + def renamed(self): + """check if file was actually renamed in this changeset revision + + If rename logged in file revision, we report copy for changeset only + if file revisions linkrev points back to the changeset in question + or both changeset parents contain different file revisions. + """ + + renamed = self._filelog.renamed(self._filenode) + if not renamed: + return renamed + + if self.rev() == self.linkrev(): + return renamed + + name = self.path() + fnode = self._filenode + for p in self._changectx.parents(): + try: + if fnode == p.filenode(name): + return None + except error.LookupError: + pass + return renamed + + def children(self): + # hard for renames + c = self._filelog.children(self._filenode) + return [filectx(self._repo, self._path, fileid=x, + filelog=self._filelog) for x in c] + +class committablectx(basectx): + """A committablectx object provides common functionality for a context that + wants the ability to commit, e.g. workingctx or memctx.""" def __init__(self, repo, text="", user=None, date=None, extra=None, changes=None): self._repo = repo @@ -827,9 +859,6 @@ def __str__(self): return str(self._parents[0]) + "+" - def __repr__(self): - return "" % str(self) - def __nonzero__(self): return True @@ -904,12 +933,6 @@ return man - def __iter__(self): - d = self._repo.dirstate - for f in d: - if d[f] != 'r': - yield f - @propertycache def _status(self): return self._repo.status()[:4] @@ -922,13 +945,6 @@ def _date(self): return util.makedate() - @propertycache - def _parents(self): - p = self._repo.dirstate.parents() - if p[1] == nullid: - p = p[:-1] - return [changectx(self._repo, x) for x in p] - def status(self, ignored=False, clean=False, unknown=False): """Explicit status query Unless this method is used to query the working copy status, the @@ -945,8 +961,6 @@ self._status = stat[:4] return stat - def manifest(self): - return self._manifest def user(self): return self._user or self._repo.ui.username() def date(self): @@ -1016,11 +1030,6 @@ except OSError: return '' - def filectx(self, path, filelog=None): - """get a file context from the working directory""" - return workingfilectx(self._repo, path, workingctx=self, - filelog=filelog) - def ancestor(self, c2): """return the ancestor context of self and c2""" return self._parents[0].ancestor(c2) # punt on two parents for now @@ -1029,6 +1038,61 @@ return sorted(self._repo.dirstate.walk(match, sorted(self.substate), True, False)) + def ancestors(self): + for a in self._repo.changelog.ancestors( + [p.rev() for p in self._parents]): + yield changectx(self._repo, a) + + def markcommitted(self, node): + """Perform post-commit cleanup necessary after committing this ctx + + Specifically, this updates backing stores this working context + wraps to reflect the fact that the changes reflected by this + workingctx have been committed. For example, it marks + modified and added files as normal in the dirstate. + + """ + + for f in self.modified() + self.added(): + self._repo.dirstate.normal(f) + for f in self.removed(): + self._repo.dirstate.drop(f) + self._repo.dirstate.setparents(node) + + def dirs(self): + return self._repo.dirstate.dirs() + +class workingctx(committablectx): + """A workingctx object makes access to data related to + the current working directory convenient. + date - any valid date string or (unixtime, offset), or None. + user - username string, or None. + extra - a dictionary of extra values, or None. + changes - a list of file lists as returned by localrepo.status() + or None to use the repository status. + """ + def __init__(self, repo, text="", user=None, date=None, extra=None, + changes=None): + super(workingctx, self).__init__(repo, text, user, date, extra, changes) + + def __iter__(self): + d = self._repo.dirstate + for f in d: + if d[f] != 'r': + yield f + + @propertycache + def _parents(self): + p = self._repo.dirstate.parents() + if p[1] == nullid: + p = p[:-1] + return [changectx(self._repo, x) for x in p] + + def filectx(self, path, filelog=None): + """get a file context from the working directory""" + return workingfilectx(self._repo, path, workingctx=self, + filelog=filelog) + def dirty(self, missing=False, merge=True, branch=True): "check whether a working directory is modified" # check subrepos first @@ -1093,11 +1157,6 @@ finally: wlock.release() - def ancestors(self): - for a in self._repo.changelog.ancestors( - [p.rev() for p in self._parents]): - yield changectx(self._repo, a) - def undelete(self, list): pctxs = self.parents() wlock = self._repo.wlock() @@ -1129,31 +1188,10 @@ finally: wlock.release() - def markcommitted(self, node): - """Perform post-commit cleanup necessary after committing this ctx - - Specifically, this updates backing stores this working context - wraps to reflect the fact that the changes reflected by this - workingctx have been committed. For example, it marks - modified and added files as normal in the dirstate. - - """ - - for f in self.modified() + self.added(): - self._repo.dirstate.normal(f) - for f in self.removed(): - self._repo.dirstate.drop(f) - self._repo.dirstate.setparents(node) - - def dirs(self): - return self._repo.dirstate.dirs() - -class workingfilectx(filectx): - """A workingfilectx object makes access to data related to a particular - file in the working directory convenient.""" - def __init__(self, repo, path, filelog=None, workingctx=None): - """changeid can be a changeset revision, node, or tag. - fileid can be a file revision or node.""" +class committablefilectx(basefilectx): + """A committablefilectx provides common functionality for a file context + that wants the ability to commit, e.g. workingfilectx or memfilectx.""" + def __init__(self, repo, path, filelog=None, ctx=None): self._repo = repo self._path = path self._changeid = None @@ -1161,30 +1199,12 @@ if filelog is not None: self._filelog = filelog - if workingctx: - self._changectx = workingctx - - @propertycache - def _changectx(self): - return workingctx(self._repo) + if ctx: + self._changectx = ctx def __nonzero__(self): return True - def __str__(self): - return "%s@%s" % (self.path(), self._changectx) - - def __repr__(self): - return "" % str(self) - - def data(self): - return self._repo.wread(self._path) - def renamed(self): - rp = self._repo.dirstate.copied(self._path) - if not rp: - return None - return rp, self._changectx._parents[0]._manifest.get(rp, nullid) - def parents(self): '''return parent filectxs, following copies if necessary''' def filenode(ctx, path): @@ -1209,6 +1229,24 @@ def children(self): return [] +class workingfilectx(committablefilectx): + """A workingfilectx object makes access to data related to a particular + file in the working directory convenient.""" + def __init__(self, repo, path, filelog=None, workingctx=None): + super(workingfilectx, self).__init__(repo, path, filelog, workingctx) + + @propertycache + def _changectx(self): + return workingctx(self._repo) + + def data(self): + return self._repo.wread(self._path) + def renamed(self): + rp = self._repo.dirstate.copied(self._path) + if not rp: + return None + return rp, self._changectx._parents[0]._manifest.get(rp, nullid) + def size(self): return os.lstat(self._repo.wjoin(self._path)).st_size def date(self): diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/dirstate.py --- a/mercurial/dirstate.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/dirstate.py Tue Oct 01 10:44:59 2013 -0700 @@ -801,12 +801,9 @@ mexact = match.exact dirignore = self._dirignore checkexec = self._checkexec - checklink = self._checklink copymap = self._copymap lastnormaltime = self._lastnormaltime - lnkkind = stat.S_IFLNK - # We need to do full walks when either # - we're listing all clean files, or # - match.traversedir does something, because match.traversedir should @@ -827,20 +824,14 @@ if not st and state in "nma": dadd(fn) elif state == 'n': - # The "mode & lnkkind != lnkkind or self._checklink" - # lines are an expansion of "islink => checklink" - # where islink means "is this a link?" and checklink - # means "can we check links?". mtime = int(st.st_mtime) if (size >= 0 and ((size != st.st_size and size != st.st_size & _rangemask) or ((mode ^ st.st_mode) & 0100 and checkexec)) - and (mode & lnkkind != lnkkind or checklink) or size == -2 # other parent or fn in copymap): madd(fn) - elif ((time != mtime and time != mtime & _rangemask) - and (mode & lnkkind != lnkkind or checklink)): + elif time != mtime and time != mtime & _rangemask: ladd(fn) elif mtime == lastnormaltime: # fn may have been changed in the same timeslot without diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/discovery.py --- a/mercurial/discovery.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/discovery.py Tue Oct 01 10:44:59 2013 -0700 @@ -269,13 +269,12 @@ allfuturecommon = set(c.node() for c in repo.set('%ld', outgoing.common)) allfuturecommon.update(allmissing) for branch, heads in sorted(headssum.iteritems()): - if heads[0] is None: - # Maybe we should abort if we push more that one head - # for new branches ? - continue candidate_newhs = set(heads[1]) # add unsynced data - oldhs = set(heads[0]) + if heads[0] is None: + oldhs = set() + else: + oldhs = set(heads[0]) oldhs.update(heads[2]) candidate_newhs.update(heads[2]) dhs = None @@ -310,7 +309,16 @@ newhs = candidate_newhs if [h for h in heads[2] if h not in discardedheads]: unsynced = True - if len(newhs) > len(oldhs): + if heads[0] is None: + if 1 < len(newhs): + dhs = list(newhs) + if error is None: + error = (_("push creates multiple headed new branch '%s'") + % (branch)) + hint = _("merge or" + " see \"hg help push\" for detail about" + " pushing new heads") + elif len(newhs) > len(oldhs): # strip updates to existing remote heads from the new heads list dhs = sorted(newhs - bookmarkedheads - oldhs) if dhs: diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/dispatch.py --- a/mercurial/dispatch.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/dispatch.py Tue Oct 01 10:44:59 2013 -0700 @@ -88,11 +88,47 @@ try: try: + debugger = 'pdb' + debugtrace = { + 'pdb' : pdb.set_trace + } + debugmortem = { + 'pdb' : pdb.post_mortem + } + + # read --config before doing anything else + # (e.g. to change trust settings for reading .hg/hgrc) + cfgs = _parseconfig(req.ui, _earlygetopt(['--config'], req.args)) + + if req.repo: + # copy configs that were passed on the cmdline (--config) to + # the repo ui + for cfg in cfgs: + req.repo.ui.setconfig(*cfg) + + debugger = ui.config("ui", "debugger") + if not debugger: + debugger = 'pdb' + + try: + debugmod = __import__(debugger) + except ImportError: + debugmod = pdb + + debugtrace[debugger] = debugmod.set_trace + debugmortem[debugger] = debugmod.post_mortem + # enter the debugger before command execution if '--debugger' in req.args: ui.warn(_("entering debugger - " "type c to continue starting hg or h for help\n")) - pdb.set_trace() + + if (debugger != 'pdb' and + debugtrace[debugger] == debugtrace['pdb']): + ui.warn(_("%s debugger specified " + "but its module was not found\n") % debugger) + + debugtrace[debugger]() try: return _dispatch(req) finally: @@ -101,7 +137,7 @@ # enter the debugger when we hit an exception if '--debugger' in req.args: traceback.print_exc() - pdb.post_mortem(sys.exc_info()[2]) + debugmortem[debugger](sys.exc_info()[2]) ui.traceback() raise @@ -619,10 +655,6 @@ args = req.args ui = req.ui - # read --config before doing anything else - # (e.g. to change trust settings for reading .hg/hgrc) - cfgs = _parseconfig(ui, _earlygetopt(['--config'], args)) - # check for cwd cwd = _earlygetopt(['--cwd'], args) if cwd: @@ -699,10 +731,6 @@ if req.repo: uis.add(req.repo.ui) - # copy configs that were passed on the cmdline (--config) to the repo ui - for cfg in cfgs: - req.repo.ui.setconfig(*cfg) - if options['verbose'] or options['debug'] or options['quiet']: for opt in ('verbose', 'debug', 'quiet'): val = str(bool(options[opt])) diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/extensions.py --- a/mercurial/extensions.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/extensions.py Tue Oct 01 10:44:59 2013 -0700 @@ -13,10 +13,18 @@ _order = [] _ignore = ['hbisect', 'bookmarks', 'parentrevspec', 'interhg'] -def extensions(): +def extensions(ui=None): + if ui: + def enabled(name): + for format in ['%s', 'hgext.%s']: + conf = ui.config('extensions', format % name) + if conf is not None and not conf.startswith('!'): + return True + else: + enabled = lambda name: True for name in _order: module = _extensions[name] - if module: + if module and enabled(name): yield name, module def find(name): diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/hg.py --- a/mercurial/hg.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/hg.py Tue Oct 01 10:44:59 2013 -0700 @@ -101,7 +101,7 @@ """return a repository object for the specified path""" obj = _peerlookup(path).instance(ui, path, create) ui = getattr(obj, "ui", ui) - for name, module in extensions.extensions(): + for name, module in extensions.extensions(ui): hook = getattr(module, 'reposetup', None) if hook: hook(ui, obj) diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/hgweb/webcommands.py --- a/mercurial/hgweb/webcommands.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/hgweb/webcommands.py Tue Oct 01 10:44:59 2013 -0700 @@ -9,13 +9,15 @@ import webutil from mercurial import error, encoding, archival, templater, templatefilters from mercurial.node import short, hex, nullid -from mercurial.util import binary +from mercurial import util from common import paritygen, staticfile, get_contact, ErrorResponse from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND from mercurial import graphmod, patch from mercurial import help as helpmod from mercurial import scmutil from mercurial.i18n import _ +from mercurial.error import ParseError, RepoLookupError, Abort +from mercurial import revset # __all__ is populated with the allowed commands. Be sure to add to it if # you're adding a new command, or the new command won't work. @@ -57,7 +59,7 @@ if guessmime: mt = mimetypes.guess_type(path)[0] if mt is None: - mt = binary(text) and 'application/binary' or 'text/plain' + mt = util.binary(text) and 'application/binary' or 'text/plain' if mt.startswith('text/'): mt += '; charset="%s"' % encoding.encoding @@ -69,7 +71,7 @@ text = fctx.data() parity = paritygen(web.stripecount) - if binary(text): + if util.binary(text): mt = mimetypes.guess_type(f)[0] or 'application/octet-stream' text = '(binary:%s)' % mt @@ -109,9 +111,14 @@ raise inst def _search(web, req, tmpl): + MODE_REVISION = 'rev' + MODE_KEYWORD = 'keyword' + MODE_REVSET = 'revset' - def changelist(**map): - count = 0 + def revsearch(ctx): + yield ctx + + def keywordsearch(query): lower = encoding.lower qw = lower(query).split() @@ -137,6 +144,62 @@ if miss: continue + yield ctx + + def revsetsearch(revs): + for r in revs: + yield web.repo[r] + + searchfuncs = { + MODE_REVISION: (revsearch, _('exact revision search')), + MODE_KEYWORD: (keywordsearch, _('literal keyword search')), + MODE_REVSET: (revsetsearch, _('revset expression search')), + } + + def getsearchmode(query): + try: + ctx = web.repo[query] + except (error.RepoError, error.LookupError): + # query is not an exact revision pointer, need to + # decide if it's a revset expession or keywords + pass + else: + return MODE_REVISION, ctx + + revdef = 'reverse(%s)' % query + try: + tree, pos = revset.parse(revdef) + except ParseError: + # can't parse to a revset tree + return MODE_KEYWORD, query + + if revset.depth(tree) <= 2: + # no revset syntax used + return MODE_KEYWORD, query + + if util.any((token, (value or '')[:3]) == ('string', 're:') + for token, value, pos in revset.tokenize(revdef)): + return MODE_KEYWORD, query + + funcsused = revset.funcsused(tree) + if not funcsused.issubset(revset.safesymbols): + return MODE_KEYWORD, query + + mfunc = revset.match(web.repo.ui, revdef) + try: + revs = mfunc(web.repo, list(web.repo)) + return MODE_REVSET, revs + # ParseError: wrongly placed tokens, wrongs arguments, etc + # RepoLookupError: no such revision, e.g. in 'revision:' + # Abort: bookmark/tag not exists + # LookupError: ambiguous identifier, e.g. in '(bc)' on a large repo + except (ParseError, RepoLookupError, Abort, LookupError): + return MODE_KEYWORD, query + + def changelist(**map): + count = 0 + + for ctx in searchfunc[0](funcarg): count += 1 n = ctx.node() showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n) @@ -176,35 +239,45 @@ morevars['revcount'] = revcount * 2 morevars['rev'] = query + mode, funcarg = getsearchmode(query) + + if 'forcekw' in req.form: + showforcekw = '' + showunforcekw = searchfuncs[mode][1] + mode = MODE_KEYWORD + funcarg = query + else: + if mode != MODE_KEYWORD: + showforcekw = searchfuncs[MODE_KEYWORD][1] + else: + showforcekw = '' + showunforcekw = '' + + searchfunc = searchfuncs[mode] + tip = web.repo['tip'] parity = paritygen(web.stripecount) return tmpl('search', query=query, node=tip.hex(), entries=changelist, archives=web.archivelist("tip"), - morevars=morevars, lessvars=lessvars) + morevars=morevars, lessvars=lessvars, + modedesc=searchfunc[1], + showforcekw=showforcekw, showunforcekw=showunforcekw) def changelog(web, req, tmpl, shortlog=False): query = '' if 'node' in req.form: ctx = webutil.changectx(web.repo, req) + elif 'rev' in req.form: + return _search(web, req, tmpl) else: - if 'rev' in req.form: - query = req.form['rev'][0] - hi = query - else: - hi = 'tip' - try: - ctx = web.repo[hi] - except (error.RepoError, error.LookupError): - return _search(web, req, tmpl) # XXX redirect to 404 page? + ctx = web.repo['tip'] - def changelist(latestonly, **map): + def changelist(): revs = [] if pos != -1: revs = web.repo.changelog.revs(pos, 0) - if latestonly: - revs = (revs.next(),) curcount = 0 for i in revs: ctx = web.repo[i] @@ -213,7 +286,7 @@ files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles) curcount += 1 - if curcount > revcount: + if curcount > revcount + 1: break yield {"parity": parity.next(), "author": ctx.user(), @@ -249,10 +322,18 @@ changenav = webutil.revnav(web.repo).gen(pos, revcount, count) + entries = list(changelist()) + latestentry = entries[:1] + if len(entries) > revcount: + nextentry = entries[-1:] + entries = entries[:-1] + else: + nextentry = [] + return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav, node=ctx.hex(), rev=pos, changesets=count, - entries=lambda **x: changelist(latestonly=False, **x), - latestentry=lambda **x: changelist(latestonly=True, **x), + entries=entries, + latestentry=latestentry, nextentry=nextentry, archives=web.archivelist("tip"), revcount=revcount, morevars=morevars, lessvars=lessvars, query=query) @@ -617,7 +698,7 @@ context = parsecontext(web.config('web', 'comparisoncontext', '5')) def filelines(f): - if binary(f.data()): + if util.binary(f.data()): mt = mimetypes.guess_type(f.path())[0] if not mt: mt = 'application/octet-stream' @@ -675,7 +756,7 @@ def annotate(**map): last = None - if binary(fctx.data()): + if util.binary(fctx.data()): mt = (mimetypes.guess_type(fctx.path())[0] or 'application/octet-stream') lines = enumerate([((fctx.filectx(fctx.filerev()), 1), diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/httpclient/__init__.py --- a/mercurial/httpclient/__init__.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/httpclient/__init__.py Tue Oct 01 10:44:59 2013 -0700 @@ -292,7 +292,7 @@ def __init__(self, host, port=None, use_ssl=None, ssl_validator=None, timeout=TIMEOUT_DEFAULT, continue_timeout=TIMEOUT_ASSUME_CONTINUE, - proxy_hostport=None, **ssl_opts): + proxy_hostport=None, ssl_wrap_socket=None, **ssl_opts): """Create a new HTTPConnection. Args: @@ -307,12 +307,23 @@ "100 Continue" response. Default is TIMEOUT_ASSUME_CONTINUE. proxy_hostport: Optional. Tuple of (host, port) to use as an http proxy for the connection. Default is to not use a proxy. + ssl_wrap_socket: Optional function to use for wrapping + sockets. If unspecified, the one from the ssl module will + be used if available, or something that's compatible with + it if on a Python older than 2.6. + + Any extra keyword arguments to this function will be provided + to the ssl_wrap_socket method. If no ssl """ if port is None and host.count(':') == 1 or ']:' in host: host, port = host.rsplit(':', 1) port = int(port) if '[' in host: host = host[1:-1] + if ssl_wrap_socket is not None: + self._ssl_wrap_socket = ssl_wrap_socket + else: + self._ssl_wrap_socket = socketutil.wrap_socket if use_ssl is None and port is None: use_ssl = False port = 80 @@ -387,7 +398,7 @@ sock.setblocking(1) logger.debug('wrapping socket for ssl with options %r', self.ssl_opts) - sock = socketutil.wrap_socket(sock, **self.ssl_opts) + sock = self._ssl_wrap_socket(sock, **self.ssl_opts) if self._ssl_validator: self._ssl_validator(sock) sock.setblocking(0) @@ -495,6 +506,10 @@ else: raise BadRequestData('body has no __len__() nor read()') + # If we're reusing the underlying socket, there are some + # conditions where we'll want to retry, so make a note of the + # state of self.sock + fresh_socket = self.sock is None self._connect() outgoing_headers = self._buildheaders( method, path, hdrs, self.http_version) @@ -640,6 +655,26 @@ # the whole request if response is None: response = self.response_class(self.sock, self.timeout, method) + if not fresh_socket: + if not response._select(): + # This means the response failed to get any response + # data at all, and in all probability the socket was + # closed before the server even saw our request. Try + # the request again on a fresh socket. + logging.debug('response._select() failed during request().' + ' Assuming request needs to be retried.') + self.sock = None + # Call this method explicitly to re-try the + # request. We don't use self.request() because + # some tools (notably Mercurial) expect to be able + # to subclass and redefine request(), and they + # don't have the same argspec as we do. + # + # TODO restructure sending of requests to avoid + # this recursion + return HTTPConnection.request( + self, method, path, body=body, headers=headers, + expect_continue=expect_continue) data_left = bool(outgoing_headers or body) if data_left: logger.info('stopped sending request early, ' diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/httpconnection.py --- a/mercurial/httpconnection.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/httpconnection.py Tue Oct 01 10:44:59 2013 -0700 @@ -275,14 +275,13 @@ if '[' in host: host = host[1:-1] - if keyfile: - kwargs['keyfile'] = keyfile - if certfile: - kwargs['certfile'] = certfile + kwargs['keyfile'] = keyfile + kwargs['certfile'] = certfile kwargs.update(sslutil.sslkwargs(self.ui, host)) con = HTTPConnection(host, port, use_ssl=True, + ssl_wrap_socket=sslutil.ssl_wrap_socket, ssl_validator=sslutil.validator(self.ui, host), **kwargs) return con diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/localrepo.py --- a/mercurial/localrepo.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/localrepo.py Tue Oct 01 10:44:59 2013 -0700 @@ -39,6 +39,8 @@ """propertycache that apply to unfiltered repo only""" def __get__(self, repo, type=None): + if hasunfilteredcache(repo, self.name): + return getattr(repo.unfiltered(), self.name) return super(unfilteredpropertycache, self).__get__(repo.unfiltered()) class filteredpropertycache(propertycache): @@ -144,12 +146,14 @@ class localrepository(object): supportedformats = set(('revlogv1', 'generaldelta')) - supported = supportedformats | set(('store', 'fncache', 'shared', - 'dotencode')) + _basesupported = supportedformats | set(('store', 'fncache', 'shared', + 'dotencode')) openerreqs = set(('revlogv1', 'generaldelta')) requirements = ['revlogv1'] filtername = None + featuresetupfuncs = set() + def _baserequirements(self, create): return self.requirements[:] @@ -174,6 +178,13 @@ except IOError: pass + if self.featuresetupfuncs: + self.supported = set(self._basesupported) # use private copy + for setupfunc in self.featuresetupfuncs: + setupfunc(self.ui, self.supported) + else: + self.supported = self._basesupported + if not self.vfs.isdir(): if create: if not self.wvfs.exists(): @@ -1457,14 +1468,8 @@ del mf[fn] return mf - if isinstance(node1, context.changectx): - ctx1 = node1 - else: - ctx1 = self[node1] - if isinstance(node2, context.changectx): - ctx2 = node2 - else: - ctx2 = self[node2] + ctx1 = self[node1] + ctx2 = self[node2] working = ctx2.rev() is None parentworking = working and ctx1 == self['.'] @@ -1561,7 +1566,7 @@ for f in modified: if ctx2.flags(f) == 'l': d = ctx2[f].data() - if len(d) >= 1024 or '\n' in d or util.binary(d): + if d == '' or len(d) >= 1024 or '\n' in d or util.binary(d): self.ui.debug('ignoring suspect symlink placeholder' ' "%s"\n' % f) continue @@ -1653,6 +1658,14 @@ return r def pull(self, remote, heads=None, force=False): + if remote.local(): + missing = set(remote.requirements) - self.supported + if missing: + msg = _("required features are not" + " supported in the destination:" + " %s") % (', '.join(sorted(missing))) + raise util.Abort(msg) + # don't open transaction for nothing or you break future useful # rollback call tr = None @@ -1753,6 +1766,14 @@ we have outgoing changesets but refused to push - other values as described by addchangegroup() ''' + if remote.local(): + missing = set(self.requirements) - remote.local().supported + if missing: + msg = _("required features are not" + " supported in the destination:" + " %s") % (', '.join(sorted(missing))) + raise util.Abort(msg) + # there are two ways to push to remote repo: # # addchangegroup assumes local user can lock remote diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/mail.py --- a/mercurial/mail.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/mail.py Tue Oct 01 10:44:59 2013 -0700 @@ -8,7 +8,11 @@ from i18n import _ import util, encoding, sslutil import os, smtplib, socket, quopri, time, sys -import email.Header, email.MIMEText, email.Utils +import email +# On python2.4 you have to import these by name or they fail to +# load. This was not a problem on Python 2.7. +import email.Header +import email.MIMEText _oldheaderinit = email.Header.Header.__init__ def _unifiedheaderinit(self, *args, **kw): diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/merge.py --- a/mercurial/merge.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/merge.py Tue Oct 01 10:44:59 2013 -0700 @@ -656,19 +656,21 @@ -c -C dirty rev | linear same cross n n n n | ok (1) x n n n y | ok ok ok - n n y * | merge (2) (2) + n n y n | merge (2) (2) + n n y y | merge (3) (3) n y * * | --- discard --- - y n y * | --- (3) --- + y n y * | --- (4) --- y n n * | --- ok --- - y y * * | --- (4) --- + y y * * | --- (5) --- x = can't happen * = don't-care - 1 = abort: crosses branches (use 'hg merge' or 'hg update -c') - 2 = abort: crosses branches (use 'hg merge' to merge or - use 'hg update -C' to discard changes) - 3 = abort: uncommitted local changes - 4 = incompatible options (checked in commands.py) + 1 = abort: not a linear update (merge or update --check to force update) + 2 = abort: uncommitted changes (commit and merge, or update --clean to + discard changes) + 3 = abort: uncommitted changes (commit or update --clean to discard changes) + 4 = abort: uncommitted changes (checked in commands.py) + 5 = incompatible options (checked in commands.py) Return the same tuple as applyupdates(). """ @@ -709,11 +711,11 @@ hint=_("use 'hg update' " "or check 'hg heads'")) if not force and (wc.files() or wc.deleted()): - raise util.Abort(_("outstanding uncommitted changes"), + raise util.Abort(_("uncommitted changes"), hint=_("use 'hg status' to list changes")) for s in sorted(wc.substate): if wc.sub(s).dirty(): - raise util.Abort(_("outstanding uncommitted changes in " + raise util.Abort(_("uncommitted changes in " "subrepository '%s'") % s) elif not overwrite: @@ -727,13 +729,18 @@ if repo[node].node() in foreground: pa = p1 # allow updating to successors elif dirty: - msg = _("crosses branches (merge branches or use" - " --clean to discard changes)") - raise util.Abort(msg) + msg = _("uncommitted changes") + if onode is None: + hint = _("commit and merge, or update --clean to" + " discard changes") + else: + hint = _("commit or update --clean to discard" + " changes") + raise util.Abort(msg, hint=hint) else: # node is none - msg = _("crosses branches (merge branches or update" - " --check to force update)") - raise util.Abort(msg) + msg = _("not a linear update") + hint = _("merge or update --check to force update") + raise util.Abort(msg, hint=hint) else: # Allow jumping branches if clean and specific rev given pa = p1 diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/obsolete.py --- a/mercurial/obsolete.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/obsolete.py Tue Oct 01 10:44:59 2013 -0700 @@ -371,7 +371,7 @@ lock.release() def syncpush(repo, remote): - """utility function to push bookmark to a remote + """utility function to push obsolete markers to a remote Exist mostly to allow overridding for experimentation purpose""" if (_enabled and repo.obsstore and @@ -387,7 +387,7 @@ repo.ui.warn(msg) def syncpull(repo, remote, gettransaction): - """utility function to pull bookmark to a remote + """utility function to pull obsolete markers from a remote The `gettransaction` is function that return the pull transaction, creating one if necessary. We return the transaction to inform the calling code that diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/parsers.c --- a/mercurial/parsers.c Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/parsers.c Tue Oct 01 10:44:59 2013 -0700 @@ -14,16 +14,32 @@ #include "util.h" +static int8_t hextable[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + static inline int hexdigit(const char *p, Py_ssize_t off) { - char c = p[off]; + int8_t val = hextable[(unsigned char)p[off]]; - if (c >= '0' && c <= '9') - return c - '0'; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; + if (val >= 0) { + return val; + } PyErr_SetString(PyExc_ValueError, "input contains non-hex character"); return 0; @@ -61,7 +77,7 @@ static PyObject *parse_manifest(PyObject *self, PyObject *args) { PyObject *mfdict, *fdict; - char *str, *cur, *start, *zero; + char *str, *start, *end; int len; if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest", @@ -70,30 +86,34 @@ &str, &len)) goto quit; - for (start = cur = str, zero = NULL; cur < str + len; cur++) { + start = str; + end = str + len; + while (start < end) { PyObject *file = NULL, *node = NULL; PyObject *flags = NULL; + char *zero = NULL, *newline = NULL; ptrdiff_t nlen; - if (!*cur) { - zero = cur; - continue; - } - else if (*cur != '\n') - continue; - + zero = memchr(start, '\0', end - start); if (!zero) { PyErr_SetString(PyExc_ValueError, "manifest entry has no separator"); goto quit; } + newline = memchr(zero + 1, '\n', end - (zero + 1)); + if (!newline) { + PyErr_SetString(PyExc_ValueError, + "manifest contains trailing garbage"); + goto quit; + } + file = PyBytes_FromStringAndSize(start, zero - start); if (!file) goto bail; - nlen = cur - zero - 1; + nlen = newline - zero - 1; node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen); if (!node) @@ -112,8 +132,7 @@ if (PyDict_SetItem(mfdict, file, node) == -1) goto bail; - start = cur + 1; - zero = NULL; + start = newline + 1; Py_XDECREF(flags); Py_XDECREF(node); @@ -126,12 +145,6 @@ goto quit; } - if (len > 0 && *(cur - 1) != '\n') { - PyErr_SetString(PyExc_ValueError, - "manifest contains trailing garbage"); - goto quit; - } - Py_INCREF(Py_None); return Py_None; quit: @@ -142,8 +155,8 @@ { PyObject *dmap, *cmap, *parents = NULL, *ret = NULL; PyObject *fname = NULL, *cname = NULL, *entry = NULL; - char *str, *cur, *end, *cpos; - int state, mode, size, mtime; + char state, *str, *cur, *end, *cpos; + int mode, size, mtime; unsigned int flen; int len; @@ -330,7 +343,7 @@ * this. */ if (PyDict_SetItem(map, k, dirstate_unset) == -1) goto bail; - mode = 0, size = -1, mtime = -1; + mtime = -1; } putbe32(mode, p); putbe32(size, p + 4); @@ -524,11 +537,12 @@ uncomp_len, base_rev, link_rev, parent_1, parent_2, c_node_id, 20); - if (entry) + if (entry) { PyObject_GC_UnTrack(entry); + Py_INCREF(entry); + } self->cache[pos] = entry; - Py_INCREF(entry); return entry; } @@ -1195,14 +1209,19 @@ long sp; bitmask *seen; + if (gca == NULL) + return PyErr_NoMemory(); + for (i = 0; i < revcount; i++) { if (revs[i] > maxrev) maxrev = revs[i]; } seen = calloc(sizeof(*seen), maxrev + 1); - if (seen == NULL) + if (seen == NULL) { + Py_DECREF(gca); return PyErr_NoMemory(); + } for (i = 0; i < revcount; i++) seen[revs[i]] = 1ull << i; diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/patch.py --- a/mercurial/patch.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/patch.py Tue Oct 01 10:44:59 2013 -0700 @@ -6,8 +6,12 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -import cStringIO, email.Parser, os, errno, re, posixpath +import cStringIO, email, os, errno, re, posixpath import tempfile, zlib, shutil +# On python2.4 you have to import these by name or they fail to +# load. This was not a problem on Python 2.7. +import email.Generator +import email.Parser from i18n import _ from node import hex, nullid, short diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/pure/parsers.py --- a/mercurial/pure/parsers.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/pure/parsers.py Tue Oct 01 10:44:59 2013 -0700 @@ -100,11 +100,11 @@ # systems with a granularity of 1 sec). This commonly happens # for at least a couple of files on 'update'. # The user could change the file without changing its size - # within the same second. Invalidate the file's stat data in + # within the same second. Invalidate the file's mtime in # dirstate, forcing future 'status' calls to compare the - # contents of the file. This prevents mistakenly treating such - # files as clean. - e = (e[0], 0, -1, -1) # mark entry as 'unset' + # contents of the file if the size is the same. This prevents + # mistakenly treating such files as clean. + e = (e[0], e[1], e[2], -1) dmap[f] = e if f in copymap: diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/revlog.py --- a/mercurial/revlog.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/revlog.py Tue Oct 01 10:44:59 2013 -0700 @@ -14,7 +14,7 @@ # import stuff from node for others to import from revlog from node import bin, hex, nullid, nullrev from i18n import _ -import ancestor, mdiff, parsers, error, util +import ancestor, mdiff, parsers, error, util, templatefilters import struct, zlib, errno _pack = struct.pack @@ -845,16 +845,43 @@ def _chunkraw(self, startrev, endrev): start = self.start(startrev) - length = self.end(endrev) - start + end = self.end(endrev) if self._inline: start += (startrev + 1) * self._io.size + end += (endrev + 1) * self._io.size + length = end - start return self._getchunk(start, length) def _chunk(self, rev): return decompress(self._chunkraw(rev, rev)) - def _chunkbase(self, rev): - return self._chunk(rev) + def _chunks(self, revs): + '''faster version of [self._chunk(rev) for rev in revs] + + Assumes that revs is in ascending order.''' + if not revs: + return [] + start = self.start + length = self.length + inline = self._inline + iosize = self._io.size + buffer = util.buffer + + l = [] + ladd = l.append + + # preload the cache + self._chunkraw(revs[0], revs[-1]) + offset, data = self._chunkcache + + for rev in revs: + chunkstart = start(rev) + if inline: + chunkstart += (rev + 1) * iosize + chunklength = length(rev) + ladd(decompress(buffer(data, chunkstart - offset, chunklength))) + + return l def _chunkclear(self): self._chunkcache = (0, '') @@ -919,21 +946,22 @@ else: iterrev -= 1 e = index[iterrev] - chain.reverse() - base = iterrev if iterrev == cachedrev: # cache hit text = self._cache[2] + else: + chain.append(iterrev) + chain.reverse() # drop cache to save memory self._cache = None - self._chunkraw(base, rev) + bins = self._chunks(chain) if text is None: - text = str(self._chunkbase(base)) + text = str(bins[0]) + bins = bins[1:] - bins = [self._chunk(r) for r in chain] text = mdiff.patches(text, bins) text = self._checkhash(text, node, rev) @@ -943,10 +971,16 @@ def _checkhash(self, text, node, rev): p1, p2 = self.parents(node) + self.checkhash(text, p1, p2, node, rev) + return text + + def checkhash(self, text, p1, p2, node, rev=None): if node != hash(text, p1, p2): - raise RevlogError(_("integrity check failed on %s:%d") - % (self.indexfile, rev)) - return text + revornode = rev + if revornode is None: + revornode = templatefilters.short(hex(node)) + raise RevlogError(_("integrity check failed on %s:%s") + % (self.indexfile, revornode)) def checkinlinesize(self, tr, fp=None): if not self._inline or (self.start(-2) + self.length(-2)) < _maxinline: @@ -987,7 +1021,8 @@ tr.replace(self.indexfile, trindex * self._io.size) self._chunkclear() - def addrevision(self, text, transaction, link, p1, p2, cachedelta=None): + def addrevision(self, text, transaction, link, p1, p2, cachedelta=None, + node=None): """add a revision to the log text - the revision data to add @@ -995,11 +1030,14 @@ link - the linkrev data to add p1, p2 - the parent nodeids of the revision cachedelta - an optional precomputed delta + node - nodeid of revision; typically node is not specified, and it is + computed by default as hash(text, p1, p2), however subclasses might + use different hashing method (and override checkhash() in such case) """ if link == nullrev: raise RevlogError(_("attempted to add linkrev -1 to %s") % self.indexfile) - node = hash(text, p1, p2) + node = node or hash(text, p1, p2) if node in self.nodemap: return node @@ -1063,9 +1101,7 @@ ifh.flush() basetext = self.revision(self.node(cachedelta[0])) btext[0] = mdiff.patch(basetext, cachedelta[1]) - chk = hash(btext[0], p1, p2) - if chk != node: - raise RevlogError(_("consistency error in delta")) + self.checkhash(btext[0], p1, p2, node) return btext[0] def builddelta(rev): diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/revset.py --- a/mercurial/revset.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/revset.py Tue Oct 01 10:44:59 2013 -0700 @@ -1599,6 +1599,75 @@ "_list": _list, } +# symbols which can't be used for a DoS attack for any given input +# (e.g. those which accept regexes as plain strings shouldn't be included) +# functions that just return a lot of changesets (like all) don't count here +safesymbols = set([ + "adds", + "all", + "ancestor", + "ancestors", + "_firstancestors", + "author", + "bisect", + "bisected", + "bookmark", + "branch", + "branchpoint", + "bumped", + "bundle", + "children", + "closed", + "converted", + "date", + "desc", + "descendants", + "_firstdescendants", + "destination", + "divergent", + "draft", + "extinct", + "extra", + "file", + "filelog", + "first", + "follow", + "_followfirst", + "head", + "heads", + "hidden", + "id", + "keyword", + "last", + "limit", + "_matchfiles", + "max", + "merge", + "min", + "modifies", + "obsolete", + "origin", + "outgoing", + "p1", + "p2", + "parents", + "present", + "public", + "remote", + "removes", + "rev", + "reverse", + "roots", + "sort", + "secret", + "matching", + "tag", + "tagged", + "user", + "unstable", + "_list", +]) + methods = { "range": rangeset, "dagrange": dagrange, @@ -1935,5 +2004,22 @@ output = '\n'.join((' '*l + s) for l, s in lines) return output +def depth(tree): + if isinstance(tree, tuple): + return max(map(depth, tree)) + 1 + else: + return 0 + +def funcsused(tree): + if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'): + return set() + else: + funcs = set() + for s in tree[1:]: + funcs |= funcsused(s) + if tree[0] == 'func': + funcs.add(tree[1][1]) + return funcs + # tell hggettext to extract docstrings from these functions: i18nfunctions = symbols.values() diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/scmutil.py --- a/mercurial/scmutil.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/scmutil.py Tue Oct 01 10:44:59 2013 -0700 @@ -755,7 +755,8 @@ ctx = repo[None] dirstate = repo.dirstate - walkresults = dirstate.walk(matcher, sorted(ctx.substate), True, False) + walkresults = dirstate.walk(matcher, sorted(ctx.substate), True, False, + full=False) for abs, st in walkresults.iteritems(): dstate = dirstate[abs] if dstate == '?' and audit_path.check(abs): diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/sslutil.py --- a/mercurial/sslutil.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/sslutil.py Tue Oct 01 10:44:59 2013 -0700 @@ -14,10 +14,13 @@ # avoid using deprecated/broken FakeSocket in python 2.6 import ssl CERT_REQUIRED = ssl.CERT_REQUIRED - def ssl_wrap_socket(sock, keyfile, certfile, + PROTOCOL_SSLv23 = ssl.PROTOCOL_SSLv23 + PROTOCOL_TLSv1 = ssl.PROTOCOL_TLSv1 + def ssl_wrap_socket(sock, keyfile, certfile, ssl_version=PROTOCOL_TLSv1, cert_reqs=ssl.CERT_NONE, ca_certs=None): sslsocket = ssl.wrap_socket(sock, keyfile, certfile, - cert_reqs=cert_reqs, ca_certs=ca_certs) + cert_reqs=cert_reqs, ca_certs=ca_certs, + ssl_version=ssl_version) # check if wrap_socket failed silently because socket had been closed # - see http://bugs.python.org/issue13721 if not sslsocket.cipher(): @@ -26,9 +29,12 @@ except ImportError: CERT_REQUIRED = 2 + PROTOCOL_SSLv23 = 2 + PROTOCOL_TLSv1 = 3 + import socket, httplib - def ssl_wrap_socket(sock, key_file, cert_file, + def ssl_wrap_socket(sock, keyfile, certfile, ssl_version=PROTOCOL_TLSv1, cert_reqs=CERT_REQUIRED, ca_certs=None): if not util.safehasattr(socket, 'ssl'): raise util.Abort(_('Python SSL support not found')) @@ -36,7 +42,7 @@ raise util.Abort(_( 'certificate checking requires Python 2.6')) - ssl = socket.ssl(sock, key_file, cert_file) + ssl = socket.ssl(sock, keyfile, certfile) return httplib.FakeSocket(sock, ssl) def _verifycert(cert, hostname): @@ -84,15 +90,22 @@ def sslkwargs(ui, host): cacerts = ui.config('web', 'cacerts') + forcetls = ui.configbool('ui', 'tls', default=True) + if forcetls: + ssl_version = PROTOCOL_TLSv1 + else: + ssl_version = PROTOCOL_SSLv23 hostfingerprint = ui.config('hostfingerprints', host) + kws = {'ssl_version': ssl_version, + } if cacerts and not hostfingerprint: cacerts = util.expandpath(cacerts) if not os.path.exists(cacerts): raise util.Abort(_('could not find web.cacerts: %s') % cacerts) - return {'ca_certs': cacerts, - 'cert_reqs': CERT_REQUIRED, - } - return {} + kws.update({'ca_certs': cacerts, + 'cert_reqs': CERT_REQUIRED, + }) + return kws class validator(object): def __init__(self, ui, host): diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/statichttprepo.py --- a/mercurial/statichttprepo.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/statichttprepo.py Tue Oct 01 10:44:59 2013 -0700 @@ -89,6 +89,8 @@ return False class statichttprepository(localrepo.localrepository): + supported = localrepo.localrepository._basesupported + def __init__(self, ui, path): self._url = path self.ui = ui diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/subrepo.py --- a/mercurial/subrepo.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/subrepo.py Tue Oct 01 10:44:59 2013 -0700 @@ -5,7 +5,8 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -import errno, os, re, xml.dom.minidom, shutil, posixpath, sys +import errno, os, re, shutil, posixpath, sys +import xml.dom.minidom import stat, subprocess, tarfile from i18n import _ import config, scmutil, util, node, error, cmdutil, bookmarks, match as matchmod @@ -201,9 +202,24 @@ wctx.sub(s).get(r, overwrite) sm[s] = r else: - debug(s, "both sides changed, merge with", r) - wctx.sub(s).merge(r) - sm[s] = l + debug(s, "both sides changed") + option = repo.ui.promptchoice( + _(' subrepository %s diverged (local revision: %s, ' + 'remote revision: %s)\n' + '(M)erge, keep (l)ocal or keep (r)emote?' + '$$ &Merge $$ &Local $$ &Remote') + % (s, l[1][:12], r[1][:12]), 0) + if option == 0: + wctx.sub(s).merge(r) + sm[s] = l + debug(s, "merge with", r) + elif option == 1: + sm[s] = l + debug(s, "keep local subrepo revision", l) + else: + wctx.sub(s).get(r, overwrite) + sm[s] = r + debug(s, "get remote subrepo revision", r) elif ld == a: # remote removed, local unchanged debug(s, "remote removed, remove") wctx.sub(s).remove() @@ -237,6 +253,7 @@ # record merged .hgsubstate writestate(repo, sm) + return sm def _updateprompt(ui, sub, dirty, local, remote): if dirty: diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templatefilters.py --- a/mercurial/templatefilters.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templatefilters.py Tue Oct 01 10:44:59 2013 -0700 @@ -15,15 +15,15 @@ """ return text.replace('\n', '
\n') -agescales = [("year", 3600 * 24 * 365), - ("month", 3600 * 24 * 30), - ("week", 3600 * 24 * 7), - ("day", 3600 * 24), - ("hour", 3600), - ("minute", 60), - ("second", 1)] +agescales = [("year", 3600 * 24 * 365, 'Y'), + ("month", 3600 * 24 * 30, 'M'), + ("week", 3600 * 24 * 7, 'W'), + ("day", 3600 * 24, 'd'), + ("hour", 3600, 'h'), + ("minute", 60, 'm'), + ("second", 1, 's')] -def age(date): +def age(date, abbrev=False): """:age: Date. Returns a human-readable date/time difference between the given date/time and the current date/time. """ @@ -32,7 +32,9 @@ if c == 1: return t return t + "s" - def fmt(t, c): + def fmt(t, c, a): + if abbrev: + return "%d%s" % (c, a) return "%d %s" % (c, plural(t, c)) now = time.time() @@ -48,12 +50,12 @@ if delta > agescales[0][1] * 2: return util.shortdate(date) - for t, s in agescales: + for t, s, a in agescales: n = delta // s if n >= 2 or s == 1: if future: - return '%s from now' % fmt(t, n) - return '%s ago' % fmt(t, n) + return '%s from now' % fmt(t, n, a) + return '%s ago' % fmt(t, n, a) def basename(path): """:basename: Any text. Treats the text as a path, and returns the last diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templater.py --- a/mercurial/templater.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templater.py Tue Oct 01 10:44:59 2013 -0700 @@ -139,7 +139,12 @@ def runsymbol(context, mapping, key): v = mapping.get(key) if v is None: - v = context._defaults.get(key, '') + v = context._defaults.get(key) + if v is None: + try: + v = context.process(key, mapping) + except TemplateNotFound: + v = '' if util.safehasattr(v, '__call__'): return v(**mapping) if isinstance(v, types.GeneratorType): @@ -449,6 +454,9 @@ stylelist.append(split[1]) return ", ".join(sorted(stylelist)) +class TemplateNotFound(util.Abort): + pass + class templater(object): def __init__(self, mapfile, filters={}, defaults={}, cache={}, @@ -500,7 +508,8 @@ try: self.cache[t] = util.readfile(self.map[t][1]) except KeyError, inst: - raise util.Abort(_('"%s" not in template map') % inst.args[0]) + raise TemplateNotFound(_('"%s" not in template map') % + inst.args[0]) except IOError, inst: raise IOError(inst.args[0], _('template file %s: %s') % (self.map[t][1], inst.args[1])) diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/paper/bookmarks.tmpl --- a/mercurial/templates/paper/bookmarks.tmpl Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/paper/bookmarks.tmpl Tue Oct 01 10:44:59 2013 -0700 @@ -38,8 +38,7 @@ diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/paper/branches.tmpl --- a/mercurial/templates/paper/branches.tmpl Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/paper/branches.tmpl Tue Oct 01 10:44:59 2013 -0700 @@ -38,8 +38,7 @@ {sessionvars%hiddenformentry}

-
find changesets by author, revision, -files, or words in the commit message
+
{searchhint}
diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/paper/changeset.tmpl --- a/mercurial/templates/paper/changeset.tmpl Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/paper/changeset.tmpl Tue Oct 01 10:44:59 2013 -0700 @@ -36,8 +36,7 @@ {sessionvars%hiddenformentry}

-
find changesets by author, revision, -files, or words in the commit message
+
{searchhint}
{desc|strip|escape|websub|nonempty}
diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/paper/error.tmpl --- a/mercurial/templates/paper/error.tmpl Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/paper/error.tmpl Tue Oct 01 10:44:59 2013 -0700 @@ -29,8 +29,7 @@ {sessionvars%hiddenformentry}

-
find changesets by author, revision, -files, or words in the commit message
+
{searchhint}
diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/paper/fileannotate.tmpl --- a/mercurial/templates/paper/fileannotate.tmpl Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/paper/fileannotate.tmpl Tue Oct 01 10:44:59 2013 -0700 @@ -42,8 +42,7 @@ {sessionvars%hiddenformentry}

-
find changesets by author, revision, -files, or words in the commit message
+
{searchhint}
{desc|strip|escape|websub|nonempty}
@@ -65,7 +64,6 @@
-{changesettag}
children {child%filerevchild}
diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/paper/filecomparison.tmpl --- a/mercurial/templates/paper/filecomparison.tmpl Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/paper/filecomparison.tmpl Tue Oct 01 10:44:59 2013 -0700 @@ -41,8 +41,7 @@
{desc|strip|escape|websub|nonempty}
@@ -64,7 +63,6 @@ children {child%filerevchild} -{changesettag}
diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/paper/filediff.tmpl --- a/mercurial/templates/paper/filediff.tmpl Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/paper/filediff.tmpl Tue Oct 01 10:44:59 2013 -0700 @@ -41,8 +41,7 @@
{desc|strip|escape|websub|nonempty}
@@ -64,7 +63,6 @@ children {child%filerevchild} -{changesettag}
diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/paper/filelog.tmpl --- a/mercurial/templates/paper/filelog.tmpl Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/paper/filelog.tmpl Tue Oct 01 10:44:59 2013 -0700 @@ -49,8 +49,7 @@ diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/paper/help.tmpl --- a/mercurial/templates/paper/help.tmpl Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/paper/help.tmpl Tue Oct 01 10:44:59 2013 -0700 @@ -28,8 +28,7 @@
{rstdoc(doc, "html")} diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/paper/helptopics.tmpl --- a/mercurial/templates/paper/helptopics.tmpl Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/paper/helptopics.tmpl Tue Oct 01 10:44:59 2013 -0700 @@ -26,8 +26,7 @@ diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/paper/manifest.tmpl --- a/mercurial/templates/paper/manifest.tmpl Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/paper/manifest.tmpl Tue Oct 01 10:44:59 2013 -0700 @@ -35,8 +35,7 @@ {sessionvars%hiddenformentry}

-
find changesets by author, revision, -files, or words in the commit message
+
{searchhint}

Topics

diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/paper/map --- a/mercurial/templates/paper/map Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/paper/map Tue Oct 01 10:44:59 2013 -0700 @@ -243,3 +243,6 @@ urlparameter = '{separator}{name}={value|urlescape}' hiddenformentry = '' breadcrumb = '> {name|escape} ' + +searchhint = 'Find changesets by keywords (author, files, the commit message), revision + number or hash, or revset expression.' diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/paper/search.tmpl --- a/mercurial/templates/paper/search.tmpl Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/paper/search.tmpl Tue Oct 01 10:44:59 2013 -0700 @@ -23,11 +23,18 @@

searching for '{query|escape}'

+

+Assuming {modedesc}. +{if(showforcekw, ' +Use {showforcekw} instead.')} +{if(showunforcekw, ' +Use {showunforcekw} instead.')} +

+ {sessionvars%hiddenformentry}

-
find changesets by author, revision, -files, or words in the commit message
+
{searchhint}
diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/paper/shortlogentry.tmpl --- a/mercurial/templates/paper/shortlogentry.tmpl Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/paper/shortlogentry.tmpl Tue Oct 01 10:44:59 2013 -0700 @@ -1,5 +1,5 @@ - + diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/paper/tags.tmpl --- a/mercurial/templates/paper/tags.tmpl Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/paper/tags.tmpl Tue Oct 01 10:44:59 2013 -0700 @@ -37,8 +37,7 @@ {sessionvars%hiddenformentry}

-
find changesets by author, revision, -files, or words in the commit message
+
{searchhint}
{date|rfc822date} {author|person}{desc|strip|firstline|escape|nonempty}{inbranch%changelogbranchname}{branches%changelogbranchhead}{tags % '{name|escape} '}{bookmarks % '{name|escape} '}{desc|strip|firstline|escape|nonempty}{inbranch%changelogbranchname}{branches%changelogbranchhead}{tags%changelogtag}{bookmarks%changelogtag}
diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/raw/search.tmpl --- a/mercurial/templates/raw/search.tmpl Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/raw/search.tmpl Tue Oct 01 10:44:59 2013 -0700 @@ -2,5 +2,6 @@ # HG changesets search # Node ID {node} # Query "{query}" +# Mode {modedesc} {entries%changelogentry} diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/static/mercurial.js --- a/mercurial/templates/static/mercurial.js Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/static/mercurial.js Tue Oct 01 10:44:59 2013 -0700 @@ -23,7 +23,7 @@ ]; function Graph() { - + this.canvas = document.getElementById('graph'); if (window.G_vmlCanvasManager) this.canvas = window.G_vmlCanvasManager.initElement(this.canvas); this.ctx = this.canvas.getContext('2d'); @@ -35,13 +35,21 @@ this.cell = [2, 0]; this.columns = 0; this.revlink = ''; - + + this.reset = function() { + this.bg = [0, 4]; + this.cell = [2, 0]; + this.columns = 0; + document.getElementById('nodebgs').innerHTML = ''; + document.getElementById('graphnodes').innerHTML = ''; + } + this.scale = function(height) { this.bg_height = height; this.box_size = Math.floor(this.bg_height / 1.2); this.cell_height = this.box_size; } - + function colorPart(num) { num *= 255 num = num < 0 ? 0 : num; @@ -55,7 +63,7 @@ } this.setColor = function(color, bg, fg) { - + // Set the colour. // // If color is a string, expect an hexadecimal RGB @@ -81,11 +89,11 @@ this.ctx.strokeStyle = s; this.ctx.fillStyle = s; return s; - + } this.edge = function(x0, y0, x1, y1, color, width) { - + this.setColor(color, 0.0, 0.65); if(width >= 0) this.ctx.lineWidth = width; @@ -93,28 +101,28 @@ this.ctx.moveTo(x0, y0); this.ctx.lineTo(x1, y1); this.ctx.stroke(); - + } this.render = function(data) { - + var backgrounds = ''; var nodedata = ''; - + for (var i in data) { - + var parity = i % 2; this.cell[1] += this.bg_height; this.bg[1] += this.bg_height; - + var cur = data[i]; var node = cur[1]; var edges = cur[2]; var fold = false; - + var prevWidth = this.ctx.lineWidth; for (var j in edges) { - + line = edges[j]; start = line[0]; end = line[1]; @@ -125,50 +133,50 @@ var branchcolor = line[4]; if(branchcolor) color = branchcolor; - + if (end > this.columns || start > this.columns) { this.columns += 1; } - + if (start == this.columns && start > end) { var fold = true; } - + x0 = this.cell[0] + this.box_size * start + this.box_size / 2; y0 = this.bg[1] - this.bg_height / 2; x1 = this.cell[0] + this.box_size * end + this.box_size / 2; y1 = this.bg[1] + this.bg_height / 2; - + this.edge(x0, y0, x1, y1, color, width); - + } this.ctx.lineWidth = prevWidth; - + // Draw the revision node in the right column - + column = node[0] color = node[1] - + radius = this.box_size / 8; x = this.cell[0] + this.box_size * column + this.box_size / 2; y = this.bg[1] - this.bg_height / 2; var add = this.vertex(x, y, color, parity, cur); backgrounds += add[0]; nodedata += add[1]; - + if (fold) this.columns -= 1; - + } - + document.getElementById('nodebgs').innerHTML += backgrounds; document.getElementById('graphnodes').innerHTML += nodedata; - + } } -process_dates = (function(document, RegExp, Math, isNaN, Date, _false, _true){ +function process_dates(){ // derived from code from mercurial/templatefilter.py @@ -219,9 +227,9 @@ var delta = Math.floor((now.getTime() - once.getTime()) / 1000); - var future = _false; + var future = false; if (delta < 0){ - future = _true; + future = true; delta = -delta; if (delta > (30 * scales.year)){ return "in the distant future"; @@ -245,25 +253,24 @@ } } - return function(){ - var nodes = document.getElementsByTagName('*'); - var ageclass = new RegExp('\\bage\\b'); - var dateclass = new RegExp('\\bdate\\b'); - for (var i=0; i<\/canvas>$/m)[1]; + addHeight = parseInt(addHeight); + graph.canvas.height = addHeight; + + var dataStr = htmlText.match(/^\s*var data = (.*);$/m)[1]; + var data = JSON.parse(dataStr) + graph.reset(); + graph.render(data); + } else { + var doc = docFromHTML(htmlText); + var nodes = doc.querySelector(containerSelector).children; + while (nodes.length) { + var node = nodes[0]; + node = document.adoptNode(node); + container.appendChild(node); + } + process_dates(); + } + }, + function onerror(errorText) { + var message = { + class: 'scroll-loading-error', + text: 'Error: ' + errorText + }; + appendFormatHTML(container, messageFormat, message); + }, + function oncomplete() { + removeByClassName('scroll-loading'); + updateInitiated = false; + scrollHandler(); + } + ); + } + } + + window.addEventListener('scroll', scrollHandler); + window.addEventListener('resize', scrollHandler); + scrollHandler(); +} diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/templates/static/style-paper.css --- a/mercurial/templates/static/style-paper.css Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/templates/static/style-paper.css Tue Oct 01 10:44:59 2013 -0700 @@ -382,3 +382,27 @@ .breadcrumb a { color: blue; } + +.scroll-loading { + -webkit-animation: change_color 1s linear 0s infinite alternate; + -moz-animation: change_color 1s linear 0s infinite alternate; + -o-animation: change_color 1s linear 0s infinite alternate; + animation: change_color 1s linear 0s infinite alternate; +} + +@-webkit-keyframes change_color { + from { background-color: #A0CEFF; } to { } +} +@-moz-keyframes change_color { + from { background-color: #A0CEFF; } to { } +} +@-o-keyframes change_color { + from { background-color: #A0CEFF; } to { } +} +@keyframes change_color { + from { background-color: #A0CEFF; } to { } +} + +.scroll-loading-error { + background-color: #FFCCCC !important; +} diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/ui.py --- a/mercurial/ui.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/ui.py Tue Oct 01 10:44:59 2013 -0700 @@ -176,7 +176,7 @@ alternates = [name] for n in alternates: - value = self._data(untrusted).get(section, name, None) + value = self._data(untrusted).get(section, n, None) if value is not None: name = n break @@ -184,10 +184,11 @@ value = default if self.debugflag and not untrusted and self._reportuntrusted: - uvalue = self._ucfg.get(section, name) - if uvalue is not None and uvalue != value: - self.debug("ignoring untrusted configuration option " - "%s.%s = %s\n" % (section, name, uvalue)) + for n in alternates: + uvalue = self._ucfg.get(section, n) + if uvalue is not None and uvalue != value: + self.debug("ignoring untrusted configuration option " + "%s.%s = %s\n" % (section, n, uvalue)) return value def configpath(self, section, name, default=None, untrusted=False): diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/unionrepo.py --- a/mercurial/unionrepo.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/unionrepo.py Tue Oct 01 10:44:59 2013 -0700 @@ -70,7 +70,7 @@ self.revlog2.rev(self.node(rev1)), self.revlog2.rev(self.node(rev2))) elif rev1 <= self.repotiprev and rev2 <= self.repotiprev: - return revlog.revlog.revdiff(self, rev1, rev2) + return self.baserevdiff(rev1, rev2) return mdiff.textdiff(self.revision(self.node(rev1)), self.revision(self.node(rev2))) @@ -93,10 +93,20 @@ text = self.revlog2.revision(node) self._cache = (node, rev, text) else: - text = revlog.revlog.revision(self, rev) + text = self.baserevision(rev) # already cached return text + def baserevision(self, nodeorrev): + # Revlog subclasses may override 'revision' method to modify format of + # content retrieved from revlog. To use unionrevlog with such class one + # needs to override 'baserevision' and make more specific call here. + return revlog.revlog.revision(self, nodeorrev) + + def baserevdiff(self, rev1, rev2): + # Exists for the same purpose as baserevision. + return revlog.revlog.revdiff(self, rev1, rev2) + def addrevision(self, text, transaction, link, p1=None, p2=None, d=None): raise NotImplementedError def addgroup(self, revs, linkmapper, transaction): @@ -114,6 +124,15 @@ unionrevlog.__init__(self, opener, self.indexfile, changelog2, linkmapper) + def baserevision(self, nodeorrev): + # Although changelog doesn't override 'revision' method, some extensions + # may replace this class with another that does. Same story with + # manifest and filelog classes. + return changelog.changelog.revision(self, nodeorrev) + + def baserevdiff(self, rev1, rev2): + return changelog.changelog.revdiff(self, rev1, rev2) + class unionmanifest(unionrevlog, manifest.manifest): def __init__(self, opener, opener2, linkmapper): manifest.manifest.__init__(self, opener) @@ -121,6 +140,12 @@ unionrevlog.__init__(self, opener, self.indexfile, manifest2, linkmapper) + def baserevision(self, nodeorrev): + return manifest.manifest.revision(self, nodeorrev) + + def baserevdiff(self, rev1, rev2): + return manifest.manifest.revdiff(self, rev1, rev2) + class unionfilelog(unionrevlog, filelog.filelog): def __init__(self, opener, path, opener2, linkmapper, repo): filelog.filelog.__init__(self, opener, path) @@ -129,6 +154,12 @@ linkmapper) self._repo = repo + def baserevision(self, nodeorrev): + return filelog.filelog.revision(self, nodeorrev) + + def baserevdiff(self, rev1, rev2): + return filelog.filelog.revdiff(self, rev1, rev2) + def _file(self, f): self._repo.file(f) diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/url.py --- a/mercurial/url.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/url.py Tue Oct 01 10:44:59 2013 -0700 @@ -108,8 +108,13 @@ def proxy_open(self, req, proxy, type_): host = req.get_host().split(':')[0] - if host in self.no_list: - return None + for e in self.no_list: + if host == e: + return None + if e.startswith('*.') and host.endswith(e[2:]): + return None + if e.startswith('.') and host.endswith(e[1:]): + return None # work around a bug in Python < 2.4.2 # (it leaves a "\n" at the end of Proxy-authorization headers) diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/util.h --- a/mercurial/util.h Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/util.h Tue Oct 01 10:44:59 2013 -0700 @@ -121,7 +121,12 @@ #ifdef _MSC_VER /* msvc 6.0 has problems */ #define inline __inline +typedef signed char int8_t; +typedef short int16_t; +typedef long int32_t; +typedef __int64 int64_t; typedef unsigned char uint8_t; +typedef unsigned short uint16_t; typedef unsigned long uint32_t; typedef unsigned __int64 uint64_t; #else diff -r 1aaefba2a3a9 -r 5c0dc243fe5b mercurial/util.py --- a/mercurial/util.py Tue Oct 01 00:12:34 2013 +0900 +++ b/mercurial/util.py Tue Oct 01 10:44:59 2013 -0700 @@ -242,6 +242,10 @@ def __contains__(self, key): return key in self._cache + def clear(self): + self._cache.clear() + self._order = deque() + def lrucachefunc(func): '''cache most recent results of function calls''' cache = {} @@ -465,7 +469,8 @@ return str(val) origcmd = cmd cmd = quotecommand(cmd) - if sys.platform == 'plan9': + if sys.platform == 'plan9' and (sys.version_info[0] == 2 + and sys.version_info[1] < 7): # subprocess kludge to work around issues in half-baked Python # ports, notably bichued/python: if not cwd is None: diff -r 1aaefba2a3a9 -r 5c0dc243fe5b setup.py --- a/setup.py Tue Oct 01 00:12:34 2013 +0900 +++ b/setup.py Tue Oct 01 10:44:59 2013 -0700 @@ -423,14 +423,21 @@ pymodules = [] +common_depends = ['mercurial/util.h'] + extmodules = [ - Extension('mercurial.base85', ['mercurial/base85.c']), - Extension('mercurial.bdiff', ['mercurial/bdiff.c']), - Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']), - Extension('mercurial.mpatch', ['mercurial/mpatch.c']), + Extension('mercurial.base85', ['mercurial/base85.c'], + depends=common_depends), + Extension('mercurial.bdiff', ['mercurial/bdiff.c'], + depends=common_depends), + Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'], + depends=common_depends), + Extension('mercurial.mpatch', ['mercurial/mpatch.c'], + depends=common_depends), Extension('mercurial.parsers', ['mercurial/dirs.c', 'mercurial/parsers.c', - 'mercurial/pathencode.c']), + 'mercurial/pathencode.c'], + depends=common_depends), ] osutil_ldflags = [] @@ -443,7 +450,8 @@ pymodules.append('mercurial.pure.osutil') else: extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'], - extra_link_args=osutil_ldflags)) + extra_link_args=osutil_ldflags, + depends=common_depends)) # the -mno-cygwin option has been deprecated for years Mingw32CCompiler = cygwinccompiler.Mingw32CCompiler @@ -467,7 +475,8 @@ if hasfunction(cc, 'inotify_add_watch'): inotify = Extension('hgext.inotify.linux._inotify', ['hgext/inotify/linux/_inotify.c'], - ['mercurial']) + ['mercurial'], + depends=common_depends) inotify.optional = True extmodules.append(inotify) packages.extend(['hgext.inotify', 'hgext.inotify.linux']) diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/run-tests.py --- a/tests/run-tests.py Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/run-tests.py Tue Oct 01 10:44:59 2013 -0700 @@ -460,6 +460,9 @@ if options.compiler: compiler = '--compiler ' + options.compiler pure = options.pure and "--pure" or "" + py3 = '' + if sys.version_info[0] == 3: + py3 = '--c2to3' # Run installer in hg root script = os.path.realpath(sys.argv[0]) @@ -472,11 +475,11 @@ # least on Windows for now, deal with .pydistutils.cfg bugs # when they happen. nohome = '' - cmd = ('%(exe)s setup.py %(pure)s clean --all' + cmd = ('%(exe)s setup.py %(py3)s %(pure)s clean --all' ' build %(compiler)s --build-base="%(base)s"' ' install --force --prefix="%(prefix)s" --install-lib="%(libdir)s"' ' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1' - % dict(exe=sys.executable, pure=pure, compiler=compiler, + % dict(exe=sys.executable, py3=py3, pure=pure, compiler=compiler, base=os.path.join(HGTMP, "build"), prefix=INST, libdir=PYTHONDIR, bindir=BINDIR, nohome=nohome, logfile=installerrs)) @@ -921,8 +924,10 @@ else: return ignore("doesn't match keyword") + if not lctest.startswith("test-"): + return skip("not a test file") for ext, func, out in testtypes: - if lctest.startswith("test-") and lctest.endswith(ext): + if lctest.endswith(ext): runner = func ref = os.path.join(TESTDIR, test + out) break @@ -1043,7 +1048,7 @@ if _hgpath is not None: return _hgpath - cmd = '%s -c "import mercurial; print mercurial.__path__[0]"' + cmd = '%s -c "import mercurial; print (mercurial.__path__[0])"' pipe = os.popen(cmd % PYTHON) try: _hgpath = pipe.read().strip() diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-casecollision-merge.t --- a/tests/test-casecollision-merge.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-casecollision-merge.t Tue Oct 01 10:44:59 2013 -0700 @@ -293,7 +293,7 @@ [255] $ hg update --check - abort: uncommitted local changes + abort: uncommitted changes [255] $ hg update --clean diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-command-template.t --- a/tests/test-command-template.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-command-template.t Tue Oct 01 10:44:59 2013 -0700 @@ -500,6 +500,28 @@ 1 0 +Missing non-standard names give no error (backward compatibility): + + $ echo "changeset = '{c}'" > t + $ hg log --style ./t + +Defining non-standard name works: + + $ cat < t + > changeset = '{c}' + > c = q + > EOF + $ hg log --style ./t + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0 + ui.style works: $ echo '[ui]' > .hg/hgrc diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-extension.t --- a/tests/test-extension.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-extension.t Tue Oct 01 10:44:59 2013 -0700 @@ -406,17 +406,21 @@ > EOF $ echo "debugissue811 = $debugpath" >> $HGRCPATH $ echo "mq=" >> $HGRCPATH + $ echo "strip=" >> $HGRCPATH $ echo "hgext.mq=" >> $HGRCPATH $ echo "hgext/mq=" >> $HGRCPATH Show extensions: +(note that mq force load strip, also checking it's not loaded twice) $ hg debugextensions debugissue811 + strip mq Disabled extension commands: + $ ORGHGRCPATH=$HGRCPATH $ HGRCPATH= $ export HGRCPATH $ hg help email @@ -573,3 +577,134 @@ ** Python * (glob) ** Mercurial Distributed SCM (*) (glob) ** Extensions loaded: throw + +Restore HGRCPATH + + $ HGRCPATH=$ORGHGRCPATH + $ export HGRCPATH + +Commands handling multiple repositories at a time should invoke only +"reposetup()" of extensions enabling in the target repository. + + $ mkdir reposetup-test + $ cd reposetup-test + + $ cat > $TESTTMP/reposetuptest.py < from mercurial import extensions + > def reposetup(ui, repo): + > ui.write('reposetup() for %s\n' % (repo.root)) + > EOF + $ hg init src + $ echo a > src/a + $ hg -R src commit -Am '#0 at src/a' + adding a + $ echo '[extensions]' >> src/.hg/hgrc + $ echo '# enable extension locally' >> src/.hg/hgrc + $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> src/.hg/hgrc + $ hg -R src status + reposetup() for $TESTTMP/reposetup-test/src + + $ hg clone -U src clone-dst1 + reposetup() for $TESTTMP/reposetup-test/src + $ hg init push-dst1 + $ hg -q -R src push push-dst1 + reposetup() for $TESTTMP/reposetup-test/src + $ hg init pull-src1 + $ hg -q -R pull-src1 pull src + reposetup() for $TESTTMP/reposetup-test/src + + $ echo '[extensions]' >> $HGRCPATH + $ echo '# disable extension globally and explicitly' >> $HGRCPATH + $ echo 'reposetuptest = !' >> $HGRCPATH + $ hg clone -U src clone-dst2 + reposetup() for $TESTTMP/reposetup-test/src + $ hg init push-dst2 + $ hg -q -R src push push-dst2 + reposetup() for $TESTTMP/reposetup-test/src + $ hg init pull-src2 + $ hg -q -R pull-src2 pull src + reposetup() for $TESTTMP/reposetup-test/src + + $ echo '[extensions]' >> $HGRCPATH + $ echo '# enable extension globally' >> $HGRCPATH + $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> $HGRCPATH + $ hg clone -U src clone-dst3 + reposetup() for $TESTTMP/reposetup-test/src + reposetup() for $TESTTMP/reposetup-test/clone-dst3 + $ hg init push-dst3 + reposetup() for $TESTTMP/reposetup-test/push-dst3 + $ hg -q -R src push push-dst3 + reposetup() for $TESTTMP/reposetup-test/src + reposetup() for $TESTTMP/reposetup-test/push-dst3 + $ hg init pull-src3 + reposetup() for $TESTTMP/reposetup-test/pull-src3 + $ hg -q -R pull-src3 pull src + reposetup() for $TESTTMP/reposetup-test/pull-src3 + reposetup() for $TESTTMP/reposetup-test/src + + $ echo '[extensions]' >> src/.hg/hgrc + $ echo '# disable extension locally' >> src/.hg/hgrc + $ echo 'reposetuptest = !' >> src/.hg/hgrc + $ hg clone -U src clone-dst4 + reposetup() for $TESTTMP/reposetup-test/clone-dst4 + $ hg init push-dst4 + reposetup() for $TESTTMP/reposetup-test/push-dst4 + $ hg -q -R src push push-dst4 + reposetup() for $TESTTMP/reposetup-test/push-dst4 + $ hg init pull-src4 + reposetup() for $TESTTMP/reposetup-test/pull-src4 + $ hg -q -R pull-src4 pull src + reposetup() for $TESTTMP/reposetup-test/pull-src4 + +disabling in command line overlays with all configuration + $ hg --config extensions.reposetuptest=! clone -U src clone-dst5 + $ hg --config extensions.reposetuptest=! init push-dst5 + $ hg --config extensions.reposetuptest=! -q -R src push push-dst5 + $ hg --config extensions.reposetuptest=! init pull-src5 + $ hg --config extensions.reposetuptest=! -q -R pull-src5 pull src + + $ echo '[extensions]' >> $HGRCPATH + $ echo '# disable extension globally and explicitly' >> $HGRCPATH + $ echo 'reposetuptest = !' >> $HGRCPATH + $ hg init parent + $ hg init parent/sub1 + $ echo 1 > parent/sub1/1 + $ hg -R parent/sub1 commit -Am '#0 at parent/sub1' + adding 1 + $ hg init parent/sub2 + $ hg init parent/sub2/sub21 + $ echo 21 > parent/sub2/sub21/21 + $ hg -R parent/sub2/sub21 commit -Am '#0 at parent/sub2/sub21' + adding 21 + $ cat > parent/sub2/.hgsub < sub21 = sub21 + > EOF + $ hg -R parent/sub2 commit -Am '#0 at parent/sub2' + adding .hgsub + $ hg init parent/sub3 + $ echo 3 > parent/sub3/3 + $ hg -R parent/sub3 commit -Am '#0 at parent/sub3' + adding 3 + $ cat > parent/.hgsub < sub1 = sub1 + > sub2 = sub2 + > sub3 = sub3 + > EOF + $ hg -R parent commit -Am '#0 at parent' + adding .hgsub + $ echo '[extensions]' >> parent/.hg/hgrc + $ echo '# enable extension locally' >> parent/.hg/hgrc + $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> parent/.hg/hgrc + $ cp parent/.hg/hgrc parent/sub2/.hg/hgrc + $ hg -R parent status -S -A + reposetup() for $TESTTMP/reposetup-test/parent + reposetup() for $TESTTMP/reposetup-test/parent/sub2 + C .hgsub + C .hgsubstate + C sub1/1 + C sub2/.hgsub + C sub2/.hgsubstate + C sub2/sub21/21 + C sub3/3 + + $ cd .. diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-graft.t --- a/tests/test-graft.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-graft.t Tue Oct 01 10:44:59 2013 -0700 @@ -71,7 +71,7 @@ $ hg up -q 0 $ echo foo > a $ hg graft 1 - abort: outstanding uncommitted changes + abort: uncommitted changes [255] $ hg revert a diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-help.t --- a/tests/test-help.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-help.t Tue Oct 01 10:44:59 2013 -0700 @@ -930,8 +930,8 @@

-
find changesets by author, revision, - files, or words in the commit message
+
Find changesets by keywords (author, files, the commit message), revision + number or hash, or revset expression.
@@ -1490,8 +1490,8 @@

-
find changesets by author, revision, - files, or words in the commit message
+
Find changesets by keywords (author, files, the commit message), revision + number or hash, or revset expression.

@@ -1656,8 +1656,8 @@

-
find changesets by author, revision, - files, or words in the commit message
+
Find changesets by keywords (author, files, the commit message), revision + number or hash, or revset expression.

@@ -1852,8 +1852,8 @@

-
find changesets by author, revision, - files, or words in the commit message
+
Find changesets by keywords (author, files, the commit message), revision + number or hash, or revset expression.

Specifying Single Revisions

diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-hgweb-commands.t --- a/tests/test-hgweb-commands.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-hgweb-commands.t Tue Oct 01 10:44:59 2013 -0700 @@ -258,8 +258,8 @@

-
find changesets by author, revision, - files, or words in the commit message
+
Find changesets by keywords (author, files, the commit message), revision + number or hash, or revset expression.
+ +
@@ -362,8 +377,8 @@

-
find changesets by author, revision, - files, or words in the commit message
+
Find changesets by keywords (author, files, the commit message), revision + number or hash, or revset expression.
base
@@ -495,11 +510,17 @@

searching for 'base'

+

+ Assuming literal keyword search. + + +

+

-
find changesets by author, revision, - files, or words in the commit message
+
Find changesets by keywords (author, files, the commit message), revision + number or hash, or revset expression.
-

Topics

children 1d22e65f027e
@@ -1256,8 +1432,10 @@ Graph json escape of multibyte character - $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'graph/' \ - > | grep -a '^var data =' + $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'graph/' > out + >>> for line in open("out"): + ... if line.startswith("var data ="): + ... print line, var data = [["061dd13ba3c3", [0, 1], [[0, 0, 1, -1, ""]], "\\u80fd", "test", "1970-01-01", ["unstable", true], ["tip"], ["something"]], ["cad8025a2e87", [0, 1], [[0, 0, 1, 3, "FF0000"]], "branch commit with null character: \x00", "test", "1970-01-01", ["unstable", false], [], []], ["1d22e65f027e", [0, 1], [[0, 0, 1, 3, ""]], "branch", "test", "1970-01-01", ["stable", true], [], []], ["a4f92ed23982", [0, 1], [[0, 0, 1, 3, ""]], "Added tag 1.0 for changeset 2ef0ac749a14", "test", "1970-01-01", ["default", true], [], []], ["2ef0ac749a14", [0, 1], [], "base", "test", "1970-01-01", ["default", false], ["1.0"], ["anotherthing"]]]; (esc) capabilities diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-hgweb-descend-empties.t --- a/tests/test-hgweb-descend-empties.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-hgweb-descend-empties.t Tue Oct 01 10:44:59 2013 -0700 @@ -76,8 +76,8 @@ diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-hgweb-diffs.t --- a/tests/test-hgweb-diffs.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-hgweb-diffs.t Tue Oct 01 10:44:59 2013 -0700 @@ -84,8 +84,8 @@

-
find changesets by author, revision, - files, or words in the commit message
+
Find changesets by keywords (author, files, the commit message), revision + number or hash, or revset expression.
a
@@ -246,8 +246,8 @@

-
find changesets by author, revision, - files, or words in the commit message
+
Find changesets by keywords (author, files, the commit message), revision + number or hash, or revset expression.
b
@@ -269,7 +269,6 @@ -
children
@@ -349,8 +348,8 @@
a
@@ -515,8 +514,8 @@
b
@@ -538,7 +537,6 @@ children -
@@ -615,8 +613,8 @@
a
@@ -638,7 +636,6 @@ children -
@@ -737,8 +734,8 @@
c
@@ -760,7 +757,6 @@ children -
@@ -861,8 +857,8 @@
d
@@ -884,7 +880,6 @@ children -
diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-hgweb-empty.t --- a/tests/test-hgweb-empty.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-hgweb-empty.t Tue Oct 01 10:44:59 2013 -0700 @@ -63,8 +63,8 @@ + +
@@ -158,8 +173,8 @@ + +
@@ -249,8 +279,8 @@ + +
@@ -385,8 +426,8 @@ diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-hgweb-filelog.t --- a/tests/test-hgweb-filelog.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-hgweb-filelog.t Tue Oct 01 10:44:59 2013 -0700 @@ -170,8 +170,8 @@

-
find changesets by author, revision, - files, or words in the commit message
+
Find changesets by keywords (author, files, the commit message), revision + number or hash, or revset expression.
-
children
diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-hgweb.t --- a/tests/test-hgweb.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-hgweb.t Tue Oct 01 10:44:59 2013 -0700 @@ -81,8 +81,8 @@
@@ -171,8 +171,8 @@
@@ -249,8 +249,8 @@ diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-highlight.t --- a/tests/test-highlight.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-highlight.t Tue Oct 01 10:44:59 2013 -0700 @@ -109,8 +109,8 @@

-
find changesets by author, revision, - files, or words in the commit message
+
Find changesets by keywords (author, files, the commit message), revision + number or hash, or revset expression.
a
@@ -132,7 +132,6 @@ -
children
@@ -241,8 +240,8 @@
a
@@ -264,7 +263,6 @@ children -
diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-import-merge.t --- a/tests/test-import-merge.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-import-merge.t Tue Oct 01 10:44:59 2013 -0700 @@ -129,7 +129,9 @@ $ echo a>>a $ hg ci -m3 $ hg export 2 | head -7 > ../a.patch - $ hg export tip | tail -n +8 >> ../a.patch + $ hg export tip > out + >>> apatch = open("../a.patch", "a") + >>> apatch.write("".join(open("out").readlines()[7:])) $ cd .. $ hg clone -qr0 repo3 repo3-clone diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-issue1502.t --- a/tests/test-issue1502.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-issue1502.t Tue Oct 01 10:44:59 2013 -0700 @@ -19,7 +19,8 @@ adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) - not updating: crosses branches (merge branches or update --check to force update) + not updating: not a linear update + (merge or update --check to force update) $ hg -R foo1 book branchy $ hg -R foo1 book diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-largefiles.t --- a/tests/test-largefiles.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-largefiles.t Tue Oct 01 10:44:59 2013 -0700 @@ -1104,7 +1104,7 @@ "update --check" refuses to update with uncommitted changes. $ hg update --check 8 - abort: uncommitted local changes + abort: uncommitted changes [255] "update --clean" leaves correct largefiles in working copy, even when there is @@ -2191,3 +2191,64 @@ $ cd .. + +Check whether "largefiles" feature is supported only in repositories +enabling largefiles extension. + + $ mkdir individualenabling + $ cd individualenabling + + $ hg init enabledlocally + $ echo large > enabledlocally/large + $ hg -R enabledlocally add --large enabledlocally/large + $ hg -R enabledlocally commit -m '#0' + Invoking status precommit hook + A large + + $ hg init notenabledlocally + $ echo large > notenabledlocally/large + $ hg -R notenabledlocally add --large notenabledlocally/large + $ hg -R notenabledlocally commit -m '#0' + Invoking status precommit hook + A large + + $ cat >> $HGRCPATH < [extensions] + > # disable globally + > largefiles=! + > EOF + $ cat >> enabledlocally/.hg/hgrc < [extensions] + > # enable locally + > largefiles= + > EOF + $ hg -R enabledlocally root + $TESTTMP/individualenabling/enabledlocally + $ hg -R notenabledlocally root + abort: unknown repository format: requires features 'largefiles' (upgrade Mercurial)! + [255] + + $ hg init push-dst + $ hg -R enabledlocally push push-dst + pushing to push-dst + abort: required features are not supported in the destination: largefiles + [255] + + $ hg init pull-src + $ hg -R pull-src pull enabledlocally + pulling from enabledlocally + abort: required features are not supported in the destination: largefiles + [255] + + $ hg clone enabledlocally clone-dst + abort: unknown repository format: requires features 'largefiles' (upgrade Mercurial)! + [255] + $ test -d clone-dst + [1] + $ hg clone --pull enabledlocally clone-pull-dst + abort: required features are not supported in the destination: largefiles + [255] + $ test -d clone-pull-dst + [1] + + $ cd .. diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-lrucachedict.py --- a/tests/test-lrucachedict.py Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-lrucachedict.py Tue Oct 01 10:44:59 2013 -0700 @@ -31,5 +31,8 @@ d['f'] = 'vf' printifpresent(d, ['b', 'c', 'd', 'e', 'f']) + d.clear() + printifpresent(d, ['b', 'c', 'd', 'e', 'f']) + if __name__ == '__main__': test_lrucachedict() diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-lrucachedict.py.out --- a/tests/test-lrucachedict.py.out Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-lrucachedict.py.out Tue Oct 01 10:44:59 2013 -0700 @@ -24,3 +24,8 @@ 'e' in d: False 'f' in d: True d['f']: vf +'b' in d: False +'c' in d: False +'d' in d: False +'e' in d: False +'f' in d: False diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-merge-force.t --- a/tests/test-merge-force.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-merge-force.t Tue Oct 01 10:44:59 2013 -0700 @@ -19,7 +19,7 @@ Should fail, since there are deleted files: $ hg merge - abort: outstanding uncommitted changes + abort: uncommitted changes (use 'hg status' to list changes) [255] diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-merge-subrepos.t --- a/tests/test-merge-subrepos.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-merge-subrepos.t Tue Oct 01 10:44:59 2013 -0700 @@ -21,5 +21,5 @@ Should fail, since there are added files to subrepo: $ hg merge - abort: outstanding uncommitted changes in subrepository 'subrepo' + abort: uncommitted changes in subrepository 'subrepo' [255] diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-merge1.t --- a/tests/test-merge1.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-merge1.t Tue Oct 01 10:44:59 2013 -0700 @@ -140,7 +140,7 @@ $ echo This is file b22 > b merge fails $ hg merge 2 - abort: outstanding uncommitted changes + abort: uncommitted changes (use 'hg status' to list changes) [255] merge expected! @@ -177,7 +177,7 @@ $ echo This is file b33 > b merge of b should fail $ hg merge 2 - abort: outstanding uncommitted changes + abort: uncommitted changes (use 'hg status' to list changes) [255] merge of b expected diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-merge5.t --- a/tests/test-merge5.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-merge5.t Tue Oct 01 10:44:59 2013 -0700 @@ -14,11 +14,12 @@ $ hg update 1 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg update - abort: crosses branches (merge branches or update --check to force update) + abort: not a linear update + (merge or update --check to force update) [255] $ rm b $ hg update -c - abort: uncommitted local changes + abort: uncommitted changes [255] $ hg revert b $ hg update -c @@ -32,7 +33,8 @@ Should abort: $ hg update -y 1 - abort: crosses branches (merge branches or use --clean to discard changes) + abort: uncommitted changes + (commit or update --clean to discard changes) [255] $ mv c a diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-mq-strip.t --- a/tests/test-mq-strip.t Tue Oct 01 00:12:34 2013 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,503 +0,0 @@ - $ echo "[extensions]" >> $HGRCPATH - $ echo "mq=" >> $HGRCPATH - $ echo "graphlog=" >> $HGRCPATH - - $ restore() { - > hg unbundle -q .hg/strip-backup/* - > rm .hg/strip-backup/* - > } - $ teststrip() { - > hg up -C $1 - > echo % before update $1, strip $2 - > hg parents - > hg --traceback strip $2 - > echo % after update $1, strip $2 - > hg parents - > restore - > } - - $ hg init test - $ cd test - - $ echo foo > bar - $ hg ci -Ama - adding bar - - $ echo more >> bar - $ hg ci -Amb - - $ echo blah >> bar - $ hg ci -Amc - - $ hg up 1 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ echo blah >> bar - $ hg ci -Amd - created new head - - $ echo final >> bar - $ hg ci -Ame - - $ hg log - changeset: 4:443431ffac4f - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: e - - changeset: 3:65bd5f99a4a3 - parent: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: d - - changeset: 2:264128213d29 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: c - - changeset: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: b - - changeset: 0:9ab35a2d17cb - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - - $ teststrip 4 4 - 0 files updated, 0 files merged, 0 files removed, 0 files unresolved - % before update 4, strip 4 - changeset: 4:443431ffac4f - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: e - - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - % after update 4, strip 4 - changeset: 3:65bd5f99a4a3 - tag: tip - parent: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: d - - $ teststrip 4 3 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - % before update 4, strip 3 - changeset: 4:443431ffac4f - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: e - - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - % after update 4, strip 3 - changeset: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: b - - $ teststrip 1 4 - 0 files updated, 0 files merged, 0 files removed, 0 files unresolved - % before update 1, strip 4 - changeset: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: b - - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - % after update 1, strip 4 - changeset: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: b - - $ teststrip 4 2 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - % before update 4, strip 2 - changeset: 4:443431ffac4f - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: e - - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - % after update 4, strip 2 - changeset: 3:443431ffac4f - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: e - - $ teststrip 4 1 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - % before update 4, strip 1 - changeset: 4:264128213d29 - tag: tip - parent: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: c - - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - % after update 4, strip 1 - changeset: 0:9ab35a2d17cb - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - $ teststrip null 4 - 0 files updated, 0 files merged, 1 files removed, 0 files unresolved - % before update null, strip 4 - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - % after update null, strip 4 - - $ hg log - changeset: 4:264128213d29 - tag: tip - parent: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: c - - changeset: 3:443431ffac4f - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: e - - changeset: 2:65bd5f99a4a3 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: d - - changeset: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: b - - changeset: 0:9ab35a2d17cb - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - - $ hg up -C 2 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ hg merge 4 - 0 files updated, 0 files merged, 0 files removed, 0 files unresolved - (branch merge, don't forget to commit) - -before strip of merge parent - - $ hg parents - changeset: 2:65bd5f99a4a3 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: d - - changeset: 4:264128213d29 - tag: tip - parent: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: c - - $ hg strip 4 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - -after strip of merge parent - - $ hg parents - changeset: 1:ef3a871183d7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: b - - $ restore - - $ hg up - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ hg glog - @ changeset: 4:264128213d29 - | tag: tip - | parent: 1:ef3a871183d7 - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: c - | - | o changeset: 3:443431ffac4f - | | user: test - | | date: Thu Jan 01 00:00:00 1970 +0000 - | | summary: e - | | - | o changeset: 2:65bd5f99a4a3 - |/ user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: d - | - o changeset: 1:ef3a871183d7 - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: b - | - o changeset: 0:9ab35a2d17cb - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - -2 is parent of 3, only one strip should happen - - $ hg strip "roots(2)" 3 - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - $ hg glog - @ changeset: 2:264128213d29 - | tag: tip - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: c - | - o changeset: 1:ef3a871183d7 - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: b - | - o changeset: 0:9ab35a2d17cb - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - $ restore - $ hg glog - o changeset: 4:443431ffac4f - | tag: tip - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: e - | - o changeset: 3:65bd5f99a4a3 - | parent: 1:ef3a871183d7 - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: d - | - | @ changeset: 2:264128213d29 - |/ user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: c - | - o changeset: 1:ef3a871183d7 - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: b - | - o changeset: 0:9ab35a2d17cb - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - -2 different branches: 2 strips - - $ hg strip 2 4 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - $ hg glog - o changeset: 2:65bd5f99a4a3 - | tag: tip - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: d - | - @ changeset: 1:ef3a871183d7 - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: b - | - o changeset: 0:9ab35a2d17cb - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - $ restore - -2 different branches and a common ancestor: 1 strip - - $ hg strip 1 "2|4" - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - $ restore - -stripping an empty revset - - $ hg strip "1 and not 1" - abort: empty revision set - [255] - -remove branchy history for qimport tests - - $ hg strip 3 - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - - -strip of applied mq should cleanup status file - - $ hg up -C 3 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ echo fooagain >> bar - $ hg ci -mf - $ hg qimport -r tip:2 - -applied patches before strip - - $ hg qapplied - 2.diff - 3.diff - 4.diff - -stripping revision in queue - - $ hg strip 3 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - -applied patches after stripping rev in queue - - $ hg qapplied - 2.diff - -stripping ancestor of queue - - $ hg strip 1 - 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - -applied patches after stripping ancestor of queue - - $ hg qapplied - -Verify strip protects against stripping wc parent when there are uncommited mods - - $ echo b > b - $ hg add b - $ hg ci -m 'b' - $ hg log --graph - @ changeset: 1:7519abd79d14 - | tag: tip - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: b - | - o changeset: 0:9ab35a2d17cb - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - - $ echo c > b - $ echo c > bar - $ hg strip tip - abort: local changes found - [255] - $ hg strip tip --keep - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - $ hg log --graph - @ changeset: 0:9ab35a2d17cb - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: a - - $ hg status - M bar - ? b - -Strip adds, removes, modifies with --keep - - $ touch b - $ hg add b - $ hg commit -mb - $ touch c - -... with a clean working dir - - $ hg add c - $ hg rm bar - $ hg commit -mc - $ hg status - $ hg strip --keep tip - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - $ hg status - ! bar - ? c - -... with a dirty working dir - - $ hg add c - $ hg rm bar - $ hg commit -mc - $ hg status - $ echo b > b - $ echo d > d - $ hg strip --keep tip - saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) - $ hg status - M b - ! bar - ? c - ? d - $ cd .. - -stripping many nodes on a complex graph (issue3299) - - $ hg init issue3299 - $ cd issue3299 - $ hg debugbuilddag '@a.:a@b.:b.:x .hgsub $ hg add .hgsub - $ hg qnew -m0 0.diff + $ hg commit -m0 $ hg debugsub path sub source sub revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31 + $ echo foo > ./sub/a + $ hg -R sub commit -m foo + $ hg commit -m1 + $ hg qimport -r "0:tip" + $ hg -R sub id --id + aa037b301eba qpop + $ hg -R sub update 0000 + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved $ hg qpop - popping 0.diff - patch queue now empty - $ hg status -AS - $ hg debugsub - -qpush - $ hg qpush - applying 0.diff + abort: local changed subrepos found, refresh first + [255] + $ hg revert sub + reverting subrepo sub + adding sub/a + $ hg qpop + popping 1.diff now at: 0.diff $ hg status -AS C .hgsub C .hgsubstate C sub/a - $ hg debugsub - path sub - source sub - revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31 + $ hg -R sub id --id + b2fdb12cd82b + +qpush + $ hg -R sub update 0000 + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ hg qpush + abort: local changed subrepos found, refresh first + [255] + $ hg revert sub + reverting subrepo sub + adding sub/a + $ hg qpush + applying 1.diff + subrepository sub diverged (local revision: b2fdb12cd82b, remote revision: aa037b301eba) + (M)erge, keep (l)ocal or keep (r)emote? m + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + now at: 1.diff + $ hg status -AS + C .hgsub + C .hgsubstate + C sub/a + $ hg -R sub id --id + aa037b301eba $ cd .. diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-mq.t --- a/tests/test-mq.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-mq.t Tue Oct 01 10:44:59 2013 -0700 @@ -67,6 +67,9 @@ changes will be tolerated and preserved. If incompatible options such as -f/--force or --exact are passed, this setting is ignored. + This extension used to provide a strip command. This command now lives in the + strip extension. + list of commands: qapplied print the patches already applied @@ -91,7 +94,6 @@ qseries print the entire series file qtop print the name of the current patch qunapplied print the patches not yet applied - strip strip changesets and all their descendants from the repository use "hg -v help mq" to show builtin aliases and global options diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-parse-date.t --- a/tests/test-parse-date.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-parse-date.t Tue Oct 01 10:44:59 2013 -0700 @@ -242,7 +242,7 @@ >>> yesterday = (datetime.date.today() - datetime.timedelta(days=1)).strftime("%b %d") >>> dates = open('dates', 'w') >>> dates.write(today + '\n') - >>> dates.write(yesterday) + >>> dates.write(yesterday + '\n') >>> dates.close() $ hg ci -d "`sed -n '1p' dates`" -m "today is a good day to code" $ hg log -d today --template '{desc}\n' diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-progress.t --- a/tests/test-progress.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-progress.t Tue Oct 01 10:44:59 2013 -0700 @@ -1,6 +1,14 @@ $ cat > loop.py < from mercurial import commands + > import time + > class incrementingtime(object): + > def __init__(self): + > self._time = 0.0 + > def __call__(self): + > self._time += 0.25 + > return self._time + > time.time = incrementingtime() > > def loop(ui, loops, **opts): > loops = int(loops) @@ -19,9 +27,14 @@ > if opts.get('parallel'): > ui.progress('other', i, 'other.%d' % i, 'othernum', total) > if nested: - > for j in range(2): - > ui.progress('nested', j, 'nested.%d' % j, 'nestnum', 2) - > ui.progress('nested', None, 'nested.done', 'nestnum', 2) + > nested_steps = 2 + > if i and i % 4 == 0: + > nested_steps = 5 + > for j in range(nested_steps): + > ui.progress( + > 'nested', j, 'nested.%d' % j, 'nestnum', nested_steps) + > ui.progress( + > 'nested', None, 'nested.done', 'nestnum', nested_steps) > ui.progress('loop', None, 'loop.done', 'loopnum', total) > > commands.norepo += " loop" @@ -69,6 +82,24 @@ loop [===============================> ] 2/3\r (no-eol) (esc) \r (no-eol) (esc) +Test nested long-lived topic which has the same name as a short-lived +peer. We shouldn't get stuck showing the short-lived inner steps, and +should go back to skipping the inner steps when the slow nested step +finishes. + + $ hg -y loop 7 --nested + \r (no-eol) (esc) + loop [ ] 0/7\r (no-eol) (esc) + loop [=====> ] 1/7\r (no-eol) (esc) + loop [============> ] 2/7\r (no-eol) (esc) + loop [===================> ] 3/7\r (no-eol) (esc) + loop [==========================> ] 4/7\r (no-eol) (esc) + nested [==========================> ] 3/5\r (no-eol) (esc) + nested [===================================> ] 4/5\r (no-eol) (esc) + loop [=================================> ] 5/7\r (no-eol) (esc) + loop [========================================> ] 6/7\r (no-eol) (esc) + \r (no-eol) (esc) + $ hg --config progress.changedelay=0 -y loop 3 --nested \r (no-eol) (esc) diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-pull-update.t --- a/tests/test-pull-update.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-pull-update.t Tue Oct 01 10:44:59 2013 -0700 @@ -25,7 +25,8 @@ adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) - not updating: crosses branches (merge branches or update --check to force update) + not updating: not a linear update + (merge or update --check to force update) $ cd ../tt @@ -38,7 +39,8 @@ adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) - not updating: crosses branches (merge branches or update --check to force update) + not updating: not a linear update + (merge or update --check to force update) $ HGMERGE=true hg merge merging foo diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-push-warn.t --- a/tests/test-push-warn.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-push-warn.t Tue Oct 01 10:44:59 2013 -0700 @@ -354,6 +354,29 @@ adding file changes added 1 changesets with 1 changes to 1 files +Pushing muliple headed new branch: + + $ echo 14 > foo + $ hg -q branch f + $ hg -q ci -m 14 + $ echo 15 > foo + $ hg -q ci -m 15 + $ hg -q up 14 + $ echo 16 > foo + $ hg -q ci -m 16 + $ hg push --branch f --new-branch ../f + pushing to ../f + searching for changes + abort: push creates multiple headed new branch 'f' + (merge or see "hg help push" for detail about pushing new heads) + [255] + $ hg push --branch f --new-branch --force ../f + pushing to ../f + searching for changes + adding changesets + adding manifests + adding file changes + added 3 changesets with 3 changes to 1 files (+1 heads) Checking prepush logic does not allow silently pushing multiple new heads: diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-requires.t --- a/tests/test-requires.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-requires.t Tue Oct 01 10:44:59 2013 -0700 @@ -15,5 +15,55 @@ $ hg tip abort: unknown repository format: requires features 'indoor-pool', 'outdoor-pool' (upgrade Mercurial)! [255] + $ cd .. + +Test checking between features supported locally and ones required in +another repository of push/pull/clone on localhost: + + $ mkdir supported-locally + $ cd supported-locally + + $ hg init supported + $ echo a > supported/a + $ hg -R supported commit -Am '#0 at supported' + adding a + + $ echo 'featuresetup-test' >> supported/.hg/requires + $ cat > $TESTTMP/supported-locally/supportlocally.py < from mercurial import localrepo, extensions + > def featuresetup(ui, supported): + > for name, module in extensions.extensions(ui): + > if __name__ == module.__name__: + > # support specific feature locally + > supported |= set(['featuresetup-test']) + > return + > def uisetup(ui): + > localrepo.localrepository.featuresetupfuncs.add(featuresetup) + > EOF + $ cat > supported/.hg/hgrc < [extensions] + > # enable extension locally + > supportlocally = $TESTTMP/supported-locally/supportlocally.py + > EOF + $ hg -R supported status + + $ hg init push-dst + $ hg -R supported push push-dst + pushing to push-dst + abort: required features are not supported in the destination: featuresetup-test + [255] + + $ hg init pull-src + $ hg -R pull-src pull supported + pulling from supported + abort: required features are not supported in the destination: featuresetup-test + [255] + + $ hg clone supported clone-dst + abort: unknown repository format: requires features 'featuresetup-test' (upgrade Mercurial)! + [255] + $ hg clone --pull supported clone-dst + abort: required features are not supported in the destination: featuresetup-test + [255] $ cd .. diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-strip.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-strip.t Tue Oct 01 10:44:59 2013 -0700 @@ -0,0 +1,504 @@ + $ echo "[extensions]" >> $HGRCPATH + $ echo "strip=" >> $HGRCPATH + $ echo "graphlog=" >> $HGRCPATH + + $ restore() { + > hg unbundle -q .hg/strip-backup/* + > rm .hg/strip-backup/* + > } + $ teststrip() { + > hg up -C $1 + > echo % before update $1, strip $2 + > hg parents + > hg --traceback strip $2 + > echo % after update $1, strip $2 + > hg parents + > restore + > } + + $ hg init test + $ cd test + + $ echo foo > bar + $ hg ci -Ama + adding bar + + $ echo more >> bar + $ hg ci -Amb + + $ echo blah >> bar + $ hg ci -Amc + + $ hg up 1 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ echo blah >> bar + $ hg ci -Amd + created new head + + $ echo final >> bar + $ hg ci -Ame + + $ hg log + changeset: 4:443431ffac4f + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: e + + changeset: 3:65bd5f99a4a3 + parent: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: d + + changeset: 2:264128213d29 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: c + + changeset: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: b + + changeset: 0:9ab35a2d17cb + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + + $ teststrip 4 4 + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + % before update 4, strip 4 + changeset: 4:443431ffac4f + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: e + + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + % after update 4, strip 4 + changeset: 3:65bd5f99a4a3 + tag: tip + parent: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: d + + $ teststrip 4 3 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + % before update 4, strip 3 + changeset: 4:443431ffac4f + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: e + + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + % after update 4, strip 3 + changeset: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: b + + $ teststrip 1 4 + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + % before update 1, strip 4 + changeset: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: b + + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + % after update 1, strip 4 + changeset: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: b + + $ teststrip 4 2 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + % before update 4, strip 2 + changeset: 4:443431ffac4f + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: e + + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + % after update 4, strip 2 + changeset: 3:443431ffac4f + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: e + + $ teststrip 4 1 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + % before update 4, strip 1 + changeset: 4:264128213d29 + tag: tip + parent: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: c + + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + % after update 4, strip 1 + changeset: 0:9ab35a2d17cb + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + $ teststrip null 4 + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + % before update null, strip 4 + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + % after update null, strip 4 + + $ hg log + changeset: 4:264128213d29 + tag: tip + parent: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: c + + changeset: 3:443431ffac4f + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: e + + changeset: 2:65bd5f99a4a3 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: d + + changeset: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: b + + changeset: 0:9ab35a2d17cb + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + + $ hg up -C 2 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg merge 4 + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + (branch merge, don't forget to commit) + +before strip of merge parent + + $ hg parents + changeset: 2:65bd5f99a4a3 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: d + + changeset: 4:264128213d29 + tag: tip + parent: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: c + + $ hg strip 4 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + +after strip of merge parent + + $ hg parents + changeset: 1:ef3a871183d7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: b + + $ restore + + $ hg up + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg glog + @ changeset: 4:264128213d29 + | tag: tip + | parent: 1:ef3a871183d7 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: c + | + | o changeset: 3:443431ffac4f + | | user: test + | | date: Thu Jan 01 00:00:00 1970 +0000 + | | summary: e + | | + | o changeset: 2:65bd5f99a4a3 + |/ user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: d + | + o changeset: 1:ef3a871183d7 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: b + | + o changeset: 0:9ab35a2d17cb + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + +2 is parent of 3, only one strip should happen + + $ hg strip "roots(2)" 3 + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + $ hg glog + @ changeset: 2:264128213d29 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: c + | + o changeset: 1:ef3a871183d7 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: b + | + o changeset: 0:9ab35a2d17cb + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + $ restore + $ hg glog + o changeset: 4:443431ffac4f + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: e + | + o changeset: 3:65bd5f99a4a3 + | parent: 1:ef3a871183d7 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: d + | + | @ changeset: 2:264128213d29 + |/ user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: c + | + o changeset: 1:ef3a871183d7 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: b + | + o changeset: 0:9ab35a2d17cb + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + +2 different branches: 2 strips + + $ hg strip 2 4 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + $ hg glog + o changeset: 2:65bd5f99a4a3 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: d + | + @ changeset: 1:ef3a871183d7 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: b + | + o changeset: 0:9ab35a2d17cb + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + $ restore + +2 different branches and a common ancestor: 1 strip + + $ hg strip 1 "2|4" + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + $ restore + +stripping an empty revset + + $ hg strip "1 and not 1" + abort: empty revision set + [255] + +remove branchy history for qimport tests + + $ hg strip 3 + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + + +strip of applied mq should cleanup status file + + $ echo "mq=" >> $HGRCPATH + $ hg up -C 3 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ echo fooagain >> bar + $ hg ci -mf + $ hg qimport -r tip:2 + +applied patches before strip + + $ hg qapplied + 2.diff + 3.diff + 4.diff + +stripping revision in queue + + $ hg strip 3 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + +applied patches after stripping rev in queue + + $ hg qapplied + 2.diff + +stripping ancestor of queue + + $ hg strip 1 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + +applied patches after stripping ancestor of queue + + $ hg qapplied + +Verify strip protects against stripping wc parent when there are uncommited mods + + $ echo b > b + $ hg add b + $ hg ci -m 'b' + $ hg log --graph + @ changeset: 1:7519abd79d14 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: b + | + o changeset: 0:9ab35a2d17cb + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + + $ echo c > b + $ echo c > bar + $ hg strip tip + abort: local changes found + [255] + $ hg strip tip --keep + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + $ hg log --graph + @ changeset: 0:9ab35a2d17cb + tag: tip + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: a + + $ hg status + M bar + ? b + +Strip adds, removes, modifies with --keep + + $ touch b + $ hg add b + $ hg commit -mb + $ touch c + +... with a clean working dir + + $ hg add c + $ hg rm bar + $ hg commit -mc + $ hg status + $ hg strip --keep tip + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + $ hg status + ! bar + ? c + +... with a dirty working dir + + $ hg add c + $ hg rm bar + $ hg commit -mc + $ hg status + $ echo b > b + $ echo d > d + $ hg strip --keep tip + saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob) + $ hg status + M b + ! bar + ? c + ? d + $ cd .. + +stripping many nodes on a complex graph (issue3299) + + $ hg init issue3299 + $ cd issue3299 + $ hg debugbuilddag '@a.:a@b.:b.:x/dev/null + subrepository s diverged (local revision: 796959400868, remote revision: aa84837ccfbd) + (M)erge, keep (l)ocal or keep (r)emote? m pulling subrepo s from $TESTTMP/gitroot 0 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) @@ -462,6 +464,8 @@ da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7 $ cd .. $ hg update 4 + subrepository s diverged (local revision: da5f5b1d8ffc, remote revision: aa84837ccfbd) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for s differ use (l)ocal source (da5f5b1) or (r)emote source (aa84837)? l @@ -487,6 +491,8 @@ HEAD is now at aa84837... f $ cd .. $ hg update 1 + subrepository s diverged (local revision: 32a343883b74, remote revision: da5f5b1d8ffc) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for s differ (in checked out version) use (l)ocal source (32a3438) or (r)emote source (da5f5b1)? l @@ -508,6 +514,8 @@ $ hg id -n 1+ $ hg update 7 + subrepository s diverged (local revision: 32a343883b74, remote revision: 32a343883b74) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for s differ use (l)ocal source (32a3438) or (r)emote source (32a3438)? l diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-subrepo-svn.t --- a/tests/test-subrepo-svn.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-subrepo-svn.t Tue Oct 01 10:44:59 2013 -0700 @@ -319,6 +319,8 @@ 2M $ cd .. $ hg update tip + subrepository s diverged (local revision: 2, remote revision: 3) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for s differ use (l)ocal source (2) or (r)emote source (3)? l @@ -349,6 +351,8 @@ $ svn update -qr 1 $ cd .. $ hg update 1 + subrepository s diverged (local revision: 3, remote revision: 2) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for s differ (in checked out version) use (l)ocal source (1) or (r)emote source (2)? l @@ -371,6 +375,8 @@ $ hg id -n 1+ $ hg update tip + subrepository s diverged (local revision: 3, remote revision: 3) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for s differ use (l)ocal source (1) or (r)emote source (3)? l @@ -404,6 +410,8 @@ $ svn update -qr 2 $ cd .. $ hg update 1 + subrepository s diverged (local revision: 3, remote revision: 2) + (M)erge, keep (l)ocal or keep (r)emote? m 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg id -n 1+ @@ -477,7 +485,8 @@ This is surprising, but is also correct based on the current code: $ echo "updating should (maybe) fail" > obstruct/other $ hg co tip - abort: crosses branches (merge branches or use --clean to discard changes) + abort: uncommitted changes + (commit or update --clean to discard changes) [255] Point to a Subversion branch which has since been deleted and recreated diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-subrepo.t --- a/tests/test-subrepo.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-subrepo.t Tue Oct 01 10:44:59 2013 -0700 @@ -236,7 +236,9 @@ .hgsubstate: versions differ -> m updating: .hgsubstate 1/1 files (100.00%) subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4 - subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg + subrepo t: both sides changed + subrepository t diverged (local revision: 20a0db6fbf6c, remote revision: 7af322bc1198) + (M)erge, keep (l)ocal or keep (r)emote? m merging subrepo t searching for copies back to rev 2 resolving manifests @@ -252,6 +254,7 @@ merging t incomplete! (edit conflicts, then use 'hg resolve --mark') 0 files updated, 0 files merged, 0 files removed, 1 files unresolved use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon + subrepo t: merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg 0 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) @@ -620,6 +623,8 @@ $ hg up 5 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg merge 4 # try to merge default into br again + subrepository s diverged (local revision: f8f13b33206e, remote revision: a3f9062a4f88) + (M)erge, keep (l)ocal or keep (r)emote? m 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) $ cd .. @@ -922,9 +927,13 @@ $ hg -R t id e95bcfa18a35+ $ hg update tip + subrepository s diverged (local revision: fc627a69481f, remote revision: 12a213df6fa9) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for s differ use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)? l + subrepository t diverged (local revision: e95bcfa18a35, remote revision: 52c0adc0515a) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for t differ use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)? l @@ -953,6 +962,10 @@ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ cd .. $ hg update 10 + subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f) + (M)erge, keep (l)ocal or keep (r)emote? m + subrepository t diverged (local revision: 52c0adc0515a, remote revision: 20a0db6fbf6c) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for t differ (in checked out version) use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)? l @@ -976,9 +989,13 @@ $ hg -R t id 7af322bc1198+ $ hg update tip + subrepository s diverged (local revision: 12a213df6fa9, remote revision: 12a213df6fa9) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for s differ use (l)ocal source (02dcf1d70411) or (r)emote source (12a213df6fa9)? l + subrepository t diverged (local revision: 52c0adc0515a, remote revision: 52c0adc0515a) + (M)erge, keep (l)ocal or keep (r)emote? m subrepository sources for t differ use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)? l @@ -1006,6 +1023,8 @@ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ cd .. $ hg update 11 + subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f) + (M)erge, keep (l)ocal or keep (r)emote? m 0 files updated, 0 files merged, 0 files removed, 0 files unresolved 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg id -n diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-symlink-placeholder.t --- a/tests/test-symlink-placeholder.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-symlink-placeholder.t Tue Oct 01 10:44:59 2013 -0700 @@ -41,6 +41,13 @@ a (no-eol) $ hg --config extensions.n=$TESTTMP/nolink.py st --debug +Empty placeholder: + + $ rm b + $ touch b + $ hg --config extensions.n=$TESTTMP/nolink.py st --debug + ignoring suspect symlink placeholder "b" + Write binary data to the placeholder: >>> open('b', 'w').write('this is a binary\0') diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-up-local-change.t --- a/tests/test-up-local-change.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-up-local-change.t Tue Oct 01 10:44:59 2013 -0700 @@ -167,10 +167,11 @@ summary: 2 $ hg --debug up - abort: crosses branches (merge branches or use --clean to discard changes) + abort: uncommitted changes + (commit and merge, or update --clean to discard changes) [255] $ hg --debug merge - abort: outstanding uncommitted changes + abort: uncommitted changes (use 'hg status' to list changes) [255] $ hg --debug merge -f diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-update-branches.t --- a/tests/test-update-branches.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-update-branches.t Tue Oct 01 10:44:59 2013 -0700 @@ -94,7 +94,8 @@ parent=5 $ norevtest 'none clean same' clean 2 - abort: crosses branches (merge branches or update --check to force update) + abort: not a linear update + (merge or update --check to force update) parent=2 @@ -122,22 +123,32 @@ M sub/suba $ revtest 'none dirty same' dirty 2 3 - abort: crosses branches (merge branches or use --clean to discard changes) + abort: uncommitted changes + (commit or update --clean to discard changes) parent=2 M foo $ revtest 'none dirtysub same' dirtysub 2 3 - abort: crosses branches (merge branches or use --clean to discard changes) + abort: uncommitted changes + (commit or update --clean to discard changes) parent=2 M sub/suba $ revtest 'none dirty cross' dirty 3 4 - abort: crosses branches (merge branches or use --clean to discard changes) + abort: uncommitted changes + (commit or update --clean to discard changes) parent=3 M foo + $ norevtest 'none dirty cross' dirty 2 + abort: uncommitted changes + (commit and merge, or update --clean to discard changes) + parent=2 + M foo + $ revtest 'none dirtysub cross' dirtysub 3 4 - abort: crosses branches (merge branches or use --clean to discard changes) + abort: uncommitted changes + (commit or update --clean to discard changes) parent=3 M sub/suba @@ -146,12 +157,12 @@ parent=2 $ revtest '-c dirty linear' dirty 1 2 -c - abort: uncommitted local changes + abort: uncommitted changes parent=1 M foo $ revtest '-c dirtysub linear' dirtysub 1 2 -c - abort: uncommitted local changes + abort: uncommitted changes parent=1 M sub/suba @@ -222,5 +233,6 @@ $ hg up --quiet 0 $ hg up --quiet 2 $ hg up 5 - abort: crosses branches (merge branches or use --clean to discard changes) + abort: uncommitted changes + (commit or update --clean to discard changes) [255] diff -r 1aaefba2a3a9 -r 5c0dc243fe5b tests/test-update-issue1456.t --- a/tests/test-update-issue1456.t Tue Oct 01 00:12:34 2013 +0900 +++ b/tests/test-update-issue1456.t Tue Oct 01 10:44:59 2013 -0700 @@ -18,7 +18,7 @@ $ echo dirty > foo $ hg up -c - abort: uncommitted local changes + abort: uncommitted changes [255] $ hg up -q $ cat foo