Merge with stable
authorMatt Mackall <mpm@selenic.com>
Thu, 03 May 2007 17:27:21 -0500
changeset 4404 47371e1c1db4
parent 4403 15289406f89c (current diff)
parent 4402 249e2603324c (diff)
child 4407 f97b89314fb3
Merge with stable
mercurial/merge.py
--- a/contrib/win32/win32-build.txt	Tue May 01 13:23:32 2007 -0700
+++ b/contrib/win32/win32-build.txt	Thu May 03 17:27:21 2007 -0500
@@ -4,7 +4,7 @@
 It has the following prerequisites, at least as I build it:
 
   Python for Windows
-      http://www.python.org/ftp/python/2.4.1/python-2.4.1.msi
+      http://www.python.org/ftp/python/2.4.3/python-2.4.3.msi
 
   MinGW
       http://www.mingw.org/
@@ -21,7 +21,7 @@
   Inno Setup
       http://www.jrsoftware.org/isinfo.php
 
-  ISTool
+  ISTool - optional
       http://www.istool.org/default.aspx/
 
   add_path (you need only add_path.exe in the zip file)
@@ -35,13 +35,37 @@
 
 In a shell, build a standalone copy of the hg.exe program:
 
-  python setup.py build -c mingw32 py2exe -b 1
+  python setup.py build -c mingw32 
+  python setup.py py2exe -b 1
+
+Note: the previously suggested combined command of "python setup.py build -c
+mingw32 py2exe -b 1" doesn't work correctly anymore as it doesn't include the
+extensions in the mercurial subdirectory.
 
-Copy mfc71.dll and add_path.exe into the dist directory that just
-got created.
+If you want to create a file named setup.cfg with the contents:
+
+[build]
+compiler=mingw32
+
+you can skip the first build step.
+
+Copy mfc71.dll and add_path.exe into the dist directory that just got created.
 
-Run ISTool, and open the C:\hg\hg-release\contrib\win32\mercurial.iss
-file.
+If you use ISTool, you open the C:\hg\hg-release\contrib\win32\mercurial.iss
+file and type Ctrl-F9 to compile the installer file.
+
+Otherwise you run the Inno Setup compiler.  Assuming it's on the path you run:
+
+  iscc contrib\win32\mercurial.iss
+
+The actual installer will be in the C:\hg\hg-release\Output directory.
 
-In ISTool, type Ctrl-F9 to compile the installer file.  The actual
-installer will be in the C:\hg\hg-release\Output directory.
+To automate the steps above you may want to create a batchfile based on the
+following:
+
+  echo [build] > setup.cfg
+  echo compiler=mingw32 >> setup.cfg
+  python setup.py py2exe -b 1
+  iscc contrib\win32\mercurial.iss
+
+and run it from the root of the hg repository (c:\hg\hg-release).
--- a/mercurial/merge.py	Tue May 01 13:23:32 2007 -0700
+++ b/mercurial/merge.py	Thu May 03 17:27:21 2007 -0500
@@ -102,6 +102,27 @@
     Find moves and copies between m1 and m2 back to limit linkrev
     """
 
+    def nonoverlap(d1, d2, d3):
+        "Return list of elements in d1 not in d2 or d3"
+        l = [d for d in d1 if d not in d3 and d not in d2]
+        l.sort()
+        return l
+
+    def dirname(f):
+        s = f.rfind("/")
+        if s == -1:
+            return ""
+        return f[:s]
+
+    def dirs(files):
+        d = {}
+        for f in files:
+            f = dirname(f)
+            while f not in d:
+                d[f] = True
+                f = dirname(f)
+        return d
+
     def findold(fctx):
         "find files that path was copied from, back to linkrev limit"
         old = {}
@@ -124,33 +145,25 @@
         old.sort()
         return old
 
-    def nonoverlap(d1, d2, d3):
-        "Return list of elements in d1 not in d2 or d3"
-        l = [d for d in d1 if d not in d3 and d not in d2]
-        l.sort()
-        return l
+    copy = {}
+    fullcopy = {}
 
     def checkcopies(c, man):
         '''check possible copies for filectx c'''
         for of in findold(c):
-            if of not in man:
+            if of not in man: # original file not in other manifest?
                 continue
             c2 = ctx(of, man[of])
             ca = c.ancestor(c2)
-            if not ca: # unrelated
+            if not ca: # unrelated?
                 continue
+            # named changed on only one side?
             if ca.path() == c.path() or ca.path() == c2.path():
-                fullcopy[c.path()] = of
-                if c == ca and c2 == ca: # no merge needed, ignore copy
+                fullcopy[c.path()] = of # remember for dir rename detection
+                if c == c2: # no merge needed, ignore copy
                     continue
                 copy[c.path()] = of
 
-    def dirs(files):
-        d = {}
-        for f in files:
-            d[os.path.dirname(f)] = True
-        return d
-
     if not repo.ui.configbool("merge", "followcopies", True):
         return {}
 
@@ -159,8 +172,6 @@
         return {}
 
     dcopies = repo.dirstate.copies()
-    copy = {}
-    fullcopy = {}
     u1 = nonoverlap(m1, m2, ma)
     u2 = nonoverlap(m2, m1, ma)
     ctx = util.cachefunc(lambda f, n: repo.filectx(f, fileid=n[:20]))
@@ -179,28 +190,41 @@
     invalid = {}
     dirmove = {}
 
+    # examine each file copy for a potential directory move, which is
+    # when all the files in a directory are moved to a new directory
     for dst, src in fullcopy.items():
-        dsrc, ddst = os.path.dirname(src), os.path.dirname(dst)
+        dsrc, ddst = dirname(src), dirname(dst)
         if dsrc in invalid:
+            # already seen to be uninteresting
             continue
-        elif (dsrc in d1 and ddst in d1) or (dsrc in d2 and ddst in d2):
+        elif dsrc in d1 and ddst in d1:
+            # directory wasn't entirely moved locally
+            invalid[dsrc] = True
+        elif dsrc in d2 and ddst in d2:
+            # directory wasn't entirely moved remotely
             invalid[dsrc] = True
         elif dsrc in dirmove and dirmove[dsrc] != ddst:
+            # files from the same directory moved to two different places
             invalid[dsrc] = True
-            del dirmove[dsrc]
         else:
+            # looks good so far
             dirmove[dsrc + "/"] = ddst + "/"
 
+    for i in invalid:
+        if i in dirmove:
+            del dirmove[i]
+
     del d1, d2, invalid
 
     if not dirmove:
         return copy
 
-    # check unaccounted nonoverlapping files
+    # check unaccounted nonoverlapping files against directory moves
     for f in u1 + u2:
         if f not in fullcopy:
             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):]
                     break