# HG changeset patch # User Benoit Boissinot # Date 1158274287 -7200 # Node ID 41e5ecfb6c247cd3812b003c3521433035d87472 # Parent edefbb3a3b0816dc02f8467b833885784e9f5eb7# Parent 7fa3d38a99b6b5802a00a4bf76e8f852f42d5889 merge with brendan diff --git a/contrib/churn.py b/contrib/churn.py --- a/contrib/churn.py +++ b/contrib/churn.py @@ -14,7 +14,7 @@ from mercurial.demandload import * from mercurial.i18n import gettext as _ demandload(globals(), 'time sys signal os') -demandload(globals(), 'mercurial:hg,mdiff,fancyopts,commands,ui,util,templater,node') +demandload(globals(), 'mercurial:hg,mdiff,fancyopts,cmdutil,ui,util,templater,node') def __gather(ui, repo, node1, node2): def dirtywork(f, mmap1, mmap2): @@ -150,7 +150,7 @@ def churn(ui, repo, **opts): amap = get_aliases(f) f.close() - revs = [int(r) for r in commands.revrange(ui, repo, opts['rev'])] + revs = [int(r) for r in cmdutil.revrange(ui, repo, opts['rev'])] revs.sort() stats = gather_stats(ui, repo, amap, revs, opts.get('progress')) diff --git a/hgext/extdiff.py b/hgext/extdiff.py --- a/hgext/extdiff.py +++ b/hgext/extdiff.py @@ -45,7 +45,7 @@ from mercurial.demandload import demandload from mercurial.i18n import gettext as _ from mercurial.node import * -demandload(globals(), 'mercurial:commands,cmdutil,util os shutil tempfile') +demandload(globals(), 'mercurial:cmdutil,util os shutil tempfile') def dodiff(ui, repo, diffcmd, diffopts, pats, opts): def snapshot_node(files, node): @@ -90,7 +90,7 @@ def dodiff(ui, repo, diffcmd, diffopts, fp.write(chunk) return dirname - node1, node2 = commands.revpair(ui, repo, opts['rev']) + node1, node2 = cmdutil.revpair(ui, repo, opts['rev']) files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) modified, added, removed, deleted, unknown = repo.status( node1, node2, files, match=matchfn)[:5] diff --git a/hgext/mq.py b/hgext/mq.py --- a/hgext/mq.py +++ b/hgext/mq.py @@ -40,7 +40,7 @@ commands.norepo += " qclone qversion" class statusentry: def __init__(self, rev, name=None): if not name: - fields = rev.split(':') + fields = rev.split(':', 1) if len(fields) == 2: self.rev, self.name = fields else: @@ -483,24 +483,35 @@ class queue: tr.close() return (err, n) - def delete(self, repo, patches, keep=False): + def delete(self, repo, patches, opts): realpatches = [] + appliedbase = 0 + forget = opts.get('forget') for patch in patches: patch = self.lookup(patch, strict=True) info = self.isapplied(patch) - if info: + if info and not forget: raise util.Abort(_("cannot delete applied patch %s") % patch) if patch not in self.series: raise util.Abort(_("patch %s not in series file") % patch) + if forget: + if not info: + raise util.Abort(_("cannot forget unapplied patch %s") % patch) + if info[0] != appliedbase: + raise util.Abort(_("patch %s not at base") % patch) + appliedbase += 1 realpatches.append(patch) - if not keep: + if not opts.get('keep'): r = self.qrepo() if r: r.remove(realpatches, True) else: os.unlink(self.join(patch)) + if forget: + del self.applied[:appliedbase] + self.applied_dirty = 1 indices = [self.find_series(p) for p in realpatches] indices.sort() for i in indices[-1::-1]: @@ -995,6 +1006,8 @@ class queue: r = list(util.unique(dd)) a = list(util.unique(aa)) filelist = filter(matchfn, util.unique(m + r + a)) + if opts.get('git'): + self.diffopts().git = True patch.diff(repo, patchparent, files=filelist, match=matchfn, fp=patchf, changes=(m, a, r, [], u), opts=self.diffopts()) @@ -1304,10 +1317,15 @@ class queue: def delete(ui, repo, patch, *patches, **opts): """remove patches from queue - The patches must not be applied. - With -k, the patch files are preserved in the patch directory.""" + With --forget, mq will stop managing the named patches. The + patches must be applied and at the base of the stack. This option + is useful when the patches have been applied upstream. + + Otherwise, the patches must not be applied. + + With --keep, the patch files are preserved in the patch directory.""" q = repo.mq - q.delete(repo, (patch,) + patches, keep=opts.get('keep')) + q.delete(repo, (patch,) + patches, opts) q.save_dirty() return 0 @@ -1651,13 +1669,6 @@ def rename(ui, repo, patch, name=None, * name = patch patch = None - if name in q.series: - raise util.Abort(_('A patch named %s already exists in the series file') % name) - - absdest = q.join(name) - if os.path.exists(absdest): - raise util.Abort(_('%s already exists') % absdest) - if patch: patch = q.lookup(patch) else: @@ -1665,6 +1676,15 @@ def rename(ui, repo, patch, name=None, * ui.write(_('No patches applied\n')) return patch = q.lookup('qtip') + absdest = q.join(name) + if os.path.isdir(absdest): + name = os.path.join(name, os.path.basename(patch)) + absdest = q.join(name) + if os.path.exists(absdest): + raise util.Abort(_('%s already exists') % absdest) + + if name in q.series: + raise util.Abort(_('A patch named %s already exists in the series file') % name) if ui.verbose: ui.write('Renaming %s to %s\n' % (patch, name)) @@ -1736,7 +1756,8 @@ def strip(ui, repo, rev, **opts): backup = 'strip' elif opts['nobackup']: backup = 'none' - repo.mq.strip(repo, rev, backup=backup) + update = repo.dirstate.parents()[0] != revlog.nullid + repo.mq.strip(repo, rev, backup=backup, update=update) return 0 def select(ui, repo, *args, **opts): @@ -1912,8 +1933,9 @@ cmdtable = { 'hg qdiff [-I] [-X] [FILE]...'), "qdelete|qremove|qrm": (delete, - [('k', 'keep', None, _('keep patch file'))], - 'hg qdelete [-k] PATCH'), + [('f', 'forget', None, _('stop managing an applied patch')), + ('k', 'keep', None, _('keep patch file'))], + 'hg qdelete [-f] [-k] PATCH'), 'qfold': (fold, [('e', 'edit', None, _('edit patch header')), @@ -1964,6 +1986,7 @@ cmdtable = { [('e', 'edit', None, _('edit commit message')), ('m', 'message', '', _('change commit message with ')), ('l', 'logfile', '', _('change commit message with content')), + ('g', 'git', None, _('use git extended diff format')), ('s', 'short', None, 'short refresh'), ('I', 'include', [], _('include names matching the given patterns')), ('X', 'exclude', [], _('exclude names matching the given patterns'))], @@ -1995,7 +2018,7 @@ cmdtable = { (series, [('m', 'missing', None, 'print patches not in series'), ('s', 'summary', None, _('print first line of patch header'))], - 'hg qseries [-m]'), + 'hg qseries [-ms]'), "^strip": (strip, [('f', 'force', None, 'force multi-head removal'), diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -11,6 +11,76 @@ from i18n import gettext as _ demandload(globals(), 'mdiff util') demandload(globals(), 'os sys') +revrangesep = ':' + +def revfix(repo, val, defval): + '''turn user-level id of changeset into rev number. + user-level id can be tag, changeset, rev number, or negative rev + number relative to number of revs (-1 is tip, etc).''' + if not val: + return defval + try: + num = int(val) + if str(num) != val: + raise ValueError + if num < 0: + num += repo.changelog.count() + if num < 0: + num = 0 + elif num >= repo.changelog.count(): + raise ValueError + except ValueError: + try: + num = repo.changelog.rev(repo.lookup(val)) + except KeyError: + raise util.Abort(_('invalid revision identifier %s') % val) + return num + +def revpair(ui, repo, revs): + '''return pair of nodes, given list of revisions. second item can + be None, meaning use working dir.''' + if not revs: + return repo.dirstate.parents()[0], None + end = None + if len(revs) == 1: + start = revs[0] + if revrangesep in start: + start, end = start.split(revrangesep, 1) + start = revfix(repo, start, 0) + end = revfix(repo, end, repo.changelog.count() - 1) + else: + start = revfix(repo, start, None) + elif len(revs) == 2: + if revrangesep in revs[0] or revrangesep in revs[1]: + raise util.Abort(_('too many revisions specified')) + start = revfix(repo, revs[0], None) + end = revfix(repo, revs[1], None) + else: + raise util.Abort(_('too many revisions specified')) + if end is not None: end = repo.lookup(str(end)) + return repo.lookup(str(start)), end + +def revrange(ui, repo, revs): + """Yield revision as strings from a list of revision specifications.""" + seen = {} + for spec in revs: + if revrangesep in spec: + start, end = spec.split(revrangesep, 1) + start = revfix(repo, start, 0) + end = revfix(repo, end, repo.changelog.count() - 1) + step = start > end and -1 or 1 + for rev in xrange(start, end+step, step): + if rev in seen: + continue + seen[rev] = 1 + yield str(rev) + else: + rev = revfix(repo, spec, None) + if rev in seen: + continue + seen[rev] = 1 + yield str(rev) + def make_filename(repo, pat, node, total=None, seqno=None, revwidth=None, pathname=None): node_expander = { diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -108,7 +108,7 @@ def walkchangerevs(ui, repo, pats, opts) defrange = '%s:0' % start else: defrange = 'tip:0' - revs = map(int, revrange(ui, repo, opts['rev'] or [defrange])) + revs = map(int, cmdutil.revrange(ui, repo, opts['rev'] or [defrange])) wanted = {} slowpath = anypats fncache = {} @@ -252,76 +252,6 @@ def walkchangerevs(ui, repo, pats, opts) yield 'iter', rev, None return iterate(), getchange, matchfn -revrangesep = ':' - -def revfix(repo, val, defval): - '''turn user-level id of changeset into rev number. - user-level id can be tag, changeset, rev number, or negative rev - number relative to number of revs (-1 is tip, etc).''' - if not val: - return defval - try: - num = int(val) - if str(num) != val: - raise ValueError - if num < 0: - num += repo.changelog.count() - if num < 0: - num = 0 - elif num >= repo.changelog.count(): - raise ValueError - except ValueError: - try: - num = repo.changelog.rev(repo.lookup(val)) - except KeyError: - raise util.Abort(_('invalid revision identifier %s') % val) - return num - -def revpair(ui, repo, revs): - '''return pair of nodes, given list of revisions. second item can - be None, meaning use working dir.''' - if not revs: - return repo.dirstate.parents()[0], None - end = None - if len(revs) == 1: - start = revs[0] - if revrangesep in start: - start, end = start.split(revrangesep, 1) - start = revfix(repo, start, 0) - end = revfix(repo, end, repo.changelog.count() - 1) - else: - start = revfix(repo, start, None) - elif len(revs) == 2: - if revrangesep in revs[0] or revrangesep in revs[1]: - raise util.Abort(_('too many revisions specified')) - start = revfix(repo, revs[0], None) - end = revfix(repo, revs[1], None) - else: - raise util.Abort(_('too many revisions specified')) - if end is not None: end = repo.lookup(str(end)) - return repo.lookup(str(start)), end - -def revrange(ui, repo, revs): - """Yield revision as strings from a list of revision specifications.""" - seen = {} - for spec in revs: - if revrangesep in spec: - start, end = spec.split(revrangesep, 1) - start = revfix(repo, start, 0) - end = revfix(repo, end, repo.changelog.count() - 1) - step = start > end and -1 or 1 - for rev in xrange(start, end+step, step): - if rev in seen: - continue - seen[rev] = 1 - yield str(rev) - else: - rev = revfix(repo, spec, None) - if rev in seen: - continue - seen[rev] = 1 - yield str(rev) - def write_bundle(cg, filename=None, compress=True): """Write a bundle file and return its filename. @@ -1344,7 +1274,7 @@ def diff(ui, repo, *pats, **opts): it detects as binary. With -a, diff will generate a diff anyway, probably with undesirable results. """ - node1, node2 = revpair(ui, repo, opts['rev']) + node1, node2 = cmdutil.revpair(ui, repo, opts['rev']) fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) @@ -1380,7 +1310,7 @@ def export(ui, repo, *changesets, **opts """ if not changesets: raise util.Abort(_("export requires at least one changeset")) - revs = list(revrange(ui, repo, changesets)) + revs = list(cmdutil.revrange(ui, repo, changesets)) if len(revs) > 1: ui.note(_('exporting patches:\n')) else: diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -143,7 +143,7 @@ class lazyparser(object): # the revlog may have grown since we've started running, # but we don't have space in self.index for more entries. # limit blocksize so that we don't get too much data. - blocksize = self.datasize - blockstart + blocksize = max(self.datasize - blockstart, 0) data = self.dataf.read(blocksize) lend = len(data) / self.s i = blockstart / self.s diff --git a/mercurial/sshrepo.py b/mercurial/sshrepo.py --- a/mercurial/sshrepo.py +++ b/mercurial/sshrepo.py @@ -32,13 +32,6 @@ class sshrepository(remoterepository): remotecmd = self.ui.config("ui", "remotecmd", "hg") if create: - try: - self.validate_repo(ui, sshcmd, args, remotecmd) - except hg.RepoError: - pass - else: - raise hg.RepoError(_("repository %s already exists") % path) - cmd = '%s %s "%s init %s"' cmd = cmd % (sshcmd, args, remotecmd, self.path) diff --git a/tests/test-init.out b/tests/test-init.out --- a/tests/test-init.out +++ b/tests/test-init.out @@ -3,7 +3,6 @@ adding foo #test failure abort: repository local already exists! # init+push to remote2 -remote: abort: repository remote2 not found! changeset: 0:c4e059d443be tag: tip user: test @@ -17,26 +16,25 @@ remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files # clone to remote1 -remote: abort: repository remote1 not found! searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files # init to existing repo -abort: repository ssh://user@dummy/remote1 already exists! +abort: repository remote1 already exists! +abort: could not create remote repo! # clone to existing repo -abort: repository ssh://user@dummy/remote1 already exists! +abort: repository remote1 already exists! +abort: could not create remote repo! # output of dummyssh -Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio 3: 4: 5: Got arguments 1:user@dummy 2:hg init remote2 3: 4: 5: Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio 3: 4: 5: Got arguments 1:user@dummy 2:hg -R remote2 serve --stdio 3: 4: 5: -Got arguments 1:user@dummy 2:hg -R remote1 serve --stdio 3: 4: 5: Got arguments 1:user@dummy 2:hg init remote1 3: 4: 5: Got arguments 1:user@dummy 2:hg -R remote1 serve --stdio 3: 4: 5: -Got arguments 1:user@dummy 2:hg -R remote1 serve --stdio 3: 4: 5: -Got arguments 1:user@dummy 2:hg -R remote1 serve --stdio 3: 4: 5: +Got arguments 1:user@dummy 2:hg init remote1 3: 4: 5: +Got arguments 1:user@dummy 2:hg init remote1 3: 4: 5: # comparing repositories 0:c4e059d443be 0:c4e059d443be diff --git a/tests/test-mq-qdelete b/tests/test-mq-qdelete new file mode 100755 --- /dev/null +++ b/tests/test-mq-qdelete @@ -0,0 +1,35 @@ +#!/bin/sh + +echo "[extensions]" >> $HGRCPATH +echo "mq=" >> $HGRCPATH + +hg init a +cd a + +echo 'base' > base +hg ci -Ambase -d '1 0' + +hg qnew a +hg qnew b +hg qnew c + +hg qdel c +hg qpop +hg qdel c +hg qseries +ls .hg/patches +hg qpop +hg qdel -k b +ls .hg/patches +hg qdel -f a +hg qapplied +hg log --template '{rev} {desc}\n' + +hg qnew d +hg qnew e +hg qnew f + +hg qdel -f e +hg qdel -f d e +hg qapplied +hg log --template '{rev} {desc}\n' diff --git a/tests/test-mq-qdelete.out b/tests/test-mq-qdelete.out new file mode 100644 --- /dev/null +++ b/tests/test-mq-qdelete.out @@ -0,0 +1,23 @@ +adding base +abort: cannot delete applied patch c +Now at: b +a +b +a +b +series +status +Now at: a +a +b +series +status +1 New patch: a +0 base +abort: patch e not at base +f +4 New patch: f +3 New patch: e +2 New patch: d +1 New patch: a +0 base diff --git a/tests/test-mq-qrename b/tests/test-mq-qrename new file mode 100755 --- /dev/null +++ b/tests/test-mq-qrename @@ -0,0 +1,25 @@ +#!/bin/sh + +echo "[extensions]" >> $HGRCPATH +echo "mq=" >> $HGRCPATH + +hg init a +cd a + +echo 'base' > base +hg ci -Ambase -d '1 0' + +hg qnew -mmqbase mqbase +hg qrename mqbase renamed +mkdir .hg/patches/foo +hg qrename renamed foo +hg qseries +ls .hg/patches/foo +mkdir .hg/patches/bar +hg qrename foo/renamed bar +hg qseries +ls .hg/patches/bar +hg qrename bar/renamed baz +hg qseries +ls .hg/patches/baz + diff --git a/tests/test-mq-qrename.out b/tests/test-mq-qrename.out new file mode 100644 --- /dev/null +++ b/tests/test-mq-qrename.out @@ -0,0 +1,7 @@ +adding base +foo/renamed +renamed +bar/renamed +renamed +baz +.hg/patches/baz