# HG changeset patch # User Matt Mackall # Date 1155149718 18000 # Node ID 49988d9f07586e55b65175a00626e9a20db094f7 # Parent 4870f795f6810ba2a02428d750bbe52ac8076b89# Parent 05316bb57d011277cae04019d9bd151e01a1b42d Merge with crew, fix most tests diff --git a/hgext/fetch.py b/hgext/fetch.py --- a/hgext/fetch.py +++ b/hgext/fetch.py @@ -36,8 +36,7 @@ def fetch(ui, repo, source='default', ** if newheads: ui.status(_('merging with new head %d:%s\n') % (repo.changelog.rev(newheads[0]), short(newheads[0]))) - err = hg.update(repo, newheads[0], allow=True, remind=False, - wlock=wlock) + err = hg.merge(repo, newheads[0], remind=False, wlock=wlock) if not err and len(newheads) > 1: ui.status(_('not merging with %d other new heads ' '(use "hg heads" and "hg merge" to merge them)') % diff --git a/hgext/hbisect.py b/hgext/hbisect.py --- a/hgext/hbisect.py +++ b/hgext/hbisect.py @@ -197,7 +197,7 @@ class bisect(object): check_clean(self.ui, self.repo) rev = self.next() if rev is not None: - return self.repo.update(rev, force=True) + return hg.clean(self.repo, rev) def good(self, rev): self.goodrevs.append(rev) diff --git a/hgext/mq.py b/hgext/mq.py --- a/hgext/mq.py +++ b/hgext/mq.py @@ -306,11 +306,11 @@ class queue: self.ui.warn("patch didn't work out, merging %s\n" % patch) # apply failed, strip away that rev and merge. - hg.update(repo, head, allow=False, force=True, wlock=wlock) + hg.clean(repo, head, wlock=wlock) self.strip(repo, n, update=False, backup='strip', wlock=wlock) c = repo.changelog.read(rev) - ret = hg.update(repo, rev, allow=True, wlock=wlock) + ret = hg.merge(repo, rev, wlock=wlock) if ret: raise util.Abort(_("update returned %d") % ret) n = repo.commit(None, c[4], c[1], force=1, wlock=wlock) @@ -653,7 +653,7 @@ class queue: if c or a or d or r: raise util.Abort(_("local changes found")) urev = self.qparents(repo, rev) - hg.update(repo, urev, allow=False, force=True, wlock=wlock) + hg.clean(repo, urev, wlock=wlock) repo.dirstate.write() # save is a list of all the branches we are truncating away @@ -1148,7 +1148,7 @@ class queue: if not r: self.ui.warn("Unable to load queue repository\n") return 1 - hg.update(r, qpp[0], allow=False, force=True) + hg.clean(r, qpp[0]) def save(self, repo, msg=None): if len(self.applied) == 0: diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -976,7 +976,7 @@ def backout(ui, repo, rev, **opts): if opts['parent']: raise util.Abort(_('cannot use --parent on non-merge changeset')) parent = p1 - hg.update(repo, node, force=True, show_stats=False) + hg.clean(repo, node, show_stats=False) revert_opts = opts.copy() revert_opts['rev'] = hex(parent) revert(ui, repo, **revert_opts) @@ -993,7 +993,8 @@ def backout(ui, repo, rev, **opts): if op1 != node: if opts['merge']: ui.status(_('merging with changeset %s\n') % nice(op1)) - doupdate(ui, repo, hex(op1), merge=True) + n = _lookup(repo, hex(op1)) + hg.merge(repo, n) else: ui.status(_('the backout changeset is a new head - ' 'do not forget to merge\n')) @@ -2152,7 +2153,7 @@ def manifest(ui, repo, rev=None): for f in files: ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f)) -def merge(ui, repo, node=None, **opts): +def merge(ui, repo, node=None, force=None, branch=None): """Merge working directory with another revision Merge the contents of the current working directory and the @@ -2160,7 +2161,9 @@ def merge(ui, repo, node=None, **opts): marked as changed for the next commit and a commit must be performed before any further updates are allowed. """ - return doupdate(ui, repo, node=node, merge=True, **opts) + + node = _lookup(repo, node, branch) + return hg.merge(repo, node, force=force) def outgoing(ui, repo, dest=None, **opts): """show changesets not found in destination @@ -2254,7 +2257,7 @@ def postincoming(ui, repo, modheads, opt return if optupdate: if modheads == 1: - return doupdate(ui, repo) + return hg.update(repo, repo.changelog.tip()) # update else: ui.status(_("not updating, since new heads added\n")) if modheads > 1: @@ -2603,8 +2606,7 @@ def revert(ui, repo, *pats, **opts): if not opts.get('dry_run'): repo.dirstate.forget(forget[0]) - r = hg.update(repo, node, False, True, update.has_key, False, - wlock=wlock, show_stats=False) + r = hg.revert(repo, node, update.has_key, wlock) repo.dirstate.update(add[0], 'a') repo.dirstate.update(undelete[0], 'n') repo.dirstate.update(remove[0], 'r') @@ -2902,13 +2904,17 @@ def update(ui, repo, node=None, merge=Fa By default, update will refuse to run if doing so would require merging or discarding local changes. """ + node = _lookup(repo, node, branch) if merge: ui.warn(_('(the -m/--merge option is deprecated; ' 'use the merge command instead)\n')) - return doupdate(ui, repo, node, merge, clean, force, branch) - -def doupdate(ui, repo, node=None, merge=False, clean=False, force=None, - branch=None): + return hg.merge(repo, node, force=force) + elif clean: + return hg.clean(repo, node) + else: + return hg.update(repo, node) + +def _lookup(repo, node, branch=None): if branch: br = repo.branchlookup(branch=branch) found = [] @@ -2916,19 +2922,19 @@ def doupdate(ui, repo, node=None, merge= if branch in br[x]: found.append(x) if len(found) > 1: - ui.warn(_("Found multiple heads for %s\n") % branch) + repo.ui.warn(_("Found multiple heads for %s\n") % branch) for x in found: show_changeset(ui, repo, {}).show(changenode=x, brinfo=br) - return 1 + raise util.Abort("") if len(found) == 1: node = found[0] - ui.warn(_("Using head %s for branch %s\n") % (short(node), branch)) + repo.ui.warn(_("Using head %s for branch %s\n") + % (short(node), branch)) else: - ui.warn(_("branch %s not found\n") % (branch)) - return 1 + raise util.Abort(_("branch %s not found\n") % (branch)) else: node = node and repo.lookup(node) or repo.changelog.tip() - return hg.update(repo, node, allow=merge, force=clean, forcemerge=force) + return node def verify(ui, repo): """verify the integrity of the repository diff --git a/mercurial/demandload.py b/mercurial/demandload.py --- a/mercurial/demandload.py +++ b/mercurial/demandload.py @@ -96,6 +96,7 @@ def demandload(scope, modules): foo import foo foo bar import foo, bar + foo@bar import foo as bar foo.bar import foo.bar foo:bar from foo import bar foo:bar,quux from foo import bar, quux @@ -108,6 +109,9 @@ def demandload(scope, modules): mod = mod[:col] else: fromlist = [] + as = None + if '@' in mod: + mod, as = mod.split("@") importer = _importer(scope, mod, fromlist) if fromlist: for name in fromlist: @@ -126,4 +130,6 @@ def demandload(scope, modules): continue else: basemod = mod - scope[basemod] = _replacer(importer, basemod) + if not as: + as = basemod + scope[as] = _replacer(importer, as) diff --git a/mercurial/hg.py b/mercurial/hg.py --- a/mercurial/hg.py +++ b/mercurial/hg.py @@ -10,7 +10,7 @@ from repo import * from demandload import * from i18n import gettext as _ demandload(globals(), "localrepo bundlerepo httprepo sshrepo statichttprepo") -demandload(globals(), "errno lock os shutil util merge") +demandload(globals(), "errno lock os shutil util merge@_merge verify@_verify") def _local(path): return (os.path.isfile(path and util.drop_scheme('file', path)) and @@ -200,23 +200,31 @@ def clone(ui, source, dest=None, pull=Fa dest_lock.release() if update: - merge.update(dest_repo, dest_repo.changelog.tip()) + _merge.update(dest_repo, dest_repo.changelog.tip()) if dir_cleanup: dir_cleanup.close() return src_repo, dest_repo +def update(repo, node): + """update the working directory to node, merging linear changes""" + return _merge.update(repo, node) -# This should instead be several functions with short arglists, like -# update/merge/revert +def clean(repo, node, wlock=None, show_stats=True): + """forcibly switch the working directory to node, clobbering changes""" + return _merge.update(repo, node, force=True, wlock=wlock, + show_stats=show_stats) -def update(repo, node, allow=False, force=False, choose=None, - moddirstate=True, forcemerge=False, wlock=None, show_stats=True, - remind=True): - return merge.update(repo, node, allow, force, choose, moddirstate, - forcemerge, wlock, show_stats, remind) +def merge(repo, node, force=None, remind=True, wlock=None): + """branch merge with node, resolving changes""" + return _merge.update(repo, node, branchmerge=True, force=force, + remind=remind, wlock=wlock) + +def revert(repo, node, choose, wlock): + """revert changes to revision in node without updating dirstate""" + return _merge.update(repo, node, force=True, partial=choose, + show_stats=False, wlock=wlock) def verify(repo): """verify the consistency of a repository""" - import verify as _verify return _verify.verify(repo) diff --git a/mercurial/merge.py b/mercurial/merge.py --- a/mercurial/merge.py +++ b/mercurial/merge.py @@ -47,17 +47,39 @@ def merge3(repo, fn, my, other, p1, p2): os.unlink(c) return r -def update(repo, node, allow=False, force=False, choose=None, - moddirstate=True, forcemerge=False, wlock=None, show_stats=True, - remind=True): +def update(repo, node, branchmerge=False, force=False, partial=None, + wlock=None, show_stats=True, remind=True): + + overwrite = force and not branchmerge + forcemerge = force and branchmerge + + if not wlock: + wlock = repo.wlock() + + ### check phase + pl = repo.dirstate.parents() - if not force and pl[1] != nullid: + if not overwrite and pl[1] != nullid: raise util.Abort(_("outstanding uncommitted merges")) - err = False - p1, p2 = pl[0], node pa = repo.changelog.ancestor(p1, p2) + + # is there a linear path from p1 to p2? + linear_path = (pa == p1 or pa == p2) + if branchmerge and linear_path: + raise util.Abort(_("there is nothing to merge, just use " + "'hg update' or look at 'hg heads'")) + + if not overwrite and not linear_path and not branchmerge: + raise util.Abort(_("update spans branches, use 'hg merge' " + "or 'hg update -C' to lose changes")) + + modified, added, removed, deleted, unknown = repo.changes() + if branchmerge and not forcemerge: + if modified or added or removed: + raise util.Abort(_("outstanding uncommitted changes")) + m1n = repo.changelog.read(p1)[0] m2n = repo.changelog.read(p2)[0] man = repo.manifest.ancestor(m1n, m2n) @@ -68,20 +90,7 @@ def update(repo, node, allow=False, forc ma = repo.manifest.read(man) mfa = repo.manifest.readflags(man) - modified, added, removed, deleted, unknown = repo.changes() - - # is this a jump, or a merge? i.e. is there a linear path - # from p1 to p2? - linear_path = (pa == p1 or pa == p2) - - if allow and linear_path: - raise util.Abort(_("there is nothing to merge, just use " - "'hg update' or look at 'hg heads'")) - if allow and not forcemerge: - if modified or added or removed: - raise util.Abort(_("outstanding uncommitted changes")) - - if not forcemerge and not force: + if not forcemerge and not overwrite: for f in unknown: if f in m2: t1 = repo.wread(f) @@ -93,8 +102,8 @@ def update(repo, node, allow=False, forc # resolve the manifest to determine which files # we care about merging repo.ui.note(_("resolving manifests\n")) - repo.ui.debug(_(" force %s allow %s moddirstate %s linear %s\n") % - (force, allow, moddirstate, linear_path)) + repo.ui.debug(_(" overwrite %s branchmerge %s partial %s linear %s\n") % + (overwrite, branchmerge, partial and True or False, linear_path)) repo.ui.debug(_(" ancestor %s local %s remote %s\n") % (short(man), short(m1n), short(m2n))) @@ -111,9 +120,6 @@ def update(repo, node, allow=False, forc mw[f] = "" mfw[f] = util.is_exec(repo.wjoin(f), mfw.get(f, False)) - if moddirstate and not wlock: - wlock = repo.wlock() - for f in deleted + removed: if f in mw: del mw[f] @@ -123,12 +129,12 @@ def update(repo, node, allow=False, forc # the file, then we need to remove it from the dirstate, to # prevent the dirstate from listing the file when it is no # longer in the manifest. - if moddirstate and linear_path and f not in m2: + if not partial and linear_path and f not in m2: repo.dirstate.forget((f,)) # Compare manifests for f, n in mw.iteritems(): - if choose and not choose(f): + if partial and not partial(f): continue if f in m2: s = 0 @@ -156,7 +162,7 @@ def update(repo, node, allow=False, forc # are we clobbering? # is remote's version newer? # or are we going back in time? - elif force or m2[f] != a or (p2 == pa and mw[f] == m1[f]): + elif overwrite or m2[f] != a or (p2 == pa and mw[f] == m1[f]): repo.ui.debug(_(" remote %s is newer, get\n") % f) get[f] = m2[f] s = 1 @@ -166,7 +172,7 @@ def update(repo, node, allow=False, forc get[f] = m2[f] if not s and mfw[f] != mf2[f]: - if force: + if overwrite: repo.ui.debug(_(" updating permissions for %s\n") % f) util.set_exec(repo.wjoin(f), mf2[f]) else: @@ -180,7 +186,7 @@ def update(repo, node, allow=False, forc elif f in ma: if n != ma[f]: r = _("d") - if not force and (linear_path or allow): + if not overwrite and (linear_path or branchmerge): r = repo.ui.prompt( (_(" local changed %s which remote deleted\n") % f) + _("(k)eep or (d)elete?"), _("[kd]"), _("k")) @@ -191,7 +197,7 @@ def update(repo, node, allow=False, forc remove.append(f) # other deleted it else: # file is created on branch or in working directory - if force and f not in umap: + if overwrite and f not in umap: repo.ui.debug(_("remote deleted %s, clobbering\n") % f) remove.append(f) elif n == m1.get(f, nullid): # same as parent @@ -204,13 +210,13 @@ def update(repo, node, allow=False, forc repo.ui.debug(_("working dir created %s, keeping\n") % f) for f, n in m2.iteritems(): - if choose and not choose(f): + if partial and not partial(f): continue if f[0] == "/": continue if f in ma and n != ma[f]: r = _("k") - if not force and (linear_path or allow): + if not overwrite and (linear_path or branchmerge): r = repo.ui.prompt( (_("remote changed %s which local deleted\n") % f) + _("(k)eep or (d)elete?"), _("[kd]"), _("k")) @@ -220,7 +226,7 @@ def update(repo, node, allow=False, forc repo.ui.debug(_("remote created %s\n") % f) get[f] = n else: - if force or p2 == pa: # going backwards? + if overwrite or p2 == pa: # going backwards? repo.ui.debug(_("local deleted %s, recreating\n") % f) get[f] = n else: @@ -228,31 +234,14 @@ def update(repo, node, allow=False, forc del mw, m1, m2, ma - if force: + if overwrite: for f in merge: get[f] = merge[f][1] merge = {} - if linear_path or force: + if linear_path or overwrite: # we don't need to do any magic, just jump to the new rev - branch_merge = False p1, p2 = p2, nullid - else: - if not allow: - repo.ui.status(_("this update spans a branch" - " affecting the following files:\n")) - fl = merge.keys() + get.keys() - fl.sort() - for f in fl: - cf = "" - if f in merge: - cf = _(" (resolve)") - repo.ui.status(" %s%s\n" % (f, cf)) - repo.ui.warn(_("aborting update spanning branches!\n")) - repo.ui.status(_("(use 'hg merge' to merge across branches" - " or 'hg update -C' to lose changes)\n")) - return 1 - branch_merge = True xp1 = hex(p1) xp2 = hex(p2) @@ -271,14 +260,14 @@ def update(repo, node, allow=False, forc t = repo.file(f).read(get[f]) repo.wwrite(f, t) util.set_exec(repo.wjoin(f), mf2[f]) - if moddirstate: - if branch_merge: + if not partial: + if branchmerge: repo.dirstate.update([f], 'n', st_mtime=-1) else: repo.dirstate.update([f], 'n') # merge the tricky bits - failedmerge = [] + unresolved = [] files = merge.keys() files.sort() for f in files: @@ -286,11 +275,10 @@ def update(repo, node, allow=False, forc my, other, flag = merge[f] ret = merge3(repo, f, my, other, xp1, xp2) if ret: - err = True - failedmerge.append(f) + unresolved.append(f) util.set_exec(repo.wjoin(f), flag) - if moddirstate: - if branch_merge: + if not partial: + if branchmerge: # We've done a branch merge, mark this file as merged # so that we properly record the merger later repo.dirstate.update([f], 'm') @@ -313,25 +301,25 @@ def update(repo, node, allow=False, forc if inst.errno != errno.ENOENT: repo.ui.warn(_("update failed to remove %s: %s!\n") % (f, inst.strerror)) - if moddirstate: - if branch_merge: + if not partial: + if branchmerge: repo.dirstate.update(remove, 'r') else: repo.dirstate.forget(remove) - if moddirstate: + if not partial: repo.dirstate.setparents(p1, p2) if show_stats: stats = ((len(get), _("updated")), - (len(merge) - len(failedmerge), _("merged")), + (len(merge) - len(unresolved), _("merged")), (len(remove), _("removed")), - (len(failedmerge), _("unresolved"))) + (len(unresolved), _("unresolved"))) note = ", ".join([_("%d files %s") % s for s in stats]) repo.ui.status("%s\n" % note) - if moddirstate: - if branch_merge: - if failedmerge: + if not partial: + if branchmerge: + if unresolved: repo.ui.status(_("There are unresolved merges," " you can redo the full merge using:\n" " hg update -C %s\n" @@ -340,10 +328,10 @@ def update(repo, node, allow=False, forc repo.changelog.rev(p2)))) elif remind: repo.ui.status(_("(branch merge, don't forget to commit)\n")) - elif failedmerge: + elif unresolved: repo.ui.status(_("There are unresolved merges with" " locally modified files.\n")) - repo.hook('update', parent1=xp1, parent2=xxp2, error=int(err)) - return err + repo.hook('update', parent1=xp1, parent2=xxp2, error=len(unresolved)) + return len(unresolved) diff --git a/tests/test-merge5.out b/tests/test-merge5.out --- a/tests/test-merge5.out +++ b/tests/test-merge5.out @@ -1,6 +1,3 @@ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved removing b -this update spans a branch affecting the following files: - b -aborting update spanning branches! -(use 'hg merge' to merge across branches or 'hg update -C' to lose changes) +abort: update spans branches, use 'hg merge' or 'hg update -C' to lose changes diff --git a/tests/test-merge7.out b/tests/test-merge7.out --- a/tests/test-merge7.out +++ b/tests/test-merge7.out @@ -22,7 +22,7 @@ added 1 changesets with 1 changes to 1 f (run 'hg heads' to see heads, 'hg merge' to merge) merge: warning: conflicts during merge resolving manifests - force False allow True moddirstate True linear False + overwrite None branchmerge True partial False linear False ancestor 055d847dd401 local 2eded9ab0a5c remote 84cf5750dd20 test.txt versions differ, resolve merging test.txt diff --git a/tests/test-up-local-change.out b/tests/test-up-local-change.out --- a/tests/test-up-local-change.out +++ b/tests/test-up-local-change.out @@ -17,7 +17,7 @@ date: Mon Jan 12 13:46:40 1970 +0 summary: 1 resolving manifests - force None allow None moddirstate True linear True + overwrite False branchmerge False partial False linear True ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e a versions differ, resolve remote created b @@ -33,7 +33,7 @@ date: Mon Jan 12 13:46:40 1970 +0 summary: 2 resolving manifests - force None allow None moddirstate True linear True + overwrite False branchmerge False partial False linear True ancestor a0c8bcbbb45c local 1165e8bd193e remote a0c8bcbbb45c remote deleted b removing b @@ -51,7 +51,7 @@ date: Mon Jan 12 13:46:40 1970 +0 summary: 1 resolving manifests - force None allow None moddirstate True linear True + overwrite False branchmerge False partial False linear True ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e a versions differ, resolve remote created b @@ -98,21 +98,12 @@ user: test date: Mon Jan 12 13:46:40 1970 +0000 summary: 2 -resolving manifests - force None allow None moddirstate True linear False - ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392 - a versions differ, resolve - b versions differ, resolve -this update spans a branch affecting the following files: - a (resolve) - b (resolve) -aborting update spanning branches! -(use 'hg merge' to merge across branches or 'hg update -C' to lose changes) +abort: update spans branches, use 'hg merge' or 'hg update -C' to lose changes failed abort: outstanding uncommitted changes failed resolving manifests - force False allow True moddirstate True linear False + overwrite False branchmerge True partial False linear False ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392 a versions differ, resolve b versions differ, resolve diff --git a/tests/test-update-reverse.out b/tests/test-update-reverse.out --- a/tests/test-update-reverse.out +++ b/tests/test-update-reverse.out @@ -40,7 +40,7 @@ a side1 side2 resolving manifests - force 1 allow None moddirstate True linear False + overwrite True branchmerge False partial False linear False ancestor 8515d4bfda76 local 1c0f48f8ece6 remote 0594b9004bae remote deleted side2, clobbering remote deleted side1, clobbering