# HG changeset patch # User Bryan O'Sullivan # Date 1180302209 25200 # Node ID c927c568a5ade7f36cc425ce85ad33a29dd64d98 # Parent a11e13d50645102bfa2cc9089e4efd932765ff80# Parent 8fa54b9c6c5a22654e3b244e073673a415059897 Automated merge with http://hg.intevation.org/mercurial/crew diff --git a/contrib/convert-repo b/contrib/convert-repo --- 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 diff --git a/contrib/zsh_completion b/contrib/zsh_completion --- a/contrib/zsh_completion +++ b/contrib/zsh_completion @@ -380,7 +380,7 @@ typeset -A _hg_cmd_globals _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 as commit message]:text:' \ - '(--logfile -l)'{-l+,--logfile}'[read commit message from ]:log file:_file -g \*.txt' \ + '(--logfile -l)'{-l+,--logfile}'[read commit message from ]: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' diff --git a/mercurial/commands.py b/mercurial/commands.py --- 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')), } diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py --- a/mercurial/dirstate.py +++ b/mercurial/dirstate.py @@ -66,6 +66,8 @@ class dirstate(object): 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 diff --git a/mercurial/patch.py b/mercurial/patch.py --- 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 diff --git a/tests/test-hgignore b/tests/test-hgignore --- a/tests/test-hgignore +++ b/tests/test-hgignore @@ -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 <findbranch.py <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 - diff --git a/tests/test-impexp-branch.out b/tests/test-impexp-branch.out new file mode 100644 --- /dev/null +++ b/tests/test-impexp-branch.out @@ -0,0 +1,4 @@ +applying patch from stdin +applying patch from stdin +applying patch from stdin +applying patch from stdin