Merge with stable
authorMatt Mackall <mpm@selenic.com>
Mon, 31 Mar 2008 21:49:26 -0500
changeset 6432 b1204fd06c2e
parent 6420 626a8e396846 (current diff)
parent 6431 a42d8d3e6ea9 (diff)
child 6433 ec5d77eb3431
Merge with stable
mercurial/commands.py
--- a/hgext/churn.py	Mon Mar 31 18:49:15 2008 +0200
+++ b/hgext/churn.py	Mon Mar 31 21:49:26 2008 -0500
@@ -155,7 +155,7 @@
 
         for l in f.readlines():
             l = l.strip()
-            alias, actual = l.split(" ")
+            alias, actual = l.split()
             aliases[alias] = actual
 
         return aliases
--- a/mercurial/ancestor.py	Mon Mar 31 18:49:15 2008 +0200
+++ b/mercurial/ancestor.py	Mon Mar 31 21:49:26 2008 -0500
@@ -81,54 +81,3 @@
                 gx = x.next()
     except StopIteration:
         return None
-
-def symmetricdifference(a, b, pfunc):
-    """symmetric difference of the sets of ancestors of a and b
-
-    I.e. revisions that are ancestors of a or b, but not both.
-    """
-    # basic idea:
-    # - mark a and b with different colors
-    # - walk the graph in topological order with the help of a heap;
-    #   for each revision r:
-    #     - if r has only one color, we want to return it
-    #     - add colors[r] to its parents
-    #
-    # We keep track of the number of revisions in the heap that
-    # we may be interested in.  We stop walking the graph as soon
-    # as this number reaches 0.
-    if a == b:
-        return [a]
-
-    WHITE = 1
-    BLACK = 2
-    ALLCOLORS = WHITE | BLACK
-    colors = {a: WHITE, b: BLACK}
-
-    visit = [-a, -b]
-    heapq.heapify(visit)
-    n_wanted = len(visit)
-    ret = []
-
-    while n_wanted:
-        r = -heapq.heappop(visit)
-        wanted = colors[r] != ALLCOLORS
-        n_wanted -= wanted
-        if wanted:
-            ret.append(r)
-
-        for p in pfunc(r):
-            if p not in colors:
-                # first time we see p; add it to visit
-                n_wanted += wanted
-                colors[p] = colors[r]
-                heapq.heappush(visit, -p)
-            elif colors[p] != ALLCOLORS and colors[p] != colors[r]:
-                # at first we thought we wanted p, but now
-                # we know we don't really want it
-                n_wanted -= 1
-                colors[p] |= colors[r]
-
-        del colors[r]
-
-    return ret
--- a/mercurial/commands.py	Mon Mar 31 18:49:15 2008 +0200
+++ b/mercurial/commands.py	Mon Mar 31 21:49:26 2008 -0500
@@ -227,7 +227,10 @@
             raise util.Abort(_('cannot use --parent on non-merge changeset'))
         parent = p1
 
+    # the backout should appear on the same branch
+    branch = repo.dirstate.branch()
     hg.clean(repo, node, show_stats=False)
+    repo.dirstate.setbranch(branch)
     revert_opts = opts.copy()
     revert_opts['date'] = None
     revert_opts['all'] = True
--- a/mercurial/copies.py	Mon Mar 31 18:49:15 2008 +0200
+++ b/mercurial/copies.py	Mon Mar 31 21:49:26 2008 -0500
@@ -7,7 +7,7 @@
 
 from node import nullid, nullrev
 from i18n import _
-import util, ancestor
+import util, heapq
 
 def _nonoverlap(d1, d2, d3):
     "Return list of elements in d1 not in d2 or d3"
@@ -35,40 +35,81 @@
     old = {}
     seen = {}
     orig = fctx.path()
-    visit = [fctx]
+    visit = [(fctx, 0)]
     while visit:
-        fc = visit.pop()
+        fc, depth = visit.pop()
         s = str(fc)
         if s in seen:
             continue
         seen[s] = 1
         if fc.path() != orig and fc.path() not in old:
-            old[fc.path()] = 1
+            old[fc.path()] = (depth, fc.path()) # remember depth
         if fc.rev() < limit and fc.rev() is not None:
             continue
