--- a/doc/hgrc.5.txt Wed Dec 19 17:02:31 2007 -0500
+++ b/doc/hgrc.5.txt Wed Dec 19 19:21:30 2007 -0800
@@ -281,7 +281,7 @@
commit to proceed. Non-zero status will cause the commit to fail.
Parent changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
preoutgoing;;
- Run before computing changes to send from the local repository to
+ Run before collecting changes to send from the local repository to
another. Non-zero status will cause failure. This lets you
prevent pull over http or ssh. Also prevents against local pull,
push (outbound) or bundle commands, but not effective, since you
--- a/hgext/mq.py Wed Dec 19 17:02:31 2007 -0500
+++ b/hgext/mq.py Wed Dec 19 19:21:30 2007 -0800
@@ -603,6 +603,7 @@
def new(self, repo, patch, *pats, **opts):
msg = opts.get('msg')
force = opts.get('force')
+ user = opts.get('user')
if os.path.exists(self.join(patch)):
raise util.Abort(_('patch "%s" already exists') % patch)
if opts.get('include') or opts.get('exclude') or pats:
@@ -617,7 +618,7 @@
try:
insert = self.full_series_end()
commitmsg = msg and msg or ("[mq]: %s" % patch)
- n = repo.commit(commitfiles, commitmsg, match=match, force=True)
+ n = repo.commit(commitfiles, commitmsg, user, match=match, force=True)
if n == None:
raise util.Abort(_("repo commit failed"))
self.full_series[insert:insert] = [patch]
@@ -626,6 +627,8 @@
self.series_dirty = 1
self.applied_dirty = 1
p = self.opener(patch, "w")
+ if user:
+ p.write("From: " + user + "\n\n")
if msg:
msg = msg + "\n"
p.write(msg)
@@ -945,6 +948,22 @@
while message[mi] != comments[ci]:
ci += 1
del comments[ci]
+
+ newuser = opts.get('user')
+ if newuser:
+ # Update all references to a user in the patch header.
+ # If none found, add "From: " header.
+ needfrom = True
+ for prefix in ['# User ', 'From: ']:
+ for i in xrange(len(comments)):
+ if comments[i].startswith(prefix):
+ comments[i] = prefix + newuser
+ needfrom = False
+ break
+ if needfrom:
+ comments = ['From: ' + newuser, ''] + comments
+ user = newuser
+
if msg:
comments.append(msg)
@@ -1070,9 +1089,12 @@
else:
message = msg
+ if not user:
+ user = changes[1]
+
self.strip(repo, top, update=False,
backup='strip')
- n = repo.commit(filelist, message, changes[1], match=matchfn,
+ n = repo.commit(filelist, message, user, match=matchfn,
force=1)
self.applied[-1] = statusentry(revlog.hex(n), patchfn)
self.applied_dirty = 1
@@ -1605,6 +1627,12 @@
return q.qseries(repo, start=l-2, length=1, status='A',
summary=opts.get('summary'))
+def setupheaderopts(ui, opts):
+ def do(opt,val):
+ if not opts[opt] and opts['current' + opt]:
+ opts[opt] = val
+ do('user', ui.username())
+
def new(ui, repo, patch, *args, **opts):
"""create a new patch
@@ -1623,6 +1651,7 @@
if opts['edit']:
message = ui.edit(message, ui.username())
opts['msg'] = message
+ setupheaderopts(ui, opts)
q.new(repo, patch, *args, **opts)
q.save_dirty()
return 0
@@ -1648,6 +1677,7 @@
patch = q.applied[-1].name
(message, comment, user, date, hasdiff) = q.readheaders(patch)
message = ui.edit('\n'.join(message), user or ui.username())
+ setupheaderopts(ui, opts)
ret = q.refresh(repo, pats, msg=message, **opts)
q.save_dirty()
return ret
@@ -2138,6 +2168,10 @@
seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
+headeropts = [
+ ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
+ ('u', 'user', '', _('add "From: <given user>" to patch'))]
+
cmdtable = {
"qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')),
"qclone":
@@ -2196,7 +2230,7 @@
[('e', 'edit', None, _('edit commit message')),
('f', 'force', None, _('import uncommitted changes into patch')),
('g', 'git', None, _('use git extended diff format')),
- ] + commands.walkopts + commands.commitopts,
+ ] + commands.walkopts + commands.commitopts + headeropts,
_('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
"qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
"qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
@@ -2219,7 +2253,7 @@
[('e', 'edit', None, _('edit commit message')),
('g', 'git', None, _('use git extended diff format')),
('s', 'short', None, _('refresh only files already in the patch')),
- ] + commands.walkopts + commands.commitopts,
+ ] + commands.walkopts + commands.commitopts + headeropts,
_('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
'qrename|qmv':
(rename, [], _('hg qrename PATCH1 [PATCH2]')),
--- a/mercurial/commands.py Wed Dec 19 17:02:31 2007 -0500
+++ b/mercurial/commands.py Wed Dec 19 19:21:30 2007 -0800
@@ -2029,6 +2029,7 @@
forget.append(abs)
continue
reason = _('has been marked for add (use -f to force removal)')
+ exact = 1 # force the message
elif abs not in repo.dirstate:
reason = _('is not managed')
elif opts['after'] and not exact and abs not in deleted:
--- a/mercurial/demandimport.py Wed Dec 19 17:02:31 2007 -0500
+++ b/mercurial/demandimport.py Wed Dec 19 19:21:30 2007 -0800
@@ -67,7 +67,7 @@
return "<proxied module '%s'>" % self._data[0]
return "<unloaded module '%s'>" % self._data[0]
def __call__(self, *args, **kwargs):
- raise TypeError("'unloaded module' object is not callable")
+ raise TypeError("%s object is not callable" % repr(self))
def __getattribute__(self, attr):
if attr in ('_data', '_extend', '_load', '_module'):
return object.__getattribute__(self, attr)
--- a/mercurial/dispatch.py Wed Dec 19 17:02:31 2007 -0500
+++ b/mercurial/dispatch.py Wed Dec 19 19:21:30 2007 -0800
@@ -133,6 +133,8 @@
except util.Abort, inst:
ui.warn(_("abort: %s\n") % inst)
+ except MemoryError:
+ ui.warn(_("abort: out of memory\n"))
except SystemExit, inst:
# Commands shouldn't sys.exit directly, but give a return code.
# Just in case catch this and and pass exit code to caller.
--- a/mercurial/fancyopts.py Wed Dec 19 17:02:31 2007 -0500
+++ b/mercurial/fancyopts.py Wed Dec 19 19:21:30 2007 -0800
@@ -1,35 +1,74 @@
import getopt
def fancyopts(args, options, state):
- long = []
- short = ''
- map = {}
- dt = {}
+ """
+ read args, parse options, and store options in state
+
+ each option is a tuple of:
+
+ short option or ''
+ long option
+ default value
+ description
+
+ option types include:
+
+ boolean or none - option sets variable in state to true
+ string - parameter string is stored in state
+ list - parameter string is added to a list
+ integer - parameter strings is stored as int
+ function - call function with parameter
- for s, l, d, c in options:
- pl = l.replace('-', '_')
- map['-'+s] = map['--'+l] = pl
- if isinstance(d, list):
- state[pl] = d[:]
+ non-option args are returned
+ """
+ namelist = []
+ shortlist = ''
+ argmap = {}
+ defmap = {}
+
+ for short, name, default, comment in options:
+ # convert opts to getopt format
+ oname = name
+ name = name.replace('-', '_')
+
+ argmap['-' + short] = argmap['--' + oname] = name
+ defmap[name] = default
+
+ # copy defaults to state
+ if isinstance(default, list):
+ state[name] = default[:]
+ elif callable(default):
+ print "whoa", name, default
+ state[name] = None
else:
- state[pl] = d
- dt[pl] = type(d)
- if (d is not None and d is not True and d is not False and
- not callable(d)):
- if s: s += ':'
- if l: l += '='
- if s: short = short + s
- if l: long.append(l)
+ state[name] = default
- opts, args = getopt.getopt(args, short, long)
+ # does it take a parameter?
+ if not (default is None or default is True or default is False):
+ if short: short += ':'
+ if oname: oname += '='
+ if short:
+ shortlist += short
+ if name:
+ namelist.append(oname)
+
+ # parse arguments
+ opts, args = getopt.getopt(args, shortlist, namelist)
- for opt, arg in opts:
- if dt[map[opt]] is type(fancyopts): state[map[opt]](state, map[opt], arg)
- elif dt[map[opt]] is type(1): state[map[opt]] = int(arg)
- elif dt[map[opt]] is type(''): state[map[opt]] = arg
- elif dt[map[opt]] is type([]): state[map[opt]].append(arg)
- elif dt[map[opt]] is type(None): state[map[opt]] = True
- elif dt[map[opt]] is type(False): state[map[opt]] = True
+ # transfer result to state
+ for opt, val in opts:
+ name = argmap[opt]
+ t = type(defmap[name])
+ if t is type(fancyopts):
+ state[name] = defmap[name](val)
+ elif t is type(1):
+ state[name] = int(val)
+ elif t is type(''):
+ state[name] = val
+ elif t is type([]):
+ state[name].append(val)
+ elif t is type(None) or t is type(False):
+ state[name] = True
+ # return unparsed args
return args
-
--- a/mercurial/hg.py Wed Dec 19 17:02:31 2007 -0500
+++ b/mercurial/hg.py Wed Dec 19 19:21:30 2007 -0800
@@ -280,13 +280,13 @@
# len(pl)==1, otherwise _merge.update() would have raised util.Abort:
repo.ui.status(_(" hg update %s\n hg update %s\n")
% (pl[0].rev(), repo.changectx(node).rev()))
- return stats[3]
+ return stats[3] > 0
def clean(repo, node, show_stats=True):
"""forcibly switch the working directory to node, clobbering changes"""
stats = _merge.update(repo, node, False, True, None)
if show_stats: _showstats(repo, stats)
- return stats[3]
+ return stats[3] > 0
def merge(repo, node, force=None, remind=True):
"""branch merge with node, resolving changes"""
@@ -301,11 +301,11 @@
% (pl[0].rev(), pl[1].rev()))
elif remind:
repo.ui.status(_("(branch merge, don't forget to commit)\n"))
- return stats[3]
+ return stats[3] > 0
def revert(repo, node, choose):
"""revert changes to revision in node without updating dirstate"""
- return _merge.update(repo, node, False, True, choose)[3]
+ return _merge.update(repo, node, False, True, choose)[3] > 0
def verify(repo):
"""verify the consistency of a repository"""
--- a/mercurial/ignore.py Wed Dec 19 17:02:31 2007 -0500
+++ b/mercurial/ignore.py Wed Dec 19 19:21:30 2007 -0800
@@ -6,18 +6,21 @@
# of the GNU General Public License, incorporated herein by reference.
from i18n import _
-import util
+import util, re
+
+_commentre = None
def _parselines(fp):
for line in fp:
- if not line.endswith('\n'):
- line += '\n'
- escape = False
- for i in xrange(len(line)):
- if escape: escape = False
- elif line[i] == '\\': escape = True
- elif line[i] == '#': break
- line = line[:i].rstrip()
+ if "#" in line:
+ global _commentre
+ if not _commentre:
+ _commentre = re.compile(r'((^|[^\\])(\\\\)*)#.*')
+ # remove comments prefixed by an even number of escapes
+ line = _commentre.sub(r'\1', line)
+ # fixup properly escaped comments that survived the above
+ line = line.replace("\\#", "#")
+ line = line.rstrip()
if line:
yield line
--- a/mercurial/localrepo.py Wed Dec 19 17:02:31 2007 -0500
+++ b/mercurial/localrepo.py Wed Dec 19 19:21:30 2007 -0800
@@ -661,6 +661,7 @@
match=util.always, force=False, force_editor=False,
p1=None, p2=None, extra={}, empty_ok=False):
wlock = lock = tr = None
+ valid = 0 # don't save the dirstate if this isn't set
try:
commit = []
remove = []
@@ -747,6 +748,9 @@
if old_exec != new_exec or old_link != new_link:
changed.append(f)
m1.set(f, new_exec, new_link)
+ if use_dirstate:
+ self.dirstate.normal(f)
+
except (OSError, IOError):
if use_dirstate:
self.ui.warn(_("trouble committing %s!\n") % f)
@@ -817,14 +821,15 @@
if use_dirstate or update_dirstate:
self.dirstate.setparents(n)
if use_dirstate:
- for f in new:
- self.dirstate.normal(f)
for f in removed:
self.dirstate.forget(f)
+ valid = 1 # our dirstate updates are complete
self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2)
return n
finally:
+ if not valid: # don't save our updated dirstate
+ self.dirstate.invalidate()
del tr, lock, wlock
def walk(self, node=None, files=[], match=util.always, badmatch=None):
--- a/mercurial/patch.py Wed Dec 19 17:02:31 2007 -0500
+++ b/mercurial/patch.py Wed Dec 19 19:21:30 2007 -0800
@@ -302,24 +302,26 @@
contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
class patchfile:
- def __init__(self, ui, fname):
+ def __init__(self, ui, fname, missing=False):
self.fname = fname
self.ui = ui
- try:
- fp = file(fname, 'rb')
- self.lines = fp.readlines()
- self.exists = True
- except IOError:
+ self.lines = []
+ self.exists = False
+ self.missing = missing
+ if not missing:
+ try:
+ fp = file(fname, 'rb')
+ self.lines = fp.readlines()
+ self.exists = True
+ except IOError:
+ pass
+ else:
+ self.ui.warn(_("unable to find '%s' for patching\n") % self.fname)
+
+ if not self.exists:
dirname = os.path.dirname(fname)
if dirname and not os.path.isdir(dirname):
- dirs = dirname.split(os.path.sep)
- d = ""
- for x in dirs:
- d = os.path.join(d, x)
- if not os.path.isdir(d):
- os.mkdir(d)
- self.lines = []
- self.exists = False
+ os.makedirs(dirname)
self.hash = {}
self.dirty = 0
@@ -427,6 +429,10 @@
if reverse:
h.reverse()
+ if self.missing:
+ self.rej.append(h)
+ return -1
+
if self.exists and h.createfile():
self.ui.warn(_("file %s already exists\n") % self.fname)
self.rej.append(h)
@@ -796,31 +802,32 @@
nulla = afile_orig == "/dev/null"
nullb = bfile_orig == "/dev/null"
afile = pathstrip(afile_orig, strip)
- gooda = os.path.exists(afile) and not nulla
+ gooda = not nulla and os.path.exists(afile)
bfile = pathstrip(bfile_orig, strip)
if afile == bfile:
goodb = gooda
else:
- goodb = os.path.exists(bfile) and not nullb
+ goodb = not nullb and os.path.exists(bfile)
createfunc = hunk.createfile
if reverse:
createfunc = hunk.rmfile
- if not goodb and not gooda and not createfunc():
- raise PatchError(_("unable to find %s or %s for patching") %
- (afile, bfile))
- if gooda and goodb:
- fname = bfile
- if afile in bfile:
+ missing = not goodb and not gooda and not createfunc()
+ fname = None
+ if not missing:
+ if gooda and goodb:
+ fname = (afile in bfile) and afile or bfile
+ elif gooda:
fname = afile
- elif gooda:
- fname = afile
- elif not nullb:
- fname = bfile
- if afile in bfile:
+
+ if not fname:
+ if not nullb:
+ fname = (afile in bfile) and afile or bfile
+ elif not nulla:
fname = afile
- elif not nulla:
- fname = afile
- return fname
+ else:
+ raise PatchError(_("undefined source and destination files"))
+
+ return fname, missing
class linereader:
# simple class to allow pushing lines back into the input stream
@@ -838,14 +845,16 @@
return l
return self.fp.readline()
-def applydiff(ui, fp, changed, strip=1, sourcefile=None, reverse=False,
- rejmerge=None, updatedir=None):
- """reads a patch from fp and tries to apply it. The dict 'changed' is
- filled in with all of the filenames changed by the patch. Returns 0
- for a clean patch, -1 if any rejects were found and 1 if there was
- any fuzz."""
+def iterhunks(ui, fp, sourcefile=None):
+ """Read a patch and yield the following events:
+ - ("file", afile, bfile, firsthunk): select a new target file.
+ - ("hunk", hunk): a new hunk is ready to be applied, follows a
+ "file" event.
+ - ("git", gitchanges): current diff is in git format, gitchanges
+ maps filenames to gitpatch records. Unique event.
+ """
- def scangitpatch(fp, firstline, cwd=None):
+ def scangitpatch(fp, firstline):
'''git patches can modify a file, then copy that file to
a new file, but expect the source to be the unmodified form.
So we scan the patch looking for that case so we can do
@@ -858,46 +867,28 @@
fp = cStringIO.StringIO(fp.read())
(dopatch, gitpatches) = readgitpatch(fp, firstline)
- for gp in gitpatches:
- if gp.op in ('COPY', 'RENAME'):
- copyfile(gp.oldpath, gp.path, basedir=cwd)
-
fp.seek(pos)
return fp, dopatch, gitpatches
+ changed = {}
current_hunk = None
- current_file = None
afile = ""
bfile = ""
state = None
hunknum = 0
- rejects = 0
+ emitfile = False
git = False
gitre = re.compile('diff --git (a/.*) (b/.*)')
# our states
BFILE = 1
- err = 0
context = None
lr = linereader(fp)
dopatch = True
gitworkdone = False
- def getpatchfile(afile, bfile, hunk):
- try:
- if sourcefile:
- targetfile = patchfile(ui, sourcefile)
- else:
- targetfile = selectfile(afile, bfile, hunk,
- strip, reverse)
- targetfile = patchfile(ui, targetfile)
- return targetfile
- except PatchError, err:
- ui.warn(str(err) + '\n')
- return None
-
while True:
newfile = False
x = lr.readline()
@@ -906,11 +897,7 @@
if current_hunk:
if x.startswith('\ '):
current_hunk.fix_newline()
- ret = current_file.apply(current_hunk, reverse)
- if ret >= 0:
- changed.setdefault(current_file.fname, (None, None))
- if ret > 0:
- err = 1
+ yield 'hunk', current_hunk
current_hunk = None
gitworkdone = False
if ((sourcefile or state == BFILE) and ((not context and x[0] == '@') or
@@ -924,21 +911,15 @@
current_hunk = None
continue
hunknum += 1
- if not current_file:
- current_file = getpatchfile(afile, bfile, current_hunk)
- if not current_file:
- current_file, current_hunk = None, None
- rejects += 1
- continue
+ if emitfile:
+ emitfile = False
+ yield 'file', (afile, bfile, current_hunk)
elif state == BFILE and x.startswith('GIT binary patch'):
current_hunk = binhunk(changed[bfile[2:]][1])
hunknum += 1
- if not current_file:
- current_file = getpatchfile(afile, bfile, current_hunk)
- if not current_file:
- current_file, current_hunk = None, None
- rejects += 1
- continue
+ if emitfile:
+ emitfile = False
+ yield 'file', (afile, bfile, current_hunk)
current_hunk.extract(fp)
elif x.startswith('diff --git'):
# check for git diff, scanning the whole patch file if needed
@@ -948,6 +929,7 @@
if not git:
git = True
fp, dopatch, gitpatches = scangitpatch(fp, x)
+ yield 'git', gitpatches
for gp in gitpatches:
changed[gp.path] = (gp.op, gp)
# else error?
@@ -984,36 +966,79 @@
bfile = parsefilename(l2)
if newfile:
- if current_file:
- current_file.close()
- if rejmerge:
- rejmerge(current_file)
- rejects += len(current_file.rej)
+ emitfile = True
state = BFILE
- current_file = None
hunknum = 0
if current_hunk:
if current_hunk.complete():
+ yield 'hunk', current_hunk
+ else:
+ raise PatchError(_("malformed patch %s %s") % (afile,
+ current_hunk.desc))
+
+ if hunknum == 0 and dopatch and not gitworkdone:
+ raise NoHunks
+
+def applydiff(ui, fp, changed, strip=1, sourcefile=None, reverse=False,
+ rejmerge=None, updatedir=None):
+ """reads a patch from fp and tries to apply it. The dict 'changed' is
+ filled in with all of the filenames changed by the patch. Returns 0
+ for a clean patch, -1 if any rejects were found and 1 if there was
+ any fuzz."""
+
+ rejects = 0
+ err = 0
+ current_file = None
+ gitpatches = None
+
+ def closefile():
+ if not current_file:
+ return 0
+ current_file.close()
+ if rejmerge:
+ rejmerge(current_file)
+ return len(current_file.rej)
+
+ for state, values in iterhunks(ui, fp, sourcefile):
+ if state == 'hunk':
+ if not current_file:
+ continue
+ current_hunk = values
ret = current_file.apply(current_hunk, reverse)
if ret >= 0:
changed.setdefault(current_file.fname, (None, None))
if ret > 0:
err = 1
+ elif state == 'file':
+ rejects += closefile()
+ afile, bfile, first_hunk = values
+ try:
+ if sourcefile:
+ current_file = patchfile(ui, sourcefile)
+ else:
+ current_file, missing = selectfile(afile, bfile, first_hunk,
+ strip, reverse)
+ current_file = patchfile(ui, current_file, missing)
+ except PatchError, err:
+ ui.warn(str(err) + '\n')
+ current_file, current_hunk = None, None
+ rejects += 1
+ continue
+ elif state == 'git':
+ gitpatches = values
+ for gp in gitpatches:
+ if gp.op in ('COPY', 'RENAME'):
+ copyfile(gp.oldpath, gp.path)
+ changed[gp.path] = (gp.op, gp)
else:
- fname = current_file and current_file.fname or None
- raise PatchError(_("malformed patch %s %s") % (fname,
- current_hunk.desc))
- if current_file:
- current_file.close()
- if rejmerge:
- rejmerge(current_file)
- rejects += len(current_file.rej)
- if updatedir and git:
+ raise util.Abort(_('unsupported parser state: %s') % state)
+
+ rejects += closefile()
+
+ if updatedir and gitpatches:
updatedir(gitpatches)
if rejects:
return -1
- if hunknum == 0 and dopatch and not gitworkdone:
- raise NoHunks
return err
def diffopts(ui, opts={}, untrusted=False):
--- a/mercurial/util.py Wed Dec 19 17:02:31 2007 -0500
+++ b/mercurial/util.py Wed Dec 19 19:21:30 2007 -0800
@@ -919,7 +919,15 @@
def write(self, s):
try:
- return self.fp.write(s)
+ # This is workaround for "Not enough space" error on
+ # writing large size of data to console.
+ limit = 16000
+ l = len(s)
+ start = 0
+ while start < l:
+ end = start + limit
+ self.fp.write(s[start:end])
+ start = end
except IOError, inst:
if inst.errno != 0: raise
self.close()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-header-from Wed Dec 19 19:21:30 2007 -0800
@@ -0,0 +1,108 @@
+#!/bin/sh
+
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
+echo "[diff]" >> $HGRCPATH
+echo "nodates=true" >> $HGRCPATH
+
+
+catlog() {
+ cat .hg/patches/$1.patch | sed -e "s/^diff \-r [0-9a-f]* /diff -r ... /"
+ hg log --template "{rev}: {desc} - {author}\n"
+}
+
+
+echo ==== init
+hg init a
+cd a
+hg qinit
+
+
+echo ==== qnew -U
+hg qnew -U 1.patch
+catlog 1
+
+echo ==== qref
+echo "1" >1
+hg add
+hg qref
+catlog 1
+
+echo ==== qref -u
+hg qref -u mary
+catlog 1
+
+echo ==== qnew
+hg qnew 2.patch
+echo "2" >2
+hg add
+hg qref
+catlog 2
+
+echo ==== qref -u
+hg qref -u jane
+catlog 2
+
+
+echo ==== qnew -U -m
+hg qnew -U -m "Three" 3.patch
+catlog 3
+
+echo ==== qref
+echo "3" >3
+hg add
+hg qref
+catlog 3
+
+echo ==== qref -m
+hg qref -m "Drei"
+catlog 3
+
+echo ==== qref -u
+hg qref -u mary
+catlog 3
+
+echo ==== qref -u -m
+hg qref -u maria -m "Three (again)"
+catlog 3
+
+echo ==== qnew -m
+hg qnew -m "Four" 4.patch
+echo "4" >4
+hg add
+hg qref
+catlog 4
+
+echo ==== qref -u
+hg qref -u jane
+catlog 4
+
+
+echo ==== qnew with HG header
+hg qnew 5.patch
+hg qpop
+echo "# HG changeset patch" >>.hg/patches/5.patch
+echo "# User johndoe" >>.hg/patches/5.patch
+# Drop patch specific error line
+hg qpush 2>&1 | grep -v garbage
+catlog 5
+
+echo ==== hg qref
+echo "5" >5
+hg add
+hg qref
+catlog 5
+
+echo ==== hg qref -U
+hg qref -U
+catlog 5
+
+echo ==== hg qref -u
+hg qref -u johndeere
+catlog 5
+
+
+echo ==== "qpop -a / qpush -a"
+hg qpop -a
+hg qpush -a
+hg log --template "{rev}: {desc} - {author}\n"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-header-from.out Wed Dec 19 19:21:30 2007 -0800
@@ -0,0 +1,200 @@
+==== init
+==== qnew -U
+From: test
+
+0: [mq]: 1.patch - test
+==== qref
+adding 1
+From: test
+
+diff -r ... 1
+--- /dev/null
++++ b/1
+@@ -0,0 +1,1 @@
++1
+0: [mq]: 1.patch - test
+==== qref -u
+From: mary
+
+diff -r ... 1
+--- /dev/null
++++ b/1
+@@ -0,0 +1,1 @@
++1
+0: [mq]: 1.patch - mary
+==== qnew
+adding 2
+diff -r ... 2
+--- /dev/null
++++ b/2
+@@ -0,0 +1,1 @@
++2
+1: [mq]: 2.patch - test
+0: [mq]: 1.patch - mary
+==== qref -u
+From: jane
+
+
+diff -r ... 2
+--- /dev/null
++++ b/2
+@@ -0,0 +1,1 @@
++2
+1: [mq]: 2.patch - jane
+0: [mq]: 1.patch - mary
+==== qnew -U -m
+From: test
+
+Three
+2: Three - test
+1: [mq]: 2.patch - jane
+0: [mq]: 1.patch - mary
+==== qref
+adding 3
+From: test
+
+Three
+
+diff -r ... 3
+--- /dev/null
++++ b/3
+@@ -0,0 +1,1 @@
++3
+2: Three - test
+1: [mq]: 2.patch - jane
+0: [mq]: 1.patch - mary
+==== qref -m
+From: test
+
+Drei
+
+diff -r ... 3
+--- /dev/null
++++ b/3
+@@ -0,0 +1,1 @@
++3
+2: Drei - test
+1: [mq]: 2.patch - jane
+0: [mq]: 1.patch - mary
+==== qref -u
+From: mary
+
+Drei
+
+diff -r ... 3
+--- /dev/null
++++ b/3
+@@ -0,0 +1,1 @@
++3
+2: Drei - mary
+1: [mq]: 2.patch - jane
+0: [mq]: 1.patch - mary
+==== qref -u -m
+From: maria
+
+Three (again)
+
+diff -r ... 3
+--- /dev/null
++++ b/3
+@@ -0,0 +1,1 @@
++3
+2: Three (again) - maria
+1: [mq]: 2.patch - jane
+0: [mq]: 1.patch - mary
+==== qnew -m
+adding 4
+Four
+
+diff -r ... 4
+--- /dev/null
++++ b/4
+@@ -0,0 +1,1 @@
++4
+3: Four - test
+2: Three (again) - maria
+1: [mq]: 2.patch - jane
+0: [mq]: 1.patch - mary
+==== qref -u
+From: jane
+
+Four
+
+diff -r ... 4
+--- /dev/null
++++ b/4
+@@ -0,0 +1,1 @@
++4
+3: Four - jane
+2: Three (again) - maria
+1: [mq]: 2.patch - jane
+0: [mq]: 1.patch - mary
+==== qnew with HG header
+Now at: 4.patch
+applying 5.patch
+patch failed, unable to continue (try -v)
+patch 5.patch is empty
+Now at: 5.patch
+# HG changeset patch
+# User johndoe
+4: imported patch 5.patch - johndoe
+3: Four - jane
+2: Three (again) - maria
+1: [mq]: 2.patch - jane
+0: [mq]: 1.patch - mary
+==== hg qref
+adding 5
+# HG changeset patch
+# User johndoe
+
+diff -r ... 5
+--- /dev/null
++++ b/5
+@@ -0,0 +1,1 @@
++5
+4: [mq]: 5.patch - johndoe
+3: Four - jane
+2: Three (again) - maria
+1: [mq]: 2.patch - jane
+0: [mq]: 1.patch - mary
+==== hg qref -U
+# HG changeset patch
+# User test
+
+diff -r ... 5
+--- /dev/null
++++ b/5
+@@ -0,0 +1,1 @@
++5
+4: [mq]: 5.patch - test
+3: Four - jane
+2: Three (again) - maria
+1: [mq]: 2.patch - jane
+0: [mq]: 1.patch - mary
+==== hg qref -u
+# HG changeset patch
+# User johndeere
+
+diff -r ... 5
+--- /dev/null
++++ b/5
+@@ -0,0 +1,1 @@
++5
+4: [mq]: 5.patch - johndeere
+3: Four - jane
+2: Three (again) - maria
+1: [mq]: 2.patch - jane
+0: [mq]: 1.patch - mary
+==== qpop -a / qpush -a
+Patch queue now empty
+applying 1.patch
+applying 2.patch
+applying 3.patch
+applying 4.patch
+applying 5.patch
+Now at: 5.patch
+4: imported patch 5.patch - johndeere
+3: Four - jane
+2: Three (again) - maria
+1: imported patch 2.patch - jane
+0: imported patch 1.patch - mary
--- a/tests/test-mq-missingfiles Wed Dec 19 17:02:31 2007 -0500
+++ b/tests/test-mq-missingfiles Wed Dec 19 19:21:30 2007 -0800
@@ -41,6 +41,8 @@
echo % display added files
cat a
cat c
+echo % display rejections
+cat b.rej
cd ..
@@ -65,5 +67,7 @@
echo % display added files
cat a
cat c
+echo % display rejections
+cat b.rej
cd ..
--- a/tests/test-mq-missingfiles.out Wed Dec 19 17:02:31 2007 -0500
+++ b/tests/test-mq-missingfiles.out Wed Dec 19 19:21:30 2007 -0800
@@ -2,24 +2,48 @@
Patch queue now empty
% push patch with missing target
applying changeb
-unable to find b or b for patching
-unable to find b or b for patching
+unable to find 'b' for patching
+2 out of 2 hunks FAILED -- saving rejects to file b.rej
patch failed, unable to continue (try -v)
patch failed, rejects left in working dir
Errors during apply, please fix and refresh changeb
% display added files
a
c
+% display rejections
+--- b
++++ b
+@@ -1,3 +1,5 @@ a
++b
++b
+ a
+ a
+ a
+@@ -8,3 +10,5 @@ a
+ a
+ a
+ a
++c
++c
adding b
Patch queue now empty
% push git patch with missing target
applying changeb
-unable to find b or b for patching
+unable to find 'b' for patching
+1 out of 1 hunk FAILED -- saving rejects to file b.rej
patch failed, unable to continue (try -v)
b: No such file or directory
b not tracked!
patch failed, rejects left in working dir
Errors during apply, please fix and refresh changeb
+? b.rej
% display added files
a
c
+% display rejections
+--- b
++++ b
+GIT binary patch
+literal 2
+Jc${No0000400IC2
+