summaryrefslogtreecommitdiff
path: root/hgext/mq.py
diff options
context:
space:
mode:
Diffstat (limited to 'hgext/mq.py')
-rw-r--r--hgext/mq.py704
1 files changed, 197 insertions, 507 deletions
diff --git a/hgext/mq.py b/hgext/mq.py
index 33a31c4..a1b4e81 100644
--- a/hgext/mq.py
+++ b/hgext/mq.py
@@ -38,32 +38,15 @@ preserving existing git patches upon qrefresh. If set to 'yes' or
'no', mq will override the [diff] section and always generate git or
regular patches, possibly losing data in the second case.
-It may be desirable for mq changesets to be kept in the secret phase (see
-:hg:`help phases`), which can be enabled with the following setting::
-
- [mq]
- secret = True
-
You will by default be managing a patch queue named "patches". You can
create other, independent patch queues with the :hg:`qqueue` command.
-
-If the working directory contains uncommitted files, qpush, qpop and
-qgoto abort immediately. If -f/--force is used, the changes are
-discarded. Setting::
-
- [mq]
- keepchanges = True
-
-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.
'''
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, url, error, phases
+from mercurial import repair, extensions, url, error
from mercurial import patch as patchmod
import os, re, errno, shutil
@@ -73,7 +56,6 @@ seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
cmdtable = {}
command = cmdutil.command(cmdtable)
-testedwith = 'internal'
# Patch names looks like unix-file names.
# They must be joinable with queue directory and result in the patch path.
@@ -269,32 +251,6 @@ class patchheader(object):
ci += 1
del self.comments[ci]
-def newcommit(repo, phase, *args, **kwargs):
- """helper dedicated to ensure a commit respect mq.secret setting
-
- It should be used instead of repo.commit inside the mq source for operation
- creating new changeset.
- """
- if phase is None:
- if repo.ui.configbool('mq', 'secret', False):
- 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)
-
-class AbortNoCleanup(error.Abort):
- pass
-
class queue(object):
def __init__(self, ui, path, patchdir=None):
self.basepath = path
@@ -311,8 +267,8 @@ class queue(object):
self.path = patchdir or curpath
self.opener = scmutil.opener(self.path)
self.ui = ui
- self.applieddirty = False
- self.seriesdirty = False
+ self.applieddirty = 0
+ self.seriesdirty = 0
self.added = []
self.seriespath = "series"
self.statuspath = "status"
@@ -323,7 +279,7 @@ class queue(object):
try:
gitmode = ui.configbool('mq', 'git', None)
if gitmode is None:
- raise error.ConfigError
+ raise error.ConfigError()
self.gitmode = gitmode and 'yes' or 'no'
except error.ConfigError:
self.gitmode = ui.config('mq', 'git', 'auto').lower()
@@ -331,31 +287,25 @@ class queue(object):
@util.propertycache
def applied(self):
- def parselines(lines):
- for l in lines:
- entry = l.split(':', 1)
- if len(entry) > 1:
- n, name = entry
- yield statusentry(bin(n), name)
- elif l.strip():
- self.ui.warn(_('malformated mq status line: %s\n') % entry)
- # else we ignore empty lines
- try:
+ if os.path.exists(self.join(self.statuspath)):
+ def parselines(lines):
+ for l in lines:
+ entry = l.split(':', 1)
+ if len(entry) > 1:
+ n, name = entry
+ yield statusentry(bin(n), name)
+ elif l.strip():
+ self.ui.warn(_('malformated mq status line: %s\n') % entry)
+ # else we ignore empty lines
lines = self.opener.read(self.statuspath).splitlines()
return list(parselines(lines))
- except IOError, e:
- if e.errno == errno.ENOENT:
- return []
- raise
+ return []
@util.propertycache
def fullseries(self):
- try:
+ if os.path.exists(self.join(self.seriespath)):
return self.opener.read(self.seriespath).splitlines()
- except IOError, e:
- if e.errno == errno.ENOENT:
- return []
- raise
+ return []
@util.propertycache
def series(self):
@@ -371,8 +321,8 @@ class queue(object):
for a in 'applied fullseries series seriesguards'.split():
if a in self.__dict__:
delattr(self, a)
- self.applieddirty = False
- self.seriesdirty = False
+ self.applieddirty = 0
+ self.seriesdirty = 0
self.guardsdirty = False
self.activeguards = None
@@ -547,13 +497,10 @@ class queue(object):
fp.close()
if self.applieddirty:
writelist(map(str, self.applied), self.statuspath)
- self.applieddirty = False
if self.seriesdirty:
writelist(self.fullseries, self.seriespath)
- self.seriesdirty = False
if self.guardsdirty:
writelist(self.activeguards, self.guardspath)
- self.guardsdirty = False
if self.added:
qrepo = self.qrepo()
if qrepo:
@@ -569,18 +516,6 @@ class queue(object):
except OSError, inst:
self.ui.warn(_('error removing undo: %s\n') % str(inst))
- def backup(self, repo, files, copy=False):
- # backup local changes in --force case
- for f in sorted(files):
- absf = repo.wjoin(f)
- if os.path.lexists(absf):
- self.ui.note(_('saving current version of %s as %s\n') %
- (f, f + '.orig'))
- if copy:
- util.copyfile(absf, absf + '.orig')
- else:
- util.rename(absf, absf + '.orig')
-
def printdiff(self, repo, diffopts, node1, node2=None, files=None,
fp=None, changes=None, opts={}):
stat = opts.get('stat')
@@ -609,12 +544,12 @@ class queue(object):
ret = hg.merge(repo, rev)
if ret:
raise util.Abort(_("update returned %d") % ret)
- n = newcommit(repo, None, ctx.description(), ctx.user(), force=True)
+ n = repo.commit(ctx.description(), ctx.user(), force=True)
if n is None:
raise util.Abort(_("repo commit failed"))
try:
ph = patchheader(mergeq.join(patch), self.plainmode)
- except Exception:
+ except:
raise util.Abort(_("unable to read %s") % patch)
diffopts = self.patchopts(diffopts, patch)
@@ -649,10 +584,10 @@ class queue(object):
# the first patch in the queue is never a merge patch
#
pname = ".hg.patches.merge.marker"
- n = newcommit(repo, None, '[mq]: merge marker', force=True)
+ n = repo.commit('[mq]: merge marker', force=True)
self.removeundo(repo)
self.applied.append(statusentry(n, pname))
- self.applieddirty = True
+ self.applieddirty = 1
head = self.qparents(repo)
@@ -673,7 +608,7 @@ class queue(object):
err, head = self.mergeone(repo, mergeq, head, patch, rev, diffopts)
if head:
self.applied.append(statusentry(head, patch))
- self.applieddirty = True
+ self.applieddirty = 1
if err:
return (err, head)
self.savedirty()
@@ -691,12 +626,10 @@ class queue(object):
self.ui.note(str(inst) + '\n')
if not self.ui.verbose:
self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
- self.ui.traceback()
return (False, list(files), False)
def apply(self, repo, series, list=False, update_status=True,
- strict=False, patchdir=None, merge=None, all_files=None,
- tobackup=None, keepchanges=False):
+ strict=False, patchdir=None, merge=None, all_files=None):
wlock = lock = tr = None
try:
wlock = repo.wlock()
@@ -704,36 +637,25 @@ class queue(object):
tr = repo.transaction("qpush")
try:
ret = self._apply(repo, series, list, update_status,
- strict, patchdir, merge, all_files=all_files,
- tobackup=tobackup, keepchanges=keepchanges)
+ strict, patchdir, merge, all_files=all_files)
tr.close()
self.savedirty()
return ret
- except AbortNoCleanup:
- tr.close()
- self.savedirty()
- return 2, repo.dirstate.p1()
- except: # re-raises
+ except:
try:
tr.abort()
finally:
repo.invalidate()
repo.dirstate.invalidate()
- self.invalidate()
raise
finally:
release(tr, lock, wlock)
self.removeundo(repo)
def _apply(self, repo, series, list=False, update_status=True,
- strict=False, patchdir=None, merge=None, all_files=None,
- tobackup=None, keepchanges=False):
- """returns (error, hash)
-
- error = 1 for unable to read, 2 for patch failed, 3 for patch
- fuzz. tobackup is None or a set of files to backup before they
- are modified by a patch.
- """
+ strict=False, patchdir=None, merge=None, all_files=None):
+ '''returns (error, hash)
+ error = 1 for unable to read, 2 for patch failed, 3 for patch fuzz'''
# TODO unify with commands.py
if not patchdir:
patchdir = self.path
@@ -765,14 +687,6 @@ class queue(object):
message = '\n'.join(message)
if ph.haspatch:
- if tobackup:
- touched = patchmod.changedfiles(self.ui, repo, pf)
- touched = set(touched) & tobackup
- if touched and keepchanges:
- raise AbortNoCleanup(
- _("local changes found, refresh first"))
- self.backup(repo, touched, copy=True)
- tobackup = tobackup - touched
(patcherr, files, fuzz) = self.patch(repo, pf)
if all_files is not None:
all_files.update(files)
@@ -795,14 +709,11 @@ class queue(object):
for f in merged:
repo.dirstate.merge(f)
p1, p2 = repo.dirstate.parents()
- repo.setparents(p1, merge)
+ repo.dirstate.setparents(p1, merge)
match = scmutil.matchfiles(repo, files or [])
- oldtip = repo['tip']
- n = newcommit(repo, None, message, ph.user, ph.date, match=match,
- force=True)
- if repo['tip'] == oldtip:
- raise util.Abort(_("qpush exactly duplicates child changeset"))
+ n = repo.commit(message, ph.user, ph.date, match=match, force=True)
+
if n is None:
raise util.Abort(_("repository commit failed"))
@@ -828,11 +739,10 @@ class queue(object):
for p in patches:
os.unlink(self.join(p))
- qfinished = []
if numrevs:
qfinished = self.applied[:numrevs]
del self.applied[:numrevs]
- self.applieddirty = True
+ self.applieddirty = 1
unknown = []
@@ -854,8 +764,7 @@ class queue(object):
raise util.Abort(''.join(msg % p for p in unknown))
self.parseseries()
- self.seriesdirty = True
- return [entry.node for entry in qfinished]
+ self.seriesdirty = 1
def _revpatches(self, repo, revs):
firstrev = repo[self.applied[0].node].rev()
@@ -882,17 +791,8 @@ class queue(object):
return patches
def finish(self, repo, revs):
- # Manually trigger phase computation to ensure phasedefaults is
- # executed before we remove the patches.
- repo._phasecache
patches = self._revpatches(repo, sorted(revs))
- qfinished = self._cleanup(patches, len(patches))
- if qfinished and repo.ui.configbool('mq', 'secret', False):
- # only use this logic when the secret option is added
- oldqbase = repo[qfinished[0]]
- tphase = repo.ui.config('phases', 'new-commit', phases.draft)
- if oldqbase.phase() > tphase and oldqbase.p1().phase() <= tphase:
- phases.advanceboundary(repo, tphase, qfinished)
+ self._cleanup(patches, len(patches))
def delete(self, repo, patches, opts):
if not patches and not opts.get('rev'):
@@ -933,35 +833,19 @@ class queue(object):
return top, patch
return None, None
- def checksubstate(self, repo, baserev=None):
+ def checksubstate(self, repo):
'''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 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():
+ elif wctx.sub(s).dirty():
inclsubs.append(s)
return inclsubs
- def putsubstate2changes(self, substatestate, changes):
- for files in changes[:3]:
- if '.hgsubstate' in files:
- return # already listed up
- # not yet listed up
- if substatestate in 'a?':
- changes[1].append('.hgsubstate')
- elif substatestate in 'r':
- changes[2].append('.hgsubstate')
- else: # modified
- changes[0].append('.hgsubstate')
-
def localchangesfound(self, refresh=True):
if refresh:
raise util.Abort(_("local changes found, refresh first"))
@@ -997,10 +881,6 @@ class queue(object):
else:
raise util.Abort(_('patch "%s" already exists') % name)
- def checkkeepchanges(self, keepchanges, force):
- if force and keepchanges:
- raise util.Abort(_('cannot use both --force and --keep-changes'))
-
def new(self, repo, patchfn, *pats, **opts):
"""options:
msg: a string or a no-argument function returning a string
@@ -1016,7 +896,6 @@ class queue(object):
inclsubs = self.checksubstate(repo)
if inclsubs:
inclsubs.append('.hgsubstate')
- substatestate = repo.dirstate['.hgsubstate']
if opts.get('include') or opts.get('exclude') or pats:
if inclsubs:
pats = list(pats or []) + inclsubs
@@ -1026,12 +905,10 @@ class queue(object):
if f != '.hgsubstate': # .hgsubstate is auto-created
raise util.Abort('%s: %s' % (f, msg))
match.bad = badfn
- changes = repo.status(match=match)
- m, a, r, d = changes[:4]
+ m, a, r, d = repo.status(match=match)[:4]
else:
- changes = self.checklocalchanges(repo, force=True)
- m, a, r, d = changes
- match = scmutil.matchfiles(repo, m + a + r + inclsubs)
+ m, a, r, d = self.checklocalchanges(repo, force=True)
+ match = scmutil.matchfiles(repo, m + a + r + inclsubs)
if len(repo[None].parents()) > 1:
raise util.Abort(_('cannot manage merge changesets'))
commitfiles = m + a + r
@@ -1061,42 +938,41 @@ class queue(object):
p.write("# User " + user + "\n")
if date:
p.write("# Date %s %s\n\n" % date)
- if util.safehasattr(msg, '__call__'):
+ if hasattr(msg, '__call__'):
msg = msg()
commitmsg = msg and msg or ("[mq]: %s" % patchfn)
- n = newcommit(repo, None, commitmsg, user, date, match=match,
- force=True)
+ n = repo.commit(commitmsg, user, date, match=match, force=True)
if n is None:
raise util.Abort(_("repo commit failed"))
try:
self.fullseries[insert:insert] = [patchfn]
self.applied.append(statusentry(n, patchfn))
self.parseseries()
- self.seriesdirty = True
- self.applieddirty = True
+ self.seriesdirty = 1
+ self.applieddirty = 1
if msg:
msg = msg + "\n\n"
p.write(msg)
if commitfiles:
parent = self.qparents(repo, n)
- if inclsubs:
- self.putsubstate2changes(substatestate, changes)
chunks = patchmod.diff(repo, node1=parent, node2=n,
- changes=changes, opts=diffopts)
+ match=match, opts=diffopts)
for chunk in chunks:
p.write(chunk)
p.close()
+ wlock.release()
+ wlock = None
r = self.qrepo()
if r:
r[None].add([patchfn])
- except: # re-raises
+ except:
repo.rollback()
raise
except Exception:
patchpath = self.join(patchfn)
try:
os.unlink(patchpath)
- except OSError:
+ except:
self.ui.warn(_('error unlinking %s\n') % patchpath)
raise
self.removeundo(repo)
@@ -1115,7 +991,12 @@ class queue(object):
hg.clean(repo, urev)
repo.dirstate.write()
- repair.strip(self.ui, repo, revs, backup)
+ self.removeundo(repo)
+ for rev in revs:
+ repair.strip(self.ui, repo, rev, backup)
+ # strip may have unbundled a set of backed up revisions after
+ # the actual strip
+ self.removeundo(repo)
finally:
release(lock, wlock)
@@ -1129,10 +1010,12 @@ class queue(object):
# if the exact patch name does not exist, we try a few
# variations. If strict is passed, we try only #1
#
- # 1) a number (as string) to indicate an offset in the series file
+ # 1) a number to indicate an offset in the series file
# 2) a unique substring of the patch name was given
# 3) patchname[-+]num to indicate an offset in the series file
def lookup(self, patch, strict=False):
+ patch = patch and str(patch)
+
def partialname(s):
if s in self.series:
return s
@@ -1151,6 +1034,8 @@ class queue(object):
return self.series[0]
return None
+ if patch is None:
+ return None
if patch in self.series:
return patch
@@ -1193,10 +1078,8 @@ class queue(object):
return self.series[i + off]
raise util.Abort(_("patch %s not in series") % patch)
- def push(self, repo, patch=None, force=False, list=False, mergeq=None,
- all=False, move=False, exact=False, nobackup=False,
- keepchanges=False):
- self.checkkeepchanges(keepchanges, force)
+ def push(self, repo, patch=None, force=False, list=False,
+ mergeq=None, all=False, move=False, exact=False):
diffopts = self.diffopts()
wlock = repo.wlock()
try:
@@ -1212,12 +1095,12 @@ class queue(object):
self.ui.warn(_('no patches in series\n'))
return 0
+ patch = self.lookup(patch)
# Suppose our series file is: A B C and the current 'top'
# patch is B. qpush C should be performed (moving forward)
# qpush B is a NOP (no change) qpush A is an error (can't
# go backwards with qpush)
if patch:
- patch = self.lookup(patch)
info = self.isapplied(patch)
if info and info[0] >= len(self.applied) - 1:
self.ui.warn(
@@ -1251,47 +1134,37 @@ class queue(object):
if start == len(self.series):
self.ui.warn(_('patch series already fully applied\n'))
return 1
- if not force and not keepchanges:
+ if not force:
self.checklocalchanges(repo, refresh=self.applied)
if exact:
- if keepchanges:
- raise util.Abort(
- _("cannot use --exact and --keep-changes together"))
if move:
- raise util.Abort(_('cannot use --exact and --move '
- 'together'))
+ raise util.Abort(_("cannot use --exact and --move together"))
if self.applied:
- raise util.Abort(_('cannot push --exact with applied '
- 'patches'))
+ raise util.Abort(_("cannot push --exact with applied patches"))
root = self.series[start]
target = patchheader(self.join(root), self.plainmode).parent
if not target:
- raise util.Abort(
- _("%s does not have a parent recorded") % root)
+ raise util.Abort(_("%s does not have a parent recorded" % root))
if not repo[target] == repo['.']:
hg.update(repo, target)
if move:
if not patch:
raise util.Abort(_("please specify the patch to move"))
- for fullstart, rpn in enumerate(self.fullseries):
- # strip markers for patch guards
- if self.guard_re.split(rpn, 1)[0] == self.series[start]:
- break
- for i, rpn in enumerate(self.fullseries[fullstart:]):
+ for i, rpn in enumerate(self.fullseries[start:]):
# strip markers for patch guards
if self.guard_re.split(rpn, 1)[0] == patch:
break
- index = fullstart + i
+ index = start + i
assert index < len(self.fullseries)
fullpatch = self.fullseries[index]
del self.fullseries[index]
- self.fullseries.insert(fullstart, fullpatch)
+ self.fullseries.insert(start, fullpatch)
self.parseseries()
- self.seriesdirty = True
+ self.seriesdirty = 1
- self.applieddirty = True
+ self.applieddirty = 1
if start > 0:
self.checktoppatch(repo)
if not patch:
@@ -1300,23 +1173,14 @@ class queue(object):
else:
end = self.series.index(patch, start) + 1
- tobackup = set()
- if (not nobackup and force) or keepchanges:
- m, a, r, d = self.checklocalchanges(repo, force=True)
- if keepchanges:
- tobackup.update(m + a + r + d)
- else:
- tobackup.update(m + a)
-
s = self.series[start:end]
all_files = set()
try:
if mergeq:
ret = self.mergepatch(repo, mergeq, s, diffopts)
else:
- ret = self.apply(repo, s, list, all_files=all_files,
- tobackup=tobackup, keepchanges=keepchanges)
- except: # re-raises
+ ret = self.apply(repo, s, list, all_files=all_files)
+ except:
self.ui.warn(_('cleaning up working directory...'))
node = repo.dirstate.p1()
hg.revert(repo, node, None)
@@ -1345,9 +1209,7 @@ class queue(object):
finally:
wlock.release()
- def pop(self, repo, patch=None, force=False, update=True, all=False,
- nobackup=False, keepchanges=False):
- self.checkkeepchanges(keepchanges, force)
+ def pop(self, repo, patch=None, force=False, update=True, all=False):
wlock = repo.wlock()
try:
if patch:
@@ -1392,17 +1254,10 @@ class queue(object):
break
update = needupdate
- tobackup = set()
- if update:
- m, a, r, d = self.checklocalchanges(
- repo, force=force or keepchanges)
- if force:
- if not nobackup:
- tobackup.update(m + a)
- elif keepchanges:
- tobackup.update(m + a + r + d)
-
- self.applieddirty = True
+ if not force and update:
+ self.checklocalchanges(repo)
+
+ self.applieddirty = 1
end = len(self.applied)
rev = self.applied[start].node
if update:
@@ -1417,10 +1272,6 @@ class queue(object):
if heads != [self.applied[-1].node]:
raise util.Abort(_("popping would remove a revision not "
"managed by this patch queue"))
- if not repo[self.applied[-1].node].mutable():
- raise util.Abort(
- _("popping would remove an immutable revision"),
- hint=_('see "hg help phases" for details'))
# we know there are no local changes, so we can make a simplified
# form of hg.update.
@@ -1430,12 +1281,6 @@ class queue(object):
m, a, r, d = repo.status(qp, top)[:4]
if d:
raise util.Abort(_("deletions found between repo revs"))
-
- tobackup = set(a + m + r) & tobackup
- if keepchanges and tobackup:
- self.localchangesfound()
- self.backup(repo, tobackup)
-
for f in a:
try:
util.unlinkpath(repo.wjoin(f))
@@ -1447,7 +1292,7 @@ class queue(object):
fctx = ctx[f]
repo.wwrite(f, fctx.data(), fctx.flags())
repo.dirstate.normal(f)
- repo.setparents(qp, nullid)
+ repo.dirstate.setparents(qp, nullid)
for patch in reversed(self.applied[start:end]):
self.ui.status(_("popping %s\n") % patch.name)
del self.applied[start:end]
@@ -1488,18 +1333,11 @@ class queue(object):
(top, patchfn) = (self.applied[-1].node, self.applied[-1].name)
if repo.changelog.heads(top) != [top]:
raise util.Abort(_("cannot refresh a revision with children"))
- if not repo[top].mutable():
- raise util.Abort(_("cannot refresh immutable revision"),
- hint=_('see "hg help phases" for details'))
+
+ inclsubs = self.checksubstate(repo)
cparents = repo.changelog.parents(top)
patchparent = self.qparents(repo, top)
-
- inclsubs = self.checksubstate(repo, hex(patchparent))
- if inclsubs:
- inclsubs.append('.hgsubstate')
- substatestate = repo.dirstate['.hgsubstate']
-
ph = patchheader(self.join(patchfn), self.plainmode)
diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
if msg:
@@ -1577,6 +1415,10 @@ class queue(object):
a = list(aa)
c = [filter(matchfn, l) for l in (m, a, r)]
match = scmutil.matchfiles(repo, set(c[0] + c[1] + c[2] + inclsubs))
+ chunks = patchmod.diff(repo, patchparent, match=match,
+ changes=c, opts=diffopts)
+ for chunk in chunks:
+ patchf.write(chunk)
try:
if diffopts.git or diffopts.upgrade:
@@ -1635,35 +1477,24 @@ class queue(object):
user = ph.user or changes[1]
- oldphase = repo[top].phase()
-
# assumes strip can roll itself back if interrupted
- repo.setparents(*cparents)
+ repo.dirstate.setparents(*cparents)
self.applied.pop()
- self.applieddirty = True
+ self.applieddirty = 1
self.strip(repo, [top], update=False,
backup='strip')
- except: # re-raises
+ except:
repo.dirstate.invalidate()
raise
try:
# might be nice to attempt to roll back strip after this
-
- # Ensure we create a new changeset in the same phase than
- # the old one.
- n = newcommit(repo, oldphase, message, user, ph.date,
- match=match, force=True)
+ n = repo.commit(message, user, ph.date, match=match,
+ force=True)
# only write patch after a successful commit
- if inclsubs:
- self.putsubstate2changes(substatestate, c)
- chunks = patchmod.diff(repo, patchparent,
- changes=c, opts=diffopts)
- for chunk in chunks:
- patchf.write(chunk)
- patchf.close()
+ patchf.rename()
self.applied.append(statusentry(n, patchfn))
- except: # re-raises
+ except:
ctx = repo[cparents[0]]
repo.dirstate.rebuild(ctx.node(), ctx.manifest())
self.savedirty()
@@ -1790,14 +1621,14 @@ class queue(object):
else:
series.append(l)
if datastart is None:
- self.ui.warn(_("no saved patch data found\n"))
+ self.ui.warn(_("No saved patch data found\n"))
return 1
self.ui.warn(_("restoring status: %s\n") % lines[0])
self.fullseries = series
self.applied = applied
self.parseseries()
- self.seriesdirty = True
- self.applieddirty = True
+ self.seriesdirty = 1
+ self.applieddirty = 1
heads = repo.changelog.heads()
if delete:
if rev not in heads:
@@ -1817,7 +1648,7 @@ class queue(object):
self.ui.status(_("updating queue directory\n"))
r = self.qrepo()
if not r:
- self.ui.warn(_("unable to load queue repository\n"))
+ self.ui.warn(_("Unable to load queue repository\n"))
return 1
hg.clean(r, qpp[0])
@@ -1845,7 +1676,7 @@ class queue(object):
self.ui.warn(_("repo commit failed\n"))
return 1
self.applied.append(statusentry(n, '.hg.patches.save.line'))
- self.applieddirty = True
+ self.applieddirty = 1
self.removeundo(repo)
def fullseriesend(self):
@@ -1869,9 +1700,9 @@ class queue(object):
for i in xrange(start, len(self.series)):
p, reason = self.pushable(i)
if p:
- return i
+ break
self.explainpushable(i)
- return len(self.series)
+ return i
if self.applied:
p = self.applied[-1].name
try:
@@ -1902,12 +1733,9 @@ class queue(object):
'files'))
rev = scmutil.revrange(repo, rev)
rev.sort(reverse=True)
- elif not files:
- raise util.Abort(_('no files or revisions specified'))
if (len(files) > 1 or len(rev) > 1) and patchname:
raise util.Abort(_('option "-n" not valid when importing multiple '
'patches'))
- imported = []
if rev:
# If mq patches are applied, we can only import revisions
# that form a linear path to qbase.
@@ -1934,9 +1762,6 @@ class queue(object):
diffopts = self.diffopts({'git': git})
for r in rev:
- if not repo[r].mutable():
- raise util.Abort(_('revision %d is not mutable') % r,
- hint=_('see "hg help phases" for details'))
p1, p2 = repo.changelog.parentrevs(r)
n = repo.changelog.node(r)
if p2 != nullrev:
@@ -1960,13 +1785,9 @@ class queue(object):
self.applied.insert(0, se)
self.added.append(patchname)
- imported.append(patchname)
patchname = None
- if rev and repo.ui.configbool('mq', 'secret', False):
- # if we added anything with --rev, we must move the secret root
- phases.retractboundary(repo, phases.secret, [n])
self.parseseries()
- self.applieddirty = True
+ self.applieddirty = 1
self.seriesdirty = True
for i, filename in enumerate(files):
@@ -2015,19 +1836,9 @@ class queue(object):
self.seriesdirty = True
self.ui.warn(_("adding %s to series file\n") % patchname)
self.added.append(patchname)
- imported.append(patchname)
patchname = None
self.removeundo(repo)
- return imported
-
-def fixkeepchangesopts(ui, opts):
- if (not ui.configbool('mq', 'keepchanges') or opts.get('force')
- or opts.get('exact')):
- return opts
- opts = dict(opts)
- opts['keep_changes'] = True
- return opts
@command("qdelete|qremove|qrm",
[('k', 'keep', None, _('keep patch file')),
@@ -2037,9 +1848,8 @@ def fixkeepchangesopts(ui, opts):
def delete(ui, repo, *patches, **opts):
"""remove patches from queue
- The patches must not be applied, and at least one patch is required. Exact
- patch identifiers must be given. With -k/--keep, the patch files are
- preserved in the patch directory.
+ The patches must not be applied, and at least one patch is required. With
+ -k/--keep, the patch files are preserved in the patch directory.
To stop managing a patch and move it into permanent history,
use the :hg:`qfinish` command."""
@@ -2049,7 +1859,7 @@ def delete(ui, repo, *patches, **opts):
return 0
@command("qapplied",
- [('1', 'last', None, _('show only the preceding applied patch'))
+ [('1', 'last', None, _('show only the last patch'))
] + seriesopts,
_('hg qapplied [-1] [-s] [PATCH]'))
def applied(ui, repo, patch=None, **opts):
@@ -2115,9 +1925,9 @@ def unapplied(ui, repo, patch=None, **opts):
_('place existing revisions under mq control'), _('REV')),
('g', 'git', None, _('use git extended diff format')),
('P', 'push', None, _('qpush after importing'))],
- _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... [FILE]...'))
+ _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... FILE...'))
def qimport(ui, repo, *filename, **opts):
- """import a patch or existing changeset
+ """import a patch
The patch is inserted into the series after the last applied
patch. If no patches have been applied, qimport prepends the patch
@@ -2149,21 +1959,16 @@ def qimport(ui, repo, *filename, **opts):
Returns 0 if import succeeded.
"""
- lock = repo.lock() # cause this may move phase
+ q = repo.mq
try:
- q = repo.mq
- try:
- imported = q.qimport(
- repo, filename, patchname=opts.get('name'),
- existing=opts.get('existing'), force=opts.get('force'),
- rev=opts.get('rev'), git=opts.get('git'))
- finally:
- q.savedirty()
+ q.qimport(repo, filename, patchname=opts.get('name'),
+ existing=opts.get('existing'), force=opts.get('force'),
+ rev=opts.get('rev'), git=opts.get('git'))
finally:
- lock.release()
+ q.savedirty()
- if imported and opts.get('push') and not opts.get('rev'):
- return q.push(repo, imported[-1])
+ if opts.get('push') and not opts.get('rev'):
+ return q.push(repo, None)
return 0
def qinit(ui, repo, create):
@@ -2210,8 +2015,7 @@ def init(ui, repo, **opts):
@command("qclone",
[('', 'pull', None, _('use pull protocol to copy metadata')),
- ('U', 'noupdate', None,
- _('do not update the new working directories')),
+ ('U', 'noupdate', None, _('do not update the new working directories')),
('', 'uncompressed', None,
_('use uncompressed transfer (fast over LAN)')),
('p', 'patches', '',
@@ -2236,63 +2040,53 @@ def clone(ui, source, dest=None, **opts):
Return 0 on success.
'''
def patchdir(repo):
- """compute a patch repo url from a repo object"""
url = repo.url()
if url.endswith('/'):
url = url[:-1]
return url + '/.hg/patches'
-
- # main repo (destination and sources)
if dest is None:
dest = hg.defaultdest(source)
- sr = hg.peer(ui, opts, ui.expandpath(source))
-
- # patches repo (source only)
+ sr = hg.repository(hg.remoteui(ui, opts), ui.expandpath(source))
if opts.get('patches'):
patchespath = ui.expandpath(opts.get('patches'))
else:
patchespath = patchdir(sr)
try:
- hg.peer(ui, opts, patchespath)
+ hg.repository(ui, patchespath)
except error.RepoError:
raise util.Abort(_('versioned patch repository not found'
' (see init --mq)'))
qbase, destrev = None, None
if sr.local():
- repo = sr.local()
- if repo.mq.applied and repo[qbase].phase() != phases.secret:
- qbase = repo.mq.applied[0].node
+ if sr.mq.applied:
+ qbase = sr.mq.applied[0].node
if not hg.islocal(dest):
- heads = set(repo.heads())
- destrev = list(heads.difference(repo.heads(qbase)))
- destrev.append(repo.changelog.parents(qbase)[0])
+ heads = set(sr.heads())
+ destrev = list(heads.difference(sr.heads(qbase)))
+ destrev.append(sr.changelog.parents(qbase)[0])
elif sr.capable('lookup'):
try:
qbase = sr.lookup('qbase')
except error.RepoError:
pass
-
ui.note(_('cloning main repository\n'))
sr, dr = hg.clone(ui, opts, sr.url(), dest,
pull=opts.get('pull'),
rev=destrev,
update=False,
stream=opts.get('uncompressed'))
-
ui.note(_('cloning patch repository\n'))
hg.clone(ui, opts, opts.get('patches') or patchdir(sr), patchdir(dr),
pull=opts.get('pull'), update=not opts.get('noupdate'),
stream=opts.get('uncompressed'))
-
if dr.local():
- repo = dr.local()
if qbase:
ui.note(_('stripping applied patches from destination '
'repository\n'))
- repo.mq.strip(repo, [qbase], update=False, backup=None)
+ dr.mq.strip(dr, [qbase], update=False, backup=None)
if not opts.get('noupdate'):
ui.note(_('updating destination repository\n'))
- hg.update(repo, repo.changelog.tip())
+ hg.update(dr, dr.changelog.tip())
@command("qcommit|qci",
commands.table["^commit|ci"][1],
@@ -2315,8 +2109,7 @@ def series(ui, repo, **opts):
"""print the entire series file
Returns 0 on success."""
- repo.mq.qseries(repo, missing=opts.get('missing'),
- summary=opts.get('summary'))
+ repo.mq.qseries(repo, missing=opts.get('missing'), summary=opts.get('summary'))
return 0
@command("qtop", seriesopts, _('hg qtop [-s]'))
@@ -2335,7 +2128,7 @@ def top(ui, repo, **opts):
@command("qnext", seriesopts, _('hg qnext [-s]'))
def next(ui, repo, **opts):
- """print the name of the next pushable patch
+ """print the name of the next patch
Returns 0 on success."""
q = repo.mq
@@ -2347,7 +2140,7 @@ def next(ui, repo, **opts):
@command("qprev", seriesopts, _('hg qprev [-s]'))
def prev(ui, repo, **opts):
- """print the name of the preceding applied patch
+ """print the name of the previous patch
Returns 0 on success."""
q = repo.mq
@@ -2358,8 +2151,7 @@ def prev(ui, repo, **opts):
if not l:
ui.write(_("no patches applied\n"))
return 1
- idx = q.series.index(q.applied[-2].name)
- q.qseries(repo, start=idx, length=1, status='A',
+ q.qseries(repo, start=l - 2, length=1, status='A',
summary=opts.get('summary'))
def setupheaderopts(ui, opts):
@@ -2517,7 +2309,9 @@ def fold(ui, repo, *files, **opts):
current patch header, separated by a line of ``* * *``.
Returns 0 on success."""
+
q = repo.mq
+
if not files:
raise util.Abort(_('qfold requires at least one patch name'))
if not q.checktoppatch(repo)[0]:
@@ -2535,10 +2329,9 @@ def fold(ui, repo, *files, **opts):
for f in files:
p = q.lookup(f)
if p in patches or p == parent:
- ui.warn(_('skipping already folded patch %s\n') % p)
+ ui.warn(_('Skipping already folded patch %s\n') % p)
if q.isapplied(p):
- raise util.Abort(_('qfold cannot fold already applied patch %s')
- % p)
+ raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
patches.append(p)
for p in patches:
@@ -2572,26 +2365,18 @@ def fold(ui, repo, *files, **opts):
wlock.release()
@command("qgoto",
- [('', 'keep-changes', None,
- _('tolerate non-conflicting local changes')),
- ('f', 'force', None, _('overwrite any local changes')),
- ('', 'no-backup', None, _('do not save backup copies of files'))],
+ [('f', 'force', None, _('overwrite any local changes'))],
_('hg qgoto [OPTION]... PATCH'))
def goto(ui, repo, patch, **opts):
'''push or pop patches until named patch is at top of stack
Returns 0 on success.'''
- opts = fixkeepchangesopts(ui, opts)
q = repo.mq
patch = q.lookup(patch)
- nobackup = opts.get('no_backup')
- keepchanges = opts.get('keep_changes')
if q.isapplied(patch):
- ret = q.pop(repo, patch, force=opts.get('force'), nobackup=nobackup,
- keepchanges=keepchanges)
+ ret = q.pop(repo, patch, force=opts.get('force'))
else:
- ret = q.push(repo, patch, force=opts.get('force'), nobackup=nobackup,
- keepchanges=keepchanges)
+ ret = q.push(repo, patch, force=opts.get('force'))
q.savedirty()
return ret
@@ -2647,8 +2432,7 @@ def guard(ui, repo, *args, **opts):
args = list(args)
if opts.get('list'):
if args or opts.get('none'):
- raise util.Abort(_('cannot mix -l/--list with options or '
- 'arguments'))
+ raise util.Abort(_('cannot mix -l/--list with options or arguments'))
for i in xrange(len(q.series)):
status(i)
return
@@ -2712,34 +2496,26 @@ def savename(path):
return newpath
@command("^qpush",
- [('', 'keep-changes', None,
- _('tolerate non-conflicting local changes')),
- ('f', 'force', None, _('apply on top of local changes')),
- ('e', 'exact', None,
- _('apply the target patch to its recorded parent')),
+ [('f', 'force', None, _('apply on top of local changes')),
+ ('e', 'exact', None, _('apply the target patch to its recorded parent')),
('l', 'list', None, _('list patch name in commit text')),
('a', 'all', None, _('apply all patches')),
('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
('n', 'name', '',
_('merge queue name (DEPRECATED)'), _('NAME')),
- ('', 'move', None,
- _('reorder patch series and apply only the patch')),
- ('', 'no-backup', None, _('do not save backup copies of files'))],
+ ('', 'move', None, _('reorder patch series and apply only the patch'))],
_('hg qpush [-f] [-l] [-a] [--move] [PATCH | INDEX]'))
def push(ui, repo, patch=None, **opts):
"""push the next patch onto the stack
- By default, abort if the working directory contains uncommitted
- changes. With --keep-changes, abort only if the uncommitted files
- overlap with patched files. With -f/--force, backup and patch over
- uncommitted changes.
+ When -f/--force is applied, all local changes in patched files
+ will be lost.
Return 0 on success.
"""
q = repo.mq
mergeq = None
- opts = fixkeepchangesopts(ui, opts)
if opts.get('merge'):
if opts.get('name'):
newpath = repo.join(opts.get('name'))
@@ -2748,48 +2524,37 @@ def push(ui, repo, patch=None, **opts):
if not newpath:
ui.warn(_("no saved queues found, please use -n\n"))
return 1
- mergeq = queue(ui, repo.path, newpath)
+ mergeq = queue(ui, repo.join(""), newpath)
ui.warn(_("merging with queue at: %s\n") % mergeq.path)
ret = q.push(repo, patch, force=opts.get('force'), list=opts.get('list'),
mergeq=mergeq, all=opts.get('all'), move=opts.get('move'),
- exact=opts.get('exact'), nobackup=opts.get('no_backup'),
- keepchanges=opts.get('keep_changes'))
+ exact=opts.get('exact'))
return ret
@command("^qpop",
[('a', 'all', None, _('pop all patches')),
('n', 'name', '',
_('queue name to pop (DEPRECATED)'), _('NAME')),
- ('', 'keep-changes', None,
- _('tolerate non-conflicting local changes')),
- ('f', 'force', None, _('forget any local changes to patched files')),
- ('', 'no-backup', None, _('do not save backup copies of files'))],
+ ('f', 'force', None, _('forget any local changes to patched files'))],
_('hg qpop [-a] [-f] [PATCH | INDEX]'))
def pop(ui, repo, patch=None, **opts):
"""pop the current patch off the stack
- Without argument, pops off the top of the patch stack. If given a
- patch name, keeps popping off patches until the named patch is at
- the top of the stack.
-
- By default, abort if the working directory contains uncommitted
- changes. With --keep-changes, abort only if the uncommitted files
- overlap with patched files. With -f/--force, backup and discard
- changes made to such files.
+ By default, pops off the top of the patch stack. If given a patch
+ name, keeps popping off patches until the named patch is at the
+ top of the stack.
Return 0 on success.
"""
- opts = fixkeepchangesopts(ui, opts)
localupdate = True
if opts.get('name'):
- q = queue(ui, repo.path, repo.join(opts.get('name')))
+ q = queue(ui, repo.join(""), repo.join(opts.get('name')))
ui.warn(_('using patch queue: %s\n') % q.path)
localupdate = False
else:
q = repo.mq
ret = q.pop(repo, patch, force=opts.get('force'), update=localupdate,
- all=opts.get('all'), nobackup=opts.get('no_backup'),
- keepchanges=opts.get('keep_changes'))
+ all=opts.get('all'))
q.savedirty()
return ret
@@ -2801,7 +2566,9 @@ def rename(ui, repo, patch, name=None, **opts):
With two arguments, renames PATCH1 to PATCH2.
Returns 0 on success."""
+
q = repo.mq
+
if not name:
name = patch
patch = None
@@ -2824,12 +2591,12 @@ def rename(ui, repo, patch, name=None, **opts):
guards = q.guard_re.findall(q.fullseries[i])
q.fullseries[i] = name + ''.join([' #' + g for g in guards])
q.parseseries()
- q.seriesdirty = True
+ q.seriesdirty = 1
info = q.isapplied(patch)
if info:
q.applied[info[0]] = statusentry(info[1], name)
- q.applieddirty = True
+ q.applieddirty = 1
destdir = os.path.dirname(absdest)
if not os.path.isdir(destdir):
@@ -2844,6 +2611,8 @@ def rename(ui, repo, patch, name=None, **opts):
r.dirstate.drop(patch)
r.dirstate.add(name)
else:
+ if r.dirstate[name] == 'r':
+ wctx.undelete([name])
wctx.copy(patch, name)
wctx.forget([patch])
finally:
@@ -2882,7 +2651,7 @@ def save(ui, repo, **opts):
ret = q.save(repo, msg=message)
if ret:
return ret
- q.savedirty() # save to .hg/patches before copying
+ q.savedirty()
if opts.get('copy'):
path = q.path
if opts.get('name'):
@@ -2899,28 +2668,22 @@ def save(ui, repo, **opts):
ui.warn(_("copy %s to %s\n") % (path, newpath))
util.copyfiles(path, newpath)
if opts.get('empty'):
- del q.applied[:]
- q.applieddirty = True
- q.savedirty()
+ try:
+ os.unlink(q.join(q.statuspath))
+ except:
+ pass
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 '
+ [('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')),
+ ('n', '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...'))
+ ('k', 'keep', None, _("do not modify working copy during strip"))],
+ _('hg strip [-k] [-f] [-n] REV...'))
def strip(ui, repo, *revs, **opts):
"""strip changesets and all their descendants from the repository
@@ -2944,10 +2707,6 @@ def strip(ui, repo, *revs, **opts):
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'
@@ -2957,38 +2716,11 @@ def strip(ui, repo, *revs, **opts):
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]
- repo._writebookmarks(mark)
- ui.write(_("bookmark '%s' deleted\n") % mark)
-
if not revs:
raise util.Abort(_('empty revision set'))
- descendants = set(cl.descendants(revs))
+ descendants = set(cl.descendants(*revs))
strippedrevs = revs.union(descendants)
roots = revs.difference(descendants)
@@ -3030,14 +2762,8 @@ def strip(ui, repo, *revs, **opts):
finally:
wlock.release()
- if opts.get('bookmark'):
- del marks[mark]
- repo._writebookmarks(marks)
- ui.write(_("bookmark '%s' deleted\n") % mark)
-
repo.mq.strip(repo, revs, backup=backup, update=update,
force=opts.get('force'))
-
return 0
@command("qselect",
@@ -3141,7 +2867,7 @@ def select(ui, repo, *args, **opts):
if i == 0:
q.pop(repo, all=True)
else:
- q.pop(repo, str(i - 1))
+ q.pop(repo, i - 1)
break
if popped:
try:
@@ -3183,22 +2909,12 @@ def finish(ui, repo, *revrange, **opts):
return 0
revs = scmutil.revrange(repo, revrange)
- if repo['.'].rev() in revs and repo[None].files():
- ui.warn(_('warning: uncommitted changes in the working directory\n'))
- # queue.finish may changes phases but leave the responsability to lock the
- # repo to the caller to avoid deadlock with wlock. This command code is
- # responsability for this locking.
- lock = repo.lock()
- try:
- q.finish(repo, revs)
- q.savedirty()
- finally:
- lock.release()
+ q.finish(repo, revs)
+ q.savedirty()
return 0
@command("qqueue",
[('l', 'list', False, _('list all available queues')),
- ('', 'active', False, _('print name of active queue')),
('c', 'create', False, _('create new queue')),
('', 'rename', False, _('rename active queue')),
('', 'delete', False, _('delete reference to queue')),
@@ -3213,8 +2929,7 @@ def qqueue(ui, repo, name=None, **opts):
Omitting a queue name or specifying -l/--list will show you the registered
queues - by default the "normal" patches queue is registered. The currently
- active queue will be marked with "(active)". Specifying --active will print
- only the name of the active queue.
+ active queue will be marked with "(active)".
To create a new queue, use -c/--create. The queue is automatically made
active, except in the case where there are applied patches from the
@@ -3226,7 +2941,9 @@ def qqueue(ui, repo, name=None, **opts):
Returns 0 on success.
'''
+
q = repo.mq
+
_defaultqueue = 'patches'
_allqueues = 'patches.queues'
_activequeue = 'patches.queue'
@@ -3305,11 +3022,8 @@ def qqueue(ui, repo, name=None, **opts):
fh.close()
util.rename(repo.join('patches.queues.new'), repo.join(_allqueues))
- if not name or opts.get('list') or opts.get('active'):
+ if not name or opts.get('list'):
current = _getcurrent()
- if opts.get('active'):
- ui.write('%s\n' % (current,))
- return
for queue in _getqueues():
ui.write('%s' % (queue,))
if queue == current and not ui.quiet:
@@ -3369,22 +3083,11 @@ def qqueue(ui, repo, name=None, **opts):
raise util.Abort(_('use --create to create a new queue'))
_setactive(name)
-def mqphasedefaults(repo, roots):
- """callback used to set mq changeset as secret when no phase data exists"""
- if repo.mq.applied:
- if repo.ui.configbool('mq', 'secret', False):
- mqphase = phases.secret
- else:
- mqphase = phases.draft
- qbase = repo[repo.mq.applied[0].node]
- roots[mqphase].add(qbase.node())
- return roots
-
def reposetup(ui, repo):
class mqrepo(repo.__class__):
@util.propertycache
def mq(self):
- return queue(self.ui, self.path)
+ return queue(self.ui, self.join(""))
def abortifwdirpatched(self, errmsg, force=False):
if self.mq.applied and not force:
@@ -3404,22 +3107,15 @@ def reposetup(ui, repo):
def checkpush(self, force, revs):
if self.mq.applied and not force:
- outapplied = [e.node for e in self.mq.applied]
+ haspatches = True
if revs:
- # Assume applied patches have no non-patch descendants and
- # are not on remote already. Filtering any changeset not
- # pushed.
- heads = set(revs)
- for node in reversed(outapplied):
- if node in heads:
- break
- else:
- outapplied.pop()
- # looking for pushed and shared changeset
- for node in outapplied:
- if repo[node].phase() < phases.secret:
- raise util.Abort(_('source has mq patches applied'))
- # no non-secret patches pushed
+ # Assume applied patches have no non-patch descendants
+ # and are not on remote already. If they appear in the
+ # set of resolved 'revs', bail out.
+ applied = set(e.node for e in self.mq.applied)
+ haspatches = bool([n for n in revs if n in applied])
+ if haspatches:
+ raise util.Abort(_('source has mq patches applied'))
super(mqrepo, self).checkpush(force, revs)
def _findtags(self):
@@ -3445,8 +3141,8 @@ def reposetup(ui, repo):
tags = result[0]
for patch in mqtags:
if patch[1] in tags:
- self.ui.warn(_('tag %s overrides mq patch of the same '
- 'name\n') % patch[1])
+ self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
+ % patch[1])
else:
tags[patch[1]] = patch[0]
@@ -3454,20 +3150,16 @@ def reposetup(ui, repo):
def _branchtags(self, partial, lrev):
q = self.mq
- cl = self.changelog
- qbase = None
if not q.applied:
- if getattr(self, '_committingpatch', False):
- # Committing a new patch, must be tip
- qbase = len(cl) - 1
- else:
- qbasenode = q.applied[0].node
- try:
- qbase = cl.rev(qbasenode)
- except error.LookupError:
- self.ui.warn(_('mq status file refers to unknown node %s\n')
- % short(qbasenode))
- if qbase is None:
+ return super(mqrepo, self)._branchtags(partial, lrev)
+
+ cl = self.changelog
+ qbasenode = q.applied[0].node
+ try:
+ qbase = cl.rev(qbasenode)
+ except error.LookupError:
+ self.ui.warn(_('mq status file refers to unknown node %s\n')
+ % short(qbasenode))
return super(mqrepo, self)._branchtags(partial, lrev)
start = lrev + 1
@@ -3490,10 +3182,8 @@ def reposetup(ui, repo):
if repo.local():
repo.__class__ = mqrepo
- repo._phasedefaults.append(mqphasedefaults)
-
def mqimport(orig, ui, repo, *args, **kwargs):
- if (util.safehasattr(repo, 'abortifwdirpatched')
+ if (hasattr(repo, 'abortifwdirpatched')
and not kwargs.get('no_commit', False)):
repo.abortifwdirpatched(_('cannot import over an applied patch'),
kwargs.get('force'))
@@ -3556,12 +3246,13 @@ def revsetmq(repo, subset, x):
applied = set([repo[r.node].rev() for r in repo.mq.applied])
return [r for r in subset if r in applied]
+def extsetup(ui):
+ revset.symbols['mq'] = revsetmq
+
# tell hggettext to extract docstrings from these functions:
i18nfunctions = [revsetmq]
-def extsetup(ui):
- # Ensure mq wrappers are called first, regardless of extension load order by
- # NOT wrapping in uisetup() and instead deferring to init stage two here.
+def uisetup(ui):
mqopt = [('', 'mq', None, _("operate on patch repository"))]
extensions.wrapcommand(commands.table, 'import', mqimport)
@@ -3586,7 +3277,6 @@ def extsetup(ui):
if extmodule.__file__ != __file__:
dotable(getattr(extmodule, 'cmdtable', {}))
- revset.symbols['mq'] = revsetmq
colortable = {'qguard.negative': 'red',
'qguard.positive': 'yellow',