filecommit: don't forget the local parent on a merge with a local rename
authorAlexis S. L. Carvalho <alexis@cecm.usp.br>
Tue, 30 Jan 2007 19:09:08 -0200
changeset 4058 e7282dede8cd
parent 4057 3600b84656d3
child 4059 431f3c1d3a37
child 4063 96863fc3036a
filecommit: don't forget the local parent on a merge with a local rename
mercurial/localrepo.py
tests/test-merge-commit
tests/test-merge-commit.out
--- a/mercurial/localrepo.py	Tue Jan 30 18:32:23 2007 -0200
+++ b/mercurial/localrepo.py	Tue Jan 30 19:09:08 2007 -0200
@@ -607,6 +607,24 @@
         meta = {}
         cp = self.dirstate.copied(fn)
         if cp:
+            # Mark the new revision of this file as a copy of another
+            # file.  This copy data will effectively act as a parent 
+            # of this new revision.  If this is a merge, the first 
+            # parent will be the nullid (meaning "look up the copy data")
+            # and the second one will be the other parent.  For example:
+            #
+            # 0 --- 1 --- 3   rev1 changes file foo
+            #   \       /     rev2 renames foo to bar and changes it
+            #    \- 2 -/      rev3 should have bar with all changes and
+            #                      should record that bar descends from
+            #                      bar in rev2 and foo in rev1
+            #
+            # this allows this merge to succeed:
+            #
+            # 0 --- 1 --- 3   rev4 reverts the content change from rev2
+            #   \       /     merging rev3 and rev4 should use bar@rev2
+            #    \- 2 --- 4        as the merge base
+            #
             meta["copy"] = cp
             if not manifest2: # not a branch merge
                 meta["copyrev"] = hex(manifest1.get(cp, nullid))
@@ -615,7 +633,7 @@
                 meta["copyrev"] = hex(manifest1.get(cp, nullid))
             elif fp1 != nullid: # copied on local side, reversed
                 meta["copyrev"] = hex(manifest2.get(cp))
