--- a/contrib/convert-repo
+++ b/contrib/convert-repo
@@ -30,7 +30,7 @@ from mercurial import hg, ui, util, fanc
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 @@ def recode(s):
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 @@ class convert_cvs:
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 @@ class convert_git:
return tags
-class convert_mercurial:
+class convert_mercurial(converter_sink):
def __init__(self, path):
self.path = path
u = ui.ui()
@@ -471,7 +552,7 @@ def converter(path):
pass
abort("%s: unknown repository type\n" % path)
-class convert:
+class convert(object):
def __init__(self, source, dest, mapfile, opts):
self.source = source
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -182,7 +182,7 @@ def archive(ui, repo, dest, **opts):
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 @@ def backout(ui, repo, rev, **opts):
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 @@ def import_(ui, repo, patch1, *patches,
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 @@ def import_(ui, repo, patch1, *patches,
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 @@ def manifest(ui, repo, rev=None):
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 @@ def merge(ui, repo, node=None, force=Non
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 @@ def unbundle(ui, repo, fname, **opts):
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 @@ def update(ui, repo, node=None, clean=Fa
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 @@ table = {
('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 @@ table = {
"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 @@ table = {
"^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/patch.py
+++ b/mercurial/patch.py
@@ -55,6 +55,7 @@ def extract(ui, fileobj):
# should try to parse msg['Date']
date = None
nodeid = None
+ branch = None
parents = []
if message:
@@ -99,6 +100,8 @@ def extract(ui, fileobj):
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 @@ def extract(ui, fileobj):
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