-        visit += fc.parents()
+        visit += [(p, depth - 1) for p in fc.parents()]
 
-    old = old.keys()
+    # return old names sorted by depth
+    old = old.values()
     old.sort()
-    return old
+    return [o[1] for o in old]
+
+def _findlimit(repo, a, b):
+    "find the earliest revision that's an ancestor of a or b but not both"
+    # basic idea:
+    # - mark a and b with different sides
+    # - if a parent's children are all on the same side, the parent is
+    #   on that side, otherwise it is on no side
+    # - walk the graph in topological order with the help of a heap;
+    #   - add unseen parents to side map
+    #   - clear side of any parent that has children on different sides
+    #   - track number of interesting revs that might still be on a side
+    #   - track the lowest interesting rev seen
+    #   - quit when interesting revs is zero
+
+    cl = repo.changelog
+    working = cl.count() # pseudo rev for the working directory
+    if a is None:
+        a = working
+    if b is None:
+        b = working
 
-def copies(repo, c1, c2, ca):
+    side = {a: -1, b: 1}
+    visit = [-a, -b]
+    heapq.heapify(visit)
+    interesting = len(visit)
+    limit = working
+
+    while interesting:
+        r = -heapq.heappop(visit)
+        if r == working:
+            parents = [cl.rev(p) for p in repo.dirstate.parents()]
+        else:
+            parents = cl.parentrevs(r)
+        for p in parents:
+            if p not in side:
+                # first time we see p; add it to visit
+                side[p] = side[r]
+                if side[p]:
+                    interesting += 1
+                heapq.heappush(visit, -p)
+            elif side[p] and side[p] != side[r]:
+                # p was interesting but now we know better
+                side[p] = 0
+                interesting -= 1
+        if side[r]:
+            limit = r # lowest rev visited
+            interesting -= 1
+    return limit
+
+def copies(repo, c1, c2, ca, checkdirs=False):
     """
     Find moves and copies between context c1 and c2
     """
     # avoid silly behavior for update from empty dir
-    if not c1 or not c2:
+    if not c1 or not c2 or c1 == c2:
         return {}, {}
 
-    rev1, rev2 = c1.rev(), c2.rev()
-    if rev1 is None: # c1 is a workingctx
-        rev1 = c1.parents()[0].rev()
-    if rev2 is None: # c2 is a workingctx
-        rev2 = c2.parents()[0].rev()
-    pr = repo.changelog.parentrevs
-    def parents(rev):
-        return [p for p in pr(rev) if p != nullrev]
-    limit = min(ancestor.symmetricdifference(rev1, rev2, parents))
+    limit = _findlimit(repo, c1.rev(), c2.rev())
     m1 = c1.manifest()
     m2 = c2.manifest()
     ma = ca.manifest()
@@ -97,15 +138,12 @@
                     c2 = ctx(of, m2[of])
                     ca = c1.ancestor(c2)
                     # related and named changed on only one side?
-                    if ca and ca.path() == f or ca.path() == c2.path():
+                    if ca and (ca.path() == f or ca.path() == c2.path()):
                         if c1 != ca or c2 != ca: # merge needed?
                             copy[f] = of
             elif of in ma:
                 diverge.setdefault(of, []).append(f)
 
-    if not repo.ui.configbool("merge", "followcopies", True):
-        return {}, {}
-
     repo.ui.debug(_("  searching for copies back to rev %d\n") % limit)
 
     u1 = _nonoverlap(m1, m2, ma)
@@ -139,7 +177,7 @@
             repo.ui.debug(_("   %s -> %s %s\n") % (f, fullcopy[f], note))
     del diverge2
 
-    if not fullcopy or not repo.ui.configbool("merge", "followdirs", True):
+    if not fullcopy or not checkdirs:
         return copy, diverge
 
     repo.ui.debug(_("  checking for directory renames\n"))
@@ -186,8 +224,10 @@
             for d in dirmove:
                 if f.startswith(d):
                     # new file added in a directory that was moved, move it
