diff --git a/mercurial/hg.py b/mercurial/hg.py --- a/mercurial/hg.py +++ b/mercurial/hg.py @@ -840,8 +840,30 @@ class localrepository: tm = util.is_exec(self.wjoin(f), mfm.get(f, False)) r = self.file(f) mfm[f] = tm - mm[f] = r.add(t, {}, tr, linkrev, - m1.get(f, nullid), m2.get(f, nullid)) + + fp1 = m1.get(f, nullid) + fp2 = m2.get(f, nullid) + + # is the same revision on two branches of a merge? + if fp2 == fp1: + fp2 = nullid + + if fp2 != nullid: + # is one parent an ancestor of the other? + fpa = r.ancestor(fp1, fp2) + if fpa == fp1: + fp1, fp2 = fp2, nullid + elif fpa == fp2: + fp2 = nullid + + # is the file unmodified from the parent? + if t == r.read(fp1): + # record the proper existing parent in manifest + # no need to add a revision + mm[f] = fp1 + continue + + mm[f] = r.add(t, {}, tr, linkrev, fp1, fp2) if update_dirstate: self.dirstate.update([f], "n") except IOError: @@ -879,19 +901,20 @@ class localrepository: commit = c + a remove = d - if not commit and not remove and not force: + p1, p2 = self.dirstate.parents() + c1 = self.changelog.read(p1) + c2 = self.changelog.read(p2) + m1 = self.manifest.read(c1[0]) + mf1 = self.manifest.readflags(c1[0]) + m2 = self.manifest.read(c2[0]) + + if not commit and not remove and not force and p2 == nullid: self.ui.status("nothing changed\n") return None if not self.hook("precommit"): return None - p1, p2 = self.dirstate.parents() - c1 = self.changelog.read(p1) - c2 = self.changelog.read(p2) - m1 = self.manifest.read(c1[0]) - mf1 = self.manifest.readflags(c1[0]) - m2 = self.manifest.read(c2[0]) lock = self.lock() tr = self.transaction() @@ -918,6 +941,26 @@ class localrepository: r = self.file(f) fp1 = m1.get(f, nullid) fp2 = m2.get(f, nullid) + + # is the same revision on two branches of a merge? + if fp2 == fp1: + fp2 = nullid + + if fp2 != nullid: + # is one parent an ancestor of the other? + fpa = r.ancestor(fp1, fp2) + if fpa == fp1: + fp1, fp2 = fp2, nullid + elif fpa == fp2: + fp2 = nullid + + # is the file unmodified from the parent? + if not meta and t == r.read(fp1): + # record the proper existing parent in manifest + # no need to add a revision + new[f] = fp1 + continue + new[f] = r.add(t, meta, tr, linkrev, fp1, fp2) # update manifest @@ -1715,12 +1758,7 @@ class localrepository: self.ui.status("(use update -m to merge across branches" + " or -C to lose changes)\n") return 1 - # we have to remember what files we needed to get/change - # because any file that's different from either one of its - # parents must be in the changeset mode = 'm' - if moddirstate: - self.dirstate.update(mark.keys(), "m") if moddirstate: self.dirstate.setparents(p1, p2) @@ -1739,7 +1777,7 @@ class localrepository: self.wfile(f, "w").write(t) util.set_exec(self.wjoin(f), mf2[f]) if moddirstate: - self.dirstate.update([f], mode) + self.dirstate.update([f], 'n') # merge the tricky bits files = merge.keys() diff --git a/tests/test-filebranch b/tests/test-filebranch new file mode 100755 --- /dev/null +++ b/tests/test-filebranch @@ -0,0 +1,73 @@ +#!/bin/sh + +# This test makes sure that we don't mark a file as merged with its ancestor +# when we do a merge. + +cat <<'EOF' > merge +#!/bin/sh +echo merging for `basename $1` +EOF +chmod +x merge + +echo creating base +hg init a +cd a +echo 1 > foo +echo 1 > bar +echo 1 > baz +echo 1 > quux +hg add foo bar baz quux +hg commit -m "base" -d "0 0" + +cd .. +hg clone a b + +echo creating branch a +cd a +echo 2a > foo +echo 2a > bar +hg commit -m "branch a" -d "0 0" + +echo creating branch b + +cd .. +cd b +echo 2b > foo +echo 2b > baz +hg commit -m "branch b" -d "0 0" + +echo "we shouldn't have anything but n state here" +hg debugstate | cut -b 1-16,35- + +echo merging +hg pull ../a +env HGMERGE=../merge hg update -vm --debug + +echo 2m > foo +echo 2b > baz +echo new > quux + +echo "we shouldn't have anything but foo in merge state here" +hg debugstate | cut -b 1-16,35- | grep "^m" + +hg ci -m "merge" -d "0 0" + +echo "main: we should have a merge here" +hg debugindex .hg/00changelog.i + +echo "foo: we should have a merge here" +hg debugindex .hg/data/foo.i + +echo "bar: we shouldn't have a merge here" +hg debugindex .hg/data/bar.i + +echo "baz: we shouldn't have a merge here" +hg debugindex .hg/data/baz.i + +echo "quux: we shouldn't have a merge here" +hg debugindex .hg/data/quux.i + +echo "everything should be clean now" +hg status + +hg verify diff --git a/tests/test-filebranch.out b/tests/test-filebranch.out new file mode 100644 --- /dev/null +++ b/tests/test-filebranch.out @@ -0,0 +1,58 @@ +creating base +creating branch a +creating branch b +we shouldn't have anything but n state here +n 644 2 bar +n 644 3 baz +n 644 3 foo +n 644 2 quux +merging +pulling from ../a +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 2 changes to 2 files +(run 'hg update' to get a working copy) +merging for foo +resolving manifests + force None allow 1 moddirstate True linear False + ancestor a0486579db29 local ef1b4dbe2193 remote 336d8406d617 + remote bar is newer, get + foo versions differ, resolve +getting bar +merging foo +resolving foo +file foo: other 33d1fb69067a ancestor b8e02f643373 +we shouldn't have anything but foo in merge state here +m 644 3 foo +main: we should have a merge here + rev offset length base linkrev nodeid p1 p2 + 0 0 73 0 0 cdca01651b96 000000000000 000000000000 + 1 73 68 1 1 f6718a9cb7f3 cdca01651b96 000000000000 + 2 141 68 2 2 bdd988058d16 cdca01651b96 000000000000 + 3 209 66 3 3 9da9fbd62226 f6718a9cb7f3 bdd988058d16 +foo: we should have a merge here + rev offset length base linkrev nodeid p1 p2 + 0 0 3 0 0 b8e02f643373 000000000000 000000000000 + 1 3 4 1 1 2ffeddde1b65 b8e02f643373 000000000000 + 2 7 4 2 2 33d1fb69067a b8e02f643373 000000000000 + 3 11 4 3 3 aa27919ee430 2ffeddde1b65 33d1fb69067a +bar: we shouldn't have a merge here + rev offset length base linkrev nodeid p1 p2 + 0 0 3 0 0 b8e02f643373 000000000000 000000000000 + 1 3 4 1 2 33d1fb69067a b8e02f643373 000000000000 +baz: we shouldn't have a merge here + rev offset length base linkrev nodeid p1 p2 + 0 0 3 0 0 b8e02f643373 000000000000 000000000000 + 1 3 4 1 1 2ffeddde1b65 b8e02f643373 000000000000 +quux: we shouldn't have a merge here + rev offset length base linkrev nodeid p1 p2 + 0 0 3 0 0 b8e02f643373 000000000000 000000000000 + 1 3 5 1 3 6128c0f33108 b8e02f643373 000000000000 +everything should be clean now +checking changesets +checking manifests +crosschecking files in changesets and manifests +checking files +4 files, 4 changesets, 10 total revisions diff --git a/tests/test-merge6.out b/tests/test-merge6.out --- a/tests/test-merge6.out +++ b/tests/test-merge6.out @@ -6,7 +6,7 @@ adding file changes added 1 changesets with 1 changes to 1 files (run 'hg update' to get a working copy) bar should remain deleted. -6b70e9e451a5a33faad7bbebe627e46b937b7364 644 foo +f405ac83a5611071d6b54dd5eb26943b1fdc4460 644 foo pulling from ../A2 searching for changes adding changesets @@ -15,4 +15,4 @@ adding file changes added 1 changesets with 0 changes to 0 files (run 'hg update' to get a working copy) bar should remain deleted. -6b70e9e451a5a33faad7bbebe627e46b937b7364 644 foo +f9b0e817f6a48de3564c6b2957687c5e7297c5a0 644 foo diff --git a/tests/test-push-warn.out b/tests/test-push-warn.out --- a/tests/test-push-warn.out +++ b/tests/test-push-warn.out @@ -18,4 +18,4 @@ searching for changes adding changesets adding manifests adding file changes -added 2 changesets with 2 changes to 2 files +added 2 changesets with 1 changes to 1 files diff --git a/tests/test-tags.out b/tests/test-tags.out --- a/tests/test-tags.out +++ b/tests/test-tags.out @@ -10,6 +10,4 @@ acb14030fe0a+ first acb14030fe0a21b60322c440ad2d20cf7685a376+ first M a c8edf04160c7 tip -c8edf04160c7+b9154636be93+ tip -M .hgtags -M a +c8edf04160c7+b9154636be93 tip