--- a/contrib/convert-repo Sun May 27 14:40:14 2007 -0700
+++ b/contrib/convert-repo Sun May 27 14:43:29 2007 -0700
@@ -30,7 +30,7 @@
class Abort(Exception): pass
class NoRepo(Exception): pass
-class commit:
+class commit(object):
def __init__(self, **parts):
for x in "author date desc parents".split():
if not x in parts:
@@ -56,8 +56,89 @@
except:
return s.decode("utf-8", "replace").encode("utf-8")
+class converter_source(object):
+ """Conversion source interface"""
+
+ def __init__(self, path):
+ """Initialize conversion source (or raise NoRepo("message")
+ exception if path is not a valid repository)"""
+ raise NotImplementedError()
+
+ def getheads(self):
+ """Return a list of this repository's heads"""
+ raise NotImplementedError()
+
+ def getfile(self, name, rev):
+ """Return file contents as a string"""
+ raise NotImplementedError()
+
+ def getmode(self, name, rev):
+ """Return file mode, eg. '', 'x', or 'l'"""
+ raise NotImplementedError()
+
+ def getchanges(self, version):
+ """Return sorted list of (filename, id) tuples for all files changed in rev.
+
+ id just tells us which revision to return in getfile(), e.g. in
+ git it's an object hash."""
+ raise NotImplementedError()
+
+ def getcommit(self, version):
+ """Return the commit object for version"""
+ raise NotImplementedError()
+
+ def gettags(self):
+ """Return the tags as a dictionary of name: revision"""
+ raise NotImplementedError()
+
+class converter_sink(object):
+ """Conversion sink (target) interface"""
+
+ def __init__(self, path):
+ """Initialize conversion sink (or raise NoRepo("message")
+ exception if path is not a valid repository)"""
+ raise NotImplementedError()
+
+ def getheads(self):
+ """Return a list of this repository's heads"""
+ raise NotImplementedError()
+
+ def mapfile(self):
+ """Path to a file that will contain lines
+ source_rev_id sink_rev_id
+ mapping equivalent revision identifiers for each system."""
+ raise NotImplementedError()
+
+ def putfile(self, f, e, data):
+ """Put file for next putcommit().
+ f: path to file
+ e: '', 'x', or 'l' (regular file, executable, or symlink)
+ data: file contents"""
+ raise NotImplementedError()
+
+ def delfile(self, f):
+ """Delete file for next putcommit().
+ f: path to file"""
+ raise NotImplementedError()
+
+ def putcommit(self, files, parents, commit):
+ """Create a revision with all changed files listed in 'files'
+ and having listed parents. 'commit' is a commit object containing
+ at a minimum the author, date, and message for this changeset.
+ Called after putfile() and delfile() calls. Note that the sink
+ repository is not told to update itself to a particular revision
+ (or even what that revision would be) before it receives the
+ file data."""
+ raise NotImplementedError()
+
+ def puttags(self, tags):
+ """Put tags into sink.
+ tags: {tagname: sink_rev_id, ...}"""
+ raise NotImplementedError()
+
+
# CVS conversion code inspired by hg-cvs-import and git-cvsimport
-class convert_cvs:
+class convert_cvs(converter_source):
def __init__(self, path):
self.path = path
cvs = os.path.join(path, "CVS")
@@ -288,7 +369,7 @@
def gettags(self):
return self.tags
-class convert_git:
+class convert_git(converter_source):
def __init__(self, path):
if os.path.isdir(path + "/.git"):
path += "/.git"
@@ -374,7 +455,7 @@
return tags
-class convert_mercurial:
+class convert_mercurial(converter_sink):
def __init__(self, path):
self.path = path
u = ui.ui()
@@ -471,7 +552,7 @@
pass
abort("%s: unknown repository type\n" % path)
-class convert:
+class convert(object):
def __init__(self, source, dest, mapfile, opts):
self.source = source
--- a/contrib/zsh_completion Sun May 27 14:40:14 2007 -0700
+++ b/contrib/zsh_completion Sun May 27 14:43:29 2007 -0700
@@ -380,7 +380,7 @@
_arguments -s -w : $_hg_global_opts $_hg_pat_opts \
'(--addremove -A)'{-A,--addremove}'[mark new/missing files as added/removed before committing]' \
'(--message -m)'{-m+,--message}'[use <text> as commit message]:text:' \
- '(--logfile -l)'{-l+,--logfile}'[read commit message from <file>]:log file:_file -g \*.txt' \
+ '(--logfile -l)'{-l+,--logfile}'[read commit message from <file>]:log file:_files -g \*.txt' \
'(--date -d)'{-d+,--date}'[record datecode as commit date]:date code:' \
'(--user -u)'{-u+,--user}'[record user as commiter]:user:' \
'*:file:_hg_files'
--- a/mercurial/commands.py Sun May 27 14:40:14 2007 -0700
+++ b/mercurial/commands.py Sun May 27 14:43:29 2007 -0700
@@ -182,7 +182,7 @@
archival.archive(repo, dest, node, kind, not opts['no_decode'],
matchfn, prefix)
-def backout(ui, repo, rev, **opts):
+def backout(ui, repo, node=None, rev=None, **opts):
'''reverse effect of earlier changeset
Commit the backed out changes as a new changeset. The new
@@ -199,6 +199,11 @@
changeset afterwards. This saves you from doing the merge by
hand. The result of this merge is not committed, as for a normal
merge.'''
+ if rev and node:
+ raise util.Abort(_("please specify just one revision"))
+
+ if not rev:
+ rev = node
bail_if_changed(repo)
op1, op2 = repo.dirstate.parents()
@@ -1511,10 +1516,10 @@
if pf == '-':
ui.status(_("applying patch from stdin\n"))
- tmpname, message, user, date, nodeid, p1, p2 = patch.extract(ui, sys.stdin)
+ tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, sys.stdin)
else:
ui.status(_("applying %s\n") % p)
- tmpname, message, user, date, nodeid, p1, p2 = patch.extract(ui, file(pf))
+ tmpname, message, user, date, branch, nodeid, p1, p2 = patch.extract(ui, file(pf))
if tmpname is None:
raise util.Abort(_('no diffs found'))
@@ -1542,6 +1547,7 @@
if p1 != wp[0].node():
hg.clean(repo, p1, wlock=wlock)
repo.dirstate.setparents(p1, p2)
+ repo.dirstate.setbranch(branch or 'default')
elif p2:
try:
p1 = repo.lookup(p1)
@@ -1826,7 +1832,7 @@
ui.write("%3s " % (m.execf(f) and "755" or "644"))
ui.write("%s\n" % f)
-def merge(ui, repo, node=None, force=None):
+def merge(ui, repo, node=None, force=None, rev=None):
"""merge working directory with another revision
Merge the contents of the current working directory and the
@@ -1840,6 +1846,12 @@
revision to merge with must be provided.
"""
+ if rev and node:
+ raise util.Abort(_("please specify just one revision"))
+
+ if not node:
+ node = rev
+
if not node:
heads = repo.heads()
if len(heads) > 2:
@@ -2552,7 +2564,7 @@
modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
return postincoming(ui, repo, modheads, opts['update'])
-def update(ui, repo, node=None, clean=False, date=None):
+def update(ui, repo, node=None, rev=None, clean=False, date=None):
"""update working directory
Update the working directory to the specified revision, or the
@@ -2568,15 +2580,21 @@
By default, update will refuse to run if doing so would require
discarding local changes.
"""
+ if rev and node:
+ raise util.Abort(_("please specify just one revision"))
+
+ if not rev:
+ rev = node
+
if date:
- if node:
+ if rev:
raise util.Abort(_("you can't specify a revision and a date"))
- node = cmdutil.finddate(ui, repo, date)
+ rev = cmdutil.finddate(ui, repo, date)
if clean:
- return hg.clean(repo, node)
+ return hg.clean(repo, rev)
else:
- return hg.update(repo, node)
+ return hg.update(repo, rev)
def verify(ui, repo):
"""verify the integrity of the repository
@@ -2676,8 +2694,9 @@
('d', 'date', '', _('record datecode as commit date')),
('', 'parent', '', _('parent to choose when backing out merge')),
('u', 'user', '', _('record user as committer')),
+ ('r', 'rev', '', _('revision to backout')),
] + walkopts + commitopts,
- _('hg backout [OPTION]... REV')),
+ _('hg backout [OPTION]... [-r] REV')),
"branch": (branch,
[('f', 'force', None,
_('set branch name even if it shadows an existing branch'))],
@@ -2852,8 +2871,10 @@
"manifest": (manifest, [], _('hg manifest [REV]')),
"^merge":
(merge,
- [('f', 'force', None, _('force a merge with outstanding changes'))],
- _('hg merge [-f] [REV]')),
+ [('f', 'force', None, _('force a merge with outstanding changes')),
+ ('r', 'rev', '', _('revision to merge')),
+ ],
+ _('hg merge [-f] [[-r] REV]')),
"outgoing|out": (outgoing,
[('M', 'no-merges', None, _('do not show merges')),
('f', 'force', None,
@@ -2984,8 +3005,9 @@
"^update|up|checkout|co":
(update,
[('C', 'clean', None, _('overwrite locally modified files')),
- ('d', 'date', '', _('tipmost revision matching date'))],
- _('hg update [-C] [-d DATE] [REV]')),
+ ('d', 'date', '', _('tipmost revision matching date')),
+ ('r', 'rev', '', _('revision'))],
+ _('hg update [-C] [-d DATE] [[-r] REV]')),
"verify": (verify, [], _('hg verify')),
"version": (version_, [], _('hg version')),
}
--- a/mercurial/dirstate.py Sun May 27 14:40:14 2007 -0700
+++ b/mercurial/dirstate.py Sun May 27 14:43:29 2007 -0700
@@ -66,6 +66,8 @@
syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
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
--- a/mercurial/patch.py Sun May 27 14:40:14 2007 -0700
+++ b/mercurial/patch.py Sun May 27 14:43:29 2007 -0700
@@ -55,6 +55,7 @@
# should try to parse msg['Date']
date = None
nodeid = None
+ branch = None
parents = []
if message:
@@ -99,6 +100,8 @@
ui.debug('From: %s\n' % user)
elif line.startswith("# Date "):
date = line[7:]
+ elif line.startswith("# Branch "):
+ branch = line[9:]
elif line.startswith("# Node ID "):
nodeid = line[10:]
elif line.startswith("# Parent "):
@@ -123,10 +126,10 @@
tmpfp.close()
if not diffs_seen:
os.unlink(tmpname)
- return None, message, user, date, None, None, None
+ return None, message, user, date, branch, None, None, None
p1 = parents and parents.pop(0) or None
p2 = parents and parents.pop(0) or None
- return tmpname, message, user, date, nodeid, p1, p2
+ return tmpname, message, user, date, branch, nodeid, p1, p2
GP_PATCH = 1 << 0 # we have to run patch
GP_FILTER = 1 << 1 # there's some copy/rename operation
--- a/tests/test-hgignore Sun May 27 14:40:14 2007 -0700
+++ b/tests/test-hgignore Sun May 27 14:43:29 2007 -0700
@@ -1,6 +1,25 @@
#!/bin/sh
hg init
+
+# Test issue 562: .hgignore requires newline at end
+touch foo
+touch bar
+touch baz
+cat > makeignore.py <<EOF
+f = open(".hgignore", "w")
+f.write("ignore\n")
+f.write("foo\n")
+# No EOL here
+f.write("bar")
+f.close()
+EOF
+
+python makeignore.py
+echo % should display baz only
+hg status
+rm foo bar baz .hgignore makeignore.py
+
touch a.o
touch a.c
touch syntax
--- a/tests/test-hgignore.out Sun May 27 14:40:14 2007 -0700
+++ b/tests/test-hgignore.out Sun May 27 14:43:29 2007 -0700
@@ -1,3 +1,5 @@
+% should display baz only
+? baz
--
A dir/b.o
? a.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-impexp-branch Sun May 27 14:43:29 2007 -0700
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+cat >findbranch.py <<EOF
+import re, sys
+
+head_re = re.compile('^#(?:(?:\\s+([A-Za-z][A-Za-z0-9_]*)(?:\\s.*)?)|(?:\\s*))$')
+
+for line in sys.stdin:
+ hmatch = head_re.match(line)
+ if not hmatch:
+ sys.exit(1)
+ if hmatch.group(1) == 'Branch':
+ sys.exit(0)
+sys.exit(1)
+EOF
+hg init a
+cd a
+echo "Rev 1" >rev
+hg add rev
+hg commit -m "No branch."
+hg branch abranch
+echo "Rev 2" >rev
+hg commit -m "With branch."
+if hg export 0 | python ../findbranch.py; then
+ echo "Export of default branch revision has Branch header" 1>&2
+ exit 1
+fi
+if hg export 1 | python ../findbranch.py; then
+ : # Do nothing
+else
+ echo "Export of branch revision is missing Branch header" 1>&2
+ exit 1
+fi
+# Make sure import still works with branch information in patches.
+cd ..
+hg init b
+cd b
+hg -R ../a export 0 | hg import -
+hg -R ../a export 1 | hg import -
+cd ..
+rm -rf b
+hg init b
+cd b
+hg -R ../a export 0 | hg import --exact -
+hg -R ../a export 1 | hg import --exact -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-impexp-branch.out Sun May 27 14:43:29 2007 -0700
@@ -0,0 +1,4 @@
+applying patch from stdin
+applying patch from stdin
+applying patch from stdin
+applying patch from stdin