-                    copy[f] = dirmove[d] + f[len(d):]
-                    repo.ui.debug(_("  file %s -> %s\n") % (f, copy[f]))
+                    df = dirmove[d] + f[len(d):]
+                    if df not in copy:
+                        copy[f] = df
+                        repo.ui.debug(_("  file %s -> %s\n") % (f, copy[f]))
                     break
 
     return copy, diverge
--- a/mercurial/merge.py	Mon Mar 31 18:49:15 2008 +0200
+++ b/mercurial/merge.py	Mon Mar 31 21:49:26 2008 -0500
@@ -101,7 +101,9 @@
         action.append((f, m) + args)
 
     if pa and not (backwards or overwrite):
-        copy, diverge = copies.copies(repo, p1, p2, pa)
+        if repo.ui.configbool("merge", "followcopies", True):
+            dirs = repo.ui.configbool("merge", "followdirs", True)
+            copy, diverge = copies.copies(repo, p1, p2, pa, dirs)
         copied = dict.fromkeys(copy.values())
         for of, fl in diverge.items():
             act("divergent renames", "dr", of, fl)
--- a/tests/test-backout.out	Mon Mar 31 18:49:15 2008 +0200
+++ b/tests/test-backout.out	Mon Mar 31 21:49:26 2008 -0500
@@ -74,7 +74,7 @@
 adding file2
 removing file1
 created new head
-changeset 3:f1c642b1d8e5 backs out changeset 1:bf1602f437f3
+changeset 3:d4e8f6db59fb backs out changeset 1:bf1602f437f3
 the backout changeset is a new head - do not forget to merge
 (use "backout --merge" if you want to auto-merge)
 % on branch2 with branch1 not merged, so file1 should still exist:
@@ -85,10 +85,11 @@
 % on branch2 with branch1 merged, so file1 should be gone:
 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
-21d4dc6f9a41 (branch2) tip
+22149cdde76d (branch2) tip
 C default
 C file2
 % on branch1, so no file1 and file2:
-0 files updated, 0 files merged, 1 files removed, 0 files unresolved
-f1c642b1d8e5 (branch1)
+1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+bf1602f437f3 (branch1)
 C default
+C file1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-diff-copy-depth	Mon Mar 31 21:49:26 2008 -0500
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+for i in aaa zzz; do
+    hg init t
+    cd t
+
+    echo "-- With $i"
+
+    touch file
+    hg add file
+    hg ci -m "Add"
+
+    hg cp file $i
+    hg ci -m "a -> $i"
+
+    hg cp $i other-file
+    echo "different" >> $i
+    hg ci -m "$i -> other-file"
+
+    hg cp other-file somename
+
+    echo "Status":
+    hg st -C
+    echo
+    echo "Diff:"
+    hg diff -g
+    echo
+
+    cd ..
+    rm -rf t
+done
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-diff-copy-depth.out	Mon Mar 31 21:49:26 2008 -0500
@@ -0,0 +1,20 @@
+-- With aaa
+Status:
+A somename
+  other-file
+
+Diff:
+diff --git a/other-file b/somename
+copy from other-file
+copy to somename
+
+-- With zzz
+Status:
+A somename
+  other-file
+
+Diff:
+diff --git a/other-file b/somename
+copy from other-file
+copy to somename
+
--- a/tests/test-mv-cp-st-diff	Mon Mar 31 18:49:15 2008 +0200
+++ b/tests/test-mv-cp-st-diff	Mon Mar 31 21:49:26 2008 -0500
@@ -11,12 +11,17 @@
 # set up a boring main branch
 add a a
 hg add a
+mkdir x
+add x/x x
+hg add x/x
 hg ci -m0
 
 add a m1
 hg ci -m1
 
 add a m2
+add x/y y1
+hg add x/y
 hg ci -m2
 
 show()
@@ -59,6 +64,7 @@
     echo
 }
 
+
 tb "add a a1" "add a a2" "hg mv a b" "rename in working dir"
 tb "add a a1" "add a a2" "hg cp a b" "copy in working dir" 
 tb "hg mv a b" "add b b1" "add b w" "single rename"
@@ -66,3 +72,5 @@
 tb "hg mv a b" "hg mv b c" "hg mv c d" "rename chain"
 tb "hg cp a b" "hg cp b c" "hg cp c d" "copy chain"
 tb "add a a1" "hg mv a b" "hg mv b a" "circular rename"
+
+tb "hg mv x y" "add y/x x1" "add y/x x2" "directory move"
--- a/tests/test-mv-cp-st-diff.out	Mon Mar 31 18:49:15 2008 +0200
+++ b/tests/test-mv-cp-st-diff.out	Mon Mar 31 21:49:26 2008 -0500
@@ -30,6 +30,7 @@
 A b
   a
 R a
+R x/y
 
 diff --git a/a b/b
 rename from a
@@ -43,6 +44,12 @@
 +0
 +a1
 +a2
+diff --git a/x/y b/x/y
+deleted file mode 100644
+--- a/x/y
++++ /dev/null
+@@ -1,1 +0,0 @@
+-y1
 
 - root to parent: --rev 0 --rev .
 M a
@@ -70,6 +77,7 @@
 
 - branch to parent: --rev 2 --rev .
 M a
+R x/y
 
 diff --git a/a b/a
 --- a/a
@@ -81,9 +89,16 @@
 +0
 +a1
 +a2
+diff --git a/x/y b/x/y
+deleted file mode 100644
+--- a/x/y
++++ /dev/null
+@@ -1,1 +0,0 @@
+-y1
 
 - parent to branch: --rev . --rev 2
 M a
+A x/y
 
 diff --git a/a b/a
 --- a/a
@@ -95,6 +110,12 @@
 -a2
 +m1
 +m2
+diff --git a/x/y b/x/y
+new file mode 100644
+--- /dev/null
++++ b/x/y
+@@ -0,0 +1,1 @@
++y1
 
 
 created new head
@@ -136,6 +157,7 @@
 M a
 A b
   a
+R x/y
 
 diff --git a/a b/a
 --- a/a
@@ -159,6 +181,12 @@
 +1
 +a1
 +a2
+diff --git a/x/y b/x/y
+deleted file mode 100644
+--- a/x/y
++++ /dev/null
+@@ -1,1 +0,0 @@
+-y1
 
 - root to parent: --rev 0 --rev .
 M a
@@ -186,6 +214,7 @@
 
 - branch to parent: --rev 2 --rev .
 M a
+R x/y
 
 diff --git a/a b/a
 --- a/a
@@ -197,9 +226,16 @@
 +1
 +a1
 +a2
+diff --git a/x/y b/x/y
+deleted file mode 100644
+--- a/x/y
++++ /dev/null
+@@ -1,1 +0,0 @@
+-y1
 
 - parent to branch: --rev . --rev 2
 M a
+A x/y
 
 diff --git a/a b/a
 --- a/a
@@ -211,6 +247,12 @@
 -a2
 +m1
 +m2
+diff --git a/x/y b/x/y
+new file mode 100644
+--- /dev/null
++++ b/x/y
+@@ -0,0 +1,1 @@
++y1
 
 
 created new head
@@ -248,6 +290,7 @@
 A b
   a
 R a
+R x/y
 
 diff --git a/a b/b
 rename from a
@@ -261,6 +304,12 @@
 +2
 +b1
 +w
+diff --git a/x/y b/x/y
+deleted file mode 100644
+--- a/x/y
++++ /dev/null
+@@ -1,1 +0,0 @@
+-y1
 
 - root to parent: --rev 0 --rev .
 A b
@@ -296,6 +345,7 @@
 A b
   a
 R a
+R x/y
 
 diff --git a/a b/b
 rename from a
@@ -308,10 +358,17 @@
 -m2
 +2
 +b1
+diff --git a/x/y b/x/y
+deleted file mode 100644
+--- a/x/y
++++ /dev/null
+@@ -1,1 +0,0 @@
+-y1
 
 - parent to branch: --rev . --rev 2
 A a
   b
+A x/y
 R b
 
 diff --git a/b b/a
@@ -325,6 +382,12 @@
 -b1
 +m1
 +m2
+diff --git a/x/y b/x/y
+new file mode 100644
+--- /dev/null
++++ b/x/y
+@@ -0,0 +1,1 @@
++y1
 
 
 created new head
@@ -367,6 +430,7 @@
 M a
 A b
   a
+R x/y
 
 diff --git a/a b/a
 --- a/a
@@ -388,6 +452,12 @@
 -m2
 +3
 +b1
+diff --git a/x/y b/x/y
+deleted file mode 100644
+--- a/x/y
++++ /dev/null
+@@ -1,1 +0,0 @@
+-y1
 
 - root to parent: --rev 0 --rev .
 M a
@@ -433,6 +503,7 @@
 M a
 A b
   a
+R x/y
 
 diff --git a/a b/a
 --- a/a
@@ -453,9 +524,16 @@
 -m2
 +3
 +b1
+diff --git a/x/y b/x/y
+deleted file mode 100644
+--- a/x/y
++++ /dev/null
+@@ -1,1 +0,0 @@
+-y1
 
 - parent to branch: --rev . --rev 2
 M a
+A x/y
 R b
 
 diff --git a/a b/a
@@ -474,6 +552,12 @@
 -a
 -3
 -b1
+diff --git a/x/y b/x/y
+new file mode 100644
+--- /dev/null
++++ b/x/y
+@@ -0,0 +1,1 @@
++y1
 
 
 created new head
@@ -506,6 +590,7 @@
 A d
   a
 R a
+R x/y
 
 diff --git a/a b/d
 rename from a
@@ -517,6 +602,12 @@
 -m1
 -m2
 +4
+diff --git a/x/y b/x/y
+deleted file mode 100644
+--- a/x/y
++++ /dev/null
+@@ -1,1 +0,0 @@
+-y1
 
 - root to parent: --rev 0 --rev .
 A c
@@ -550,6 +641,7 @@
 A c
   a
 R a
+R x/y
 
 diff --git a/a b/c
 rename from a
@@ -561,10 +653,17 @@
 -m1
 -m2
 +4
+diff --git a/x/y b/x/y
+deleted file mode 100644
+--- a/x/y
++++ /dev/null
+@@ -1,1 +0,0 @@
+-y1
 
 - parent to branch: --rev . --rev 2
 A a
   c
+A x/y
 R c
 
 diff --git a/c b/a
@@ -577,6 +676,12 @@
 -4
 +m1
 +m2
+diff --git a/x/y b/x/y
+new file mode 100644
+--- /dev/null
++++ b/x/y
+@@ -0,0 +1,1 @@
++y1
 
 
 created new head
@@ -638,6 +743,7 @@
   a
 A d
   a
+R x/y
 
 diff --git a/a b/a
 --- a/a
@@ -677,6 +783,12 @@
 -m1
 -m2
 +5
+diff --git a/x/y b/x/y
+deleted file mode 100644
+--- a/x/y
++++ /dev/null
+@@ -1,1 +0,0 @@
+-y1
 
 - root to parent: --rev 0 --rev .
 M a
@@ -740,6 +852,7 @@
   a
 A c
   a
+R x/y
 
 diff --git a/a b/a
 --- a/a
@@ -769,9 +882,16 @@
 -m1
 -m2
 +5
+diff --git a/x/y b/x/y
+deleted file mode 100644
+--- a/x/y
++++ /dev/null
+@@ -1,1 +0,0 @@
+-y1
 
 - parent to branch: --rev . --rev 2
 M a
+A x/y
 R b
 R c
 
@@ -797,6 +917,12 @@
 @@ -1,2 +0,0 @@
 -a
 -5
+diff --git a/x/y b/x/y
+new file mode 100644
+--- /dev/null
++++ b/x/y
+@@ -0,0 +1,1 @@
++y1
 
 
 created new head
@@ -824,6 +950,7 @@
 
 - working to branch: --rev 2
 M a
+R x/y
 
 diff --git a/a b/a
 --- a/a
@@ -834,6 +961,12 @@
 -m2
 +6
 +a1
+diff --git a/x/y b/x/y
+deleted file mode 100644
+--- a/x/y
++++ /dev/null
+@@ -1,1 +0,0 @@
+-y1
 
 - root to parent: --rev 0 --rev .
 A b
@@ -869,6 +1002,7 @@
 A b
   a
 R a
+R x/y
 
 diff --git a/a b/b
 rename from a
@@ -881,10 +1015,17 @@
 -m2
 +6
 +a1
+diff --git a/x/y b/x/y
+deleted file mode 100644
+--- a/x/y
++++ /dev/null
+@@ -1,1 +0,0 @@
+-y1
 
 - parent to branch: --rev . --rev 2
 A a
   b
+A x/y
 R b
 
 diff --git a/b b/a
@@ -898,5 +1039,182 @@
 -a1
 +m1
 +m2
+diff --git a/x/y b/x/y
+new file mode 100644
+--- /dev/null
++++ b/x/y
+@@ -0,0 +1,1 @@
++y1
 
 
+created new head
+moving x/x to y/x
+** directory move **
+** hg mv x y / add y/x x1 / add y/x x2
+- working to parent: 
+M y/x
+
+diff --git a/y/x b/y/x
+--- a/y/x
++++ b/y/x
+@@ -1,2 +1,3 @@
+ x
+ x1
++x2
+
+- working to root: --rev 0
+M a
+A y/x
+  x/x
+R x/x
+
+diff --git a/a b/a
+--- a/a
++++ b/a
+@@ -1,1 +1,2 @@
+ a
++7
+diff --git a/x/x b/y/x
+rename from x/x
+rename to y/x
+--- a/x/x
++++ b/y/x
+@@ -1,1 +1,3 @@
+ x
++x1
++x2
+
+- working to branch: --rev 2
+M a
+A y/x
+  x/x
+R x/x
+R x/y
+
+diff --git a/a b/a
+--- a/a
++++ b/a
+@@ -1,3 +1,2 @@
+ a
+-m1
+-m2
++7
+diff --git a/x/y b/x/y
+deleted file mode 100644
+--- a/x/y
++++ /dev/null
+@@ -1,1 +0,0 @@
+-y1
+diff --git a/x/x b/y/x
+rename from x/x
+rename to y/x
+--- a/x/x
++++ b/y/x
+@@ -1,1 +1,3 @@
+ x
++x1
++x2
+
+- root to parent: --rev 0 --rev .
+M a
+A y/x
+  x/x
+R x/x
+
+diff --git a/a b/a
+--- a/a
++++ b/a
+@@ -1,1 +1,2 @@
+ a
++7
+diff --git a/x/x b/y/x
+rename from x/x
+rename to y/x
+--- a/x/x
++++ b/y/x
+@@ -1,1 +1,2 @@
+ x
++x1
+
+- parent to root: --rev . --rev 0
+M a
+A x/x
+  y/x
+R y/x
+
+diff --git a/a b/a
+--- a/a
++++ b/a
+@@ -1,2 +1,1 @@
+ a
+-7
+diff --git a/y/x b/x/x
+rename from y/x
+rename to x/x
+--- a/y/x
++++ b/x/x
+@@ -1,2 +1,1 @@
+ x
+-x1
+
+- branch to parent: --rev 2 --rev .
+M a
+A y/x
+  x/x
+R x/x
+R x/y
+
+diff --git a/a b/a
+--- a/a
++++ b/a
+@@ -1,3 +1,2 @@
+ a
+-m1
+-m2
++7
+diff --git a/x/y b/x/y
+deleted file mode 100644
+--- a/x/y
++++ /dev/null
+@@ -1,1 +0,0 @@
+-y1
+diff --git a/x/x b/y/x
+rename from x/x
+rename to y/x
+--- a/x/x
++++ b/y/x
+@@ -1,1 +1,2 @@
+ x
++x1
+
+- parent to branch: --rev . --rev 2
+M a
+A x/x
+  y/x
+A x/y
+R y/x
+
+diff --git a/a b/a
+--- a/a
++++ b/a
+@@ -1,2 +1,3 @@
+ a
+-7
++m1
++m2
+diff --git a/y/x b/x/x
+rename from y/x
+rename to x/x
+--- a/y/x
++++ b/x/x
+@@ -1,2 +1,1 @@
+ x
+-x1
+diff --git a/x/y b/x/y
+new file mode 100644
+--- /dev/null
++++ b/x/y
+@@ -0,0 +1,1 @@
++y1
+
+