changeset 3164:ca00ce41a2e8

Merge with crew
author Matt Mackall <mpm@selenic.com>
date Mon, 25 Sep 2006 22:26:54 -0500
parents 56c59ba7aa76 (diff) 4fe41a9e4591 (current diff)
children e43fd1623fe1
files
diffstat 5 files changed, 129 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/context.py	Sun Sep 24 13:52:27 2006 +0200
+++ b/mercurial/context.py	Mon Sep 25 22:26:54 2006 -0500
@@ -124,7 +124,7 @@
             raise AttributeError, name
 
     def __repr__(self):
-        return "<filectx %s:%s>" % (self.path(), short(self.node()))
+        return "<filectx %s@%s>" % (self.path(), short(self.node()))
 
     def filerev(self): return self._filerev
     def filenode(self): return self._filenode
--- a/mercurial/dirstate.py	Sun Sep 24 13:52:27 2006 +0200
+++ b/mercurial/dirstate.py	Mon Sep 25 22:26:54 2006 -0500
@@ -23,7 +23,7 @@
         self.map = None
         self.pl = None
         self.dirs = None
-        self.copies = {}
+        self.copymap = {}
         self.ignorefunc = None
         self.blockignore = False
 
@@ -160,7 +160,7 @@
 
         # deref fields so they will be local in loop
         map = self.map
-        copies = self.copies
+        copymap = self.copymap
         format = self.format
         unpack = struct.unpack
 
@@ -176,7 +176,7 @@
             f = st[pos:newpos]
             if '\0' in f:
                 f, c = f.split('\0')
-                copies[f] = c
+                copymap[f] = c
             map[f] = e[:4]
             pos = newpos
 
@@ -193,10 +193,13 @@
     def copy(self, source, dest):
         self.lazyread()
         self.markdirty()
-        self.copies[dest] = source
+        self.copymap[dest] = source
 
     def copied(self, file):
-        return self.copies.get(file, None)
+        return self.copymap.get(file, None)
+
+    def copies(self):
+        return self.copymap
 
     def initdirs(self):
         if self.dirs is None:
@@ -254,8 +257,8 @@
                 st_size = kw.get('st_size', s.st_size)
                 st_mtime = kw.get('st_mtime', s.st_mtime)
                 self.map[f] = (state, s.st_mode, st_size, st_mtime)
-            if self.copies.has_key(f):
-                del self.copies[f]
+            if self.copymap.has_key(f):
+                del self.copymap[f]
 
     def forget(self, files):
         if not files: return
@@ -272,7 +275,7 @@
 
     def clear(self):
         self.map = {}
-        self.copies = {}
+        self.copymap = {}
         self.dirs = None
         self.markdirty()
 
--- a/mercurial/merge.py	Sun Sep 24 13:52:27 2006 +0200
+++ b/mercurial/merge.py	Mon Sep 25 22:26:54 2006 -0500
@@ -63,10 +63,11 @@
     Update manifest to correspond to the working directory
     """
 
+    copied = repo.dirstate.copies()
     modified, added, removed, deleted, unknown = status[:5]
     for i,l in (("a", added), ("m", modified), ("u", unknown)):
         for f in l:
-            man[f] = man.get(f, nullid) + i
+            man[f] = man.get(copied.get(f, f), nullid) + i
             man.set(f, util.is_exec(repo.wjoin(f), man.execf(f)))
 
     for f in deleted + removed:
@@ -94,6 +95,78 @@
 
     return action
 
+def nonoverlap(d1, d2):
+    """
+    Return list of elements in d1 not in d2
+    """
+
+    l = []
+    for d in d1:
+        if d not in d2:
+            l.append(d)
+
+    l.sort()
+    return l
+
+def findold(fctx, limit):
+    """
+    find files that path was copied from, back to linkrev limit
+    """
+
+    old = {}
+    orig = fctx.path()
+    visit = [fctx]
+    while visit:
+        fc = visit.pop()
+        if fc.rev() < limit:
+            continue
+        if fc.path() != orig and fc.path() not in old:
+            old[fc.path()] = 1
+        visit += fc.parents()
+
+    old = old.keys()
+    old.sort()
+    return old
+
+def findcopies(repo, m1, m2, limit):
+    """
+    Find moves and copies between m1 and m2 back to limit linkrev
+    """
+
+    dcopies = repo.dirstate.copies()
+    copy = {}
+    match = {}
+    u1 = nonoverlap(m1, m2)
+    u2 = nonoverlap(m2, m1)
+    ctx = util.cachefunc(lambda f,n: repo.filectx(f, fileid=n[:20]))
+
+    def checkpair(c, f2, man):
+        ''' check if an apparent pair actually matches '''
+        c2 = ctx(f2, man[f2])
+        ca = c.ancestor(c2)
+        if ca:
+            copy[c.path()] = f2
+            copy[f2] = c.path()
+
+    for f in u1:
+        c = ctx(dcopies.get(f, f), m1[f])
+        for of in findold(c, limit):
+            if of in m2:
+                checkpair(c, of, m2)
+            else:
+                match.setdefault(of, []).append(f)
+
+    for f in u2:
+        c = ctx(f, m2[f])
+        for of in findold(c, limit):
+            if of in m1:
+                checkpair(c, of, m1)
+            elif of in match:
+                for mf in match[of]:
+                    checkpair(c, mf, m1)
+
+    return copy
+
 def manifestmerge(ui, m1, m2, ma, overwrite, backwards, partial):
     """
     Merge manifest m1 with m2 using ancestor ma and generate merge action list
@@ -283,12 +356,18 @@
                   (short(p1), short(p2), short(pa)))
 
     action = []
+
+    copy = {}
+    if not (backwards or overwrite):
+        copy = findcopies(repo, m1, m2, repo.changelog.rev(pa))
+
     m1 = workingmanifest(repo, m1, status)
 
     if not force:
         checkunknown(repo, m2, status)
     if not branchmerge:
         action += forgetremoved(m2, status)
+
     action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards, partial)
     del m1, m2, ma
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-rename-merge1	Mon Sep 25 22:26:54 2006 -0500
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+mkdir t
+cd t
+hg init
+echo foo > a
+echo foo > a2
+hg add a a2
+hg ci -m "start" -d "0 0"
+hg mv a b
+hg mv a2 b2
+hg ci -m "rename" -d "0 0"
+echo "checkout"
+hg co 0
+echo blahblah > a
+echo blahblah > a2
+hg mv a2 c2
+hg ci -m "modify" -d "0 0"
+echo "merge"
+hg merge -y --debug
+cat a
+cat b
+hg ci -m "merge" -d "0 0"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-rename-merge1.out	Mon Sep 25 22:26:54 2006 -0500
@@ -0,0 +1,14 @@
+checkout
+2 files updated, 0 files merged, 2 files removed, 0 files unresolved
+merge
+resolving manifests
+ overwrite None branchmerge True partial False
+ ancestor f26ec4fc3fa3 local 8e765a822af2 remote af1939970a1c
+ b: remote created -> g
+ b2: remote created -> g
+getting b
+getting b2
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+blahblah
+foo