merge with upstream
authorThomas Arendsen Hein <thomas@intevation.de>
Thu, 05 Oct 2006 10:07:40 +0200
changeset 3259 53d6bcccdbef
parent 3258 03acd01520ac (current diff)
parent 3251 c93ce7f10f85 (diff)
child 3266 03880d4e2550
merge with upstream
--- a/mercurial/commands.py	Thu Oct 05 00:14:21 2006 +0200
+++ b/mercurial/commands.py	Thu Oct 05 10:07:40 2006 +0200
@@ -2532,8 +2532,7 @@
 
         for f in changes:
             ui.write(format % f)
-            if ((all or opts.get('copies')) and not opts.get('no_status')
-                and opt == 'added'):
+            if ((all or opts.get('copies')) and not opts.get('no_status')):
                 copied = repo.dirstate.copied(f)
                 if copied:
                     ui.write('  %s%s' % (copied, end))
--- a/mercurial/merge.py	Thu Oct 05 00:14:21 2006 +0200
+++ b/mercurial/merge.py	Thu Oct 05 10:07:40 2006 +0200
@@ -54,6 +54,13 @@
                              'HG_OTHER_NODE': p2})
     if r:
         repo.ui.warn(_("merging %s failed!\n") % fw)
+    else:
+        if fd != fw:
+            repo.ui.debug(_("copying %s to %s\n") % (fw, fd))
+            repo.wwrite(fd, repo.wread(fw))
+            if move:
+                repo.ui.debug(_("removing %s\n") % fw)
+                os.unlink(a)
 
     os.unlink(b)
     os.unlink(c)
@@ -126,6 +133,9 @@
     Find moves and copies between m1 and m2 back to limit linkrev
     """
 
+    if not repo.ui.config("merge", "followcopies"):
+        return {}
+
     # avoid silly behavior for update from empty dir
     if not m1:
         return {}
@@ -141,7 +151,7 @@
         ''' check if an apparent pair actually matches '''
         c2 = ctx(f2, man[f2])
         ca = c.ancestor(c2)
-        if ca:
+        if ca and ca.path() == c.path() or ca.path() == c2.path():
             copy[c.path()] = f2
             copy[f2] = c.path()
 
@@ -164,19 +174,17 @@
 
     return copy
 
-def filtermanifest(man, partial):
-    if partial:
-        for k in man.keys():
-            if not partial(k): del man[k]
-
-def manifestmerge(ui, m1, m2, ma, overwrite, backwards):
+def manifestmerge(ui, m1, m2, ma, copy, overwrite, backwards, partial):
     """
     Merge manifest m1 with m2 using ancestor ma and generate merge action list
     """
 
-    def fmerge(f):
+    def fmerge(f, f2=None, fa=None):
         """merge executable flags"""
-        a, b, c = ma.execf(f), m1.execf(f), m2.execf(f)
+        if not f2:
+            f2 = f
+            fa = f
+        a, b, c = ma.execf(fa), m1.execf(f), m2.execf(f2)
         return ((a^b) | (a^c)) ^ a
 
     action = []
@@ -187,6 +195,8 @@
 
     # Compare manifests
     for f, n in m1.iteritems():
+        if partial and not partial(f):
+            continue
         if f in m2:
             # are files different?
             if n != m2[f]:
@@ -206,7 +216,18 @@
             elif m1.execf(f) != m2.execf(f):
                 if overwrite or fmerge(f) != m1.execf(f):
                     act("update permissions", f, "e", m2.execf(f))
-            del m2[f]
+        elif f in copy:
+            f2 = copy[f]
+            if f in ma: # case 3,20 A/B/A
+                act("remote moved",
+                    f, "c", f2, f2, m1[f], m2[f2], fmerge(f, f2, f), True)
+            else:
+                if f2 in m1: # case 2 A,B/B/B
+                    act("local copied",
+                        f, "c", f2, f, m1[f], m2[f2], fmerge(f, f2, f2), False)
+                else: # case 4,21 A/B/B
+                    act("local moved",
+                        f, "c", f2, f, m1[f], m2[f2], fmerge(f, f2, f2), False)
         elif f in ma:
             if n != ma[f] and not overwrite:
                 if ui.prompt(
@@ -221,7 +242,18 @@
                 act("remote deleted", f, "r")
 
     for f, n in m2.iteritems():
-        if f in ma:
+        if partial and not partial(f):
+            continue
+        if f in m1:
+            continue
+        if f in copy:
+            f2 = copy[f]
+            if f2 in ma or f2 in m1: # already seen
+                continue
+            # rename case 1, A/A,B/A
+            act("remote copied",
+                f, "c", f2, f, m1[f2], m2[f], fmerge(f2, f, f2), False)
+        elif f in ma:
             if overwrite or backwards:
                 act("recreating", f, "g", m2.execf(f), n)
             elif n != ma[f]:
@@ -251,6 +283,12 @@
                     repo.ui.warn(_("update failed to remove %s: %s!\n") %
                                  (f, inst.strerror))
             removed +=1
+        elif m == "c": # copy
+            f2, fd, my, other, flag, move = a[2:]
+            if filemerge(repo, f, f2, fd, my, other, xp1, xp2, move):
+                unresolved += 1
+            util.set_exec(repo.wjoin(fd), flag)
+            merged += 1
         elif m == "m": # merge
             flag, my, other = a[2:]
             repo.ui.status(_("merging %s\n") % f)
@@ -301,6 +339,25 @@
                 fl = repo.file(f)
                 f_len = fl.size(fl.rev(other))
                 repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
+        elif m == "c": # copy
+            f2, fd, my, other, flag, move = a[2:]
+            if branchmerge:
+                # We've done a branch merge, mark this file as merged
+                # so that we properly record the merger later
+                repo.dirstate.update([fd], 'm')
+            else:
+                # We've update-merged a locally modified file, so
+                # we set the dirstate to emulate a normal checkout
+                # of that file some time in the past. Thus our
+                # merge will appear as a normal local file
+                # modification.
+                fl = repo.file(f)
+                f_len = fl.size(fl.rev(other))
+                repo.dirstate.update([fd], 'n', st_size=f_len, st_mtime=-1)
+            if move:
+                repo.dirstate.update([f], 'r')
+            if f != fd:
+                repo.dirstate.copy(f, fd)
 
 def update(repo, node, branchmerge=False, force=False, partial=None,
            wlock=None, show_stats=True, remind=True):
@@ -337,8 +394,8 @@
         if wc.modified() or wc.added() or wc.removed():
             raise util.Abort(_("outstanding uncommitted changes"))
 
-    m1 = wc.manifest().copy()
-    m2 = p2.manifest().copy()
+    m1 = wc.manifest()
+    m2 = p2.manifest()
     ma = pa.manifest()
 
     # resolve the manifest to determine which files
@@ -351,9 +408,6 @@
     action = []
     copy = {}
 
-    filtermanifest(m1, partial)
-    filtermanifest(m2, partial)
-
     if not force:
         checkunknown(repo, m2, wc)
     if not branchmerge:
@@ -361,8 +415,8 @@
     if not (backwards or overwrite):
         copy = findcopies(repo, m1, m2, pa.rev())
 
-    action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards)
-    del m1, m2, ma
+    action += manifestmerge(repo.ui, m1, m2, ma, copy,
+                            overwrite, backwards, partial)
 
     ### apply phase
 
--- a/tests/test-rename-merge1	Thu Oct 05 00:14:21 2006 +0200
+++ b/tests/test-rename-merge1	Thu Oct 05 10:07:40 2006 +0200
@@ -3,6 +3,8 @@
 mkdir t
 cd t
 hg init
+echo "[merge]" >> .hg/hgrc
+echo "followcopies = 1" >> .hg/hgrc
 echo foo > a
 echo foo > a2
 hg add a a2
@@ -18,6 +20,6 @@
 hg ci -m "modify" -d "0 0"
 echo "merge"
 hg merge -y --debug
-cat a
+hg status -AC
 cat b
 hg ci -m "merge" -d "0 0"
--- a/tests/test-rename-merge1.out	Thu Oct 05 00:14:21 2006 +0200
+++ b/tests/test-rename-merge1.out	Thu Oct 05 10:07:40 2006 +0200
@@ -4,11 +4,18 @@
 resolving manifests
  overwrite None branchmerge True partial False
  ancestor f26ec4fc3fa3 local 8e765a822af2 remote af1939970a1c
- b: remote created -> g
+ a: remote moved -> c
  b2: remote created -> g
-getting b
+resolving a
+my a@f26ec4fc3fa3 other b@8e765a822af2 ancestor a@af1939970a1c
+copying a to b
+removing a
 getting b2
-2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+1 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
+M b
+  a
+M b2
+R a
+C c2
 blahblah
-foo