Merge with crew, fix most tests
authorMatt Mackall <mpm@selenic.com>
Wed, 09 Aug 2006 13:55:18 -0500
changeset 2830 49988d9f0758
parent 2829 4870f795f681 (diff)
parent 2818 05316bb57d01 (current diff)
child 2831 0b9ac7dfcf56
child 2848 e78cad1f6b1f
child 2981 0171a5432621
Merge with crew, fix most tests
hgext/fetch.py
hgext/mq.py
mercurial/hg.py
tests/test-merge5.out
tests/test-merge7.out
tests/test-up-local-change.out
tests/test-update-reverse.out
--- 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)') %
--- 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)
--- 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:
--- 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
--- 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)
--- 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)
--- 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)
 
--- 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
--- 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
--- 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
--- 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