-                fp2 = nullid
+                fp2 = fp1
             else: # directory rename
                 meta["copyrev"] = hex(manifest1.get(cp, nullid))
             self.ui.debug(_(" %s: copy %s:%s\n") %
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-merge-commit	Tue Jan 30 19:09:08 2007 -0200
@@ -0,0 +1,77 @@
+#!/bin/sh
+# check that renames are correctly saved by a commit after a merge
+
+HGMERGE=merge
+export HGMERGE
+
+# test with the merge on 3 having the rename on the local parent
+hg init a
+cd a
+
+echo line1 > foo
+hg add foo
+hg ci -m '0: add foo' -d '0 0'
+
+echo line2 >> foo
+hg ci -m '1: change foo' -d '0 0'
+
+hg up -C 0
+hg mv foo bar
+rm bar
+echo line0 > bar
+echo line1 >> bar
+hg ci -m '2: mv foo bar; change bar' -d '0 0'
+
+hg merge 1
+echo '% contents of bar should be line0 line1 line2'
+cat bar
+hg ci -m '3: merge with local rename' -d '0 0'
+hg debugindex .hg/store/data/bar.i
+hg debugrename bar
+hg debugindex .hg/store/data/foo.i
+
+# revert the content change from rev 2
+hg up -C 2
+rm bar
+echo line1 > bar
+hg ci -m '4: revert content change from rev 2' -d '0 0'
+
+hg log --template '#rev#:#node|short# #parents#\n'
+echo '% this should use bar@rev2 as the ancestor'
+hg --debug merge 3
+echo '% contents of bar should be line1 line2'
+cat bar
+hg ci -m '5: merge' -d '0 0'
+hg debugindex .hg/store/data/bar.i
+
+
+# same thing, but with the merge on 3 having the rename on the remote parent
+echo
+echo
+cd ..
+hg clone -U -r 1 -r 2 a b
+cd b
+
+hg up -C 1
+hg merge 2
+echo '% contents of bar should be line0 line1 line2'
+cat bar
+hg ci -m '3: merge with remote rename' -d '0 0'
+hg debugindex .hg/store/data/bar.i
+hg debugrename bar
+hg debugindex .hg/store/data/foo.i
+
+# revert the content change from rev 2
+hg up -C 2
+rm bar
+echo line1 > bar
+hg ci -m '4: revert content change from rev 2' -d '0 0'
+
+hg log --template '#rev#:#node|short# #parents#\n'
+echo '% this should use bar@rev2 as the ancestor'
+hg --debug merge 3
+echo '% contents of bar should be line1 line2'
+cat bar
+hg ci -m '5: merge' -d '0 0'
+hg debugindex .hg/store/data/bar.i
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-merge-commit.out	Tue Jan 30 19:09:08 2007 -0200
@@ -0,0 +1,83 @@
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+merging bar and foo
+0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+% contents of bar should be line0 line1 line2
+line0
+line1
+line2
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0      77      0       2 da78c0659611 000000000000 000000000000
+     1        77      76      0       3 4b358025380b 000000000000 da78c0659611
+bar renamed from foo:9e25c27b87571a1edee5ae4dddee5687746cc8e2
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0       7      0       0 690b295714ae 000000000000 000000000000
+     1         7      13      1       1 9e25c27b8757 690b295714ae 000000000000
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+4:2d2f9a22c82b 2:0a3ab4856510 
+3:7d3b554bfdf1 2:0a3ab4856510 1:5cd961e4045d 
+2:0a3ab4856510 0:2665aaee66e9 
+1:5cd961e4045d 
+0:2665aaee66e9 
+% this should use bar@rev2 as the ancestor
+resolving manifests
+ overwrite None partial False
+ ancestor 0a3ab4856510 local 2d2f9a22c82b+ remote 7d3b554bfdf1
+ bar: versions differ -> m
+merging bar
+my bar@2d2f9a22c82b+ other bar@7d3b554bfdf1 ancestor bar@0a3ab4856510
+0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+% contents of bar should be line1 line2
+line1
+line2
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0      77      0       2 da78c0659611 000000000000 000000000000
+     1        77      76      0       3 4b358025380b 000000000000 da78c0659611
+     2       153       7      2       4 4defe5eec418 da78c0659611 000000000000
+     3       160      13      3       5 4663501da27b 4defe5eec418 4b358025380b
+
+
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 3 changesets with 3 changes to 2 files (+1 heads)
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+merging foo and bar
+0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+% contents of bar should be line0 line1 line2
+line0
+line1
+line2
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0      77      0       2 da78c0659611 000000000000 000000000000
+     1        77      76      0       3 4b358025380b 000000000000 da78c0659611
+bar renamed from foo:9e25c27b87571a1edee5ae4dddee5687746cc8e2
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0       7      0       0 690b295714ae 000000000000 000000000000
+     1         7      13      1       1 9e25c27b8757 690b295714ae 000000000000
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+4:2d2f9a22c82b 2:0a3ab4856510 
+3:96ab80c60897 1:5cd961e4045d 2:0a3ab4856510 
+2:0a3ab4856510 0:2665aaee66e9 
+1:5cd961e4045d 
+0:2665aaee66e9 
+% this should use bar@rev2 as the ancestor
+resolving manifests
+ overwrite None partial False
+ ancestor 0a3ab4856510 local 2d2f9a22c82b+ remote 96ab80c60897
+ bar: versions differ -> m
+merging bar
+my bar@2d2f9a22c82b+ other bar@96ab80c60897 ancestor bar@0a3ab4856510
+0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+% contents of bar should be line1 line2
+line1
+line2
+   rev    offset  length   base linkrev nodeid       p1           p2
+     0         0      77      0       2 da78c0659611 000000000000 000000000000
+     1        77      76      0       3 4b358025380b 000000000000 da78c0659611
+     2       153       7      2       4 4defe5eec418 da78c0659611 000000000000
+     3       160      13      3       5 4663501da27b 4defe5eec418 4b358025380b