The attached file is a bundle of a simple repository. - Heads are revisions 9 and 8; - a_file was added in Rev 3 with contents AAA; - a_file's content changed to BBB in Rev 6; - Rev 7 is a merge with Rev 3, and thus has AAA in a_file; - Rev 8 is a merge with Rev 6, and thus has BBB in b_file; After unbundling, do the following: $ hg up -r 8 and: $ hg merge 7 says 'merging a_file' a_file's content is now AAA, but BBB is a descendant of AAA! Therefore, the BBB version is 'lost'. This bug can be reproduced with 1.6.2, 1.6.1 and 1.5.4 (other versions were not checked...)
small correction: heads are 8 and 7...
The repository has two possible ancestors: rev 2 and rev 3, and Mercurial has to choose one - and that is rev 2. a_file did however not exist in rev 2, so a_file should be merged based on the other ancestor, rev 3. But for some reason mercurial merges a_file based on rev 6, and that seems wrong. Thus, when a_file contained BBB in the ancestor and in one tip then the other tip containing AAA must be the most interesting change and wins. The "wrong" choice of ancestor was introduced with 6f1894d6a6b0 "filemerge: use working dir parent as ancestor for backward wdir merge", perhaps tricked by the custom cmp operator for filectx?
Because we don't pick the right changelog-level ancestor, we don't see that local is simply newer than remote. Instead we mark the file as "needs to be merged" (which is wrong). Then the code for file-level merge thinks it's a backward update instead and does the wrong thing.
I took a peek at this. If we look at the revisions reported by merge --debug at the top level and check their manifests, we see: ancestor 89e2984f9f71 local e2a65692fdff+ remote 6752a305d109 ... my a_file@e2a65692fdff+ other a_file@6752a305d109 ancestor a_file@33ef31d354f2 That's: revision contents merge used local 8:e2a6 "BBB" 8:e2a6 "BBB" other 7:6752 "AAA" 7:6752 "AAA" ancestor 2:89e29 none 6:33ef "BBB" That is, if we'd done a 'standard' three-way merge, we would have gotten a conflict, but filemerge tried to be smarter than that and got confused. That result looks a little ridiculous: 6 is not an ancestor of 8 and 7: @ 8:e2a65692fdff |\ | | @ 7:6752a305d109 | | |\ | o | | 6:33ef31d354f2 | |/ / | | o 5:703a264ca997 | | | o---+ 4:74c5a007f643 / / o | 3:5f327c854c02 | | | o 2:89e2984f9f71 |/ o 1:ba8afaa6d9bd | o 0:34a32141761a Adding a strategic print statement in merge:applyupdates shows us: using a_file@e2a65692fdff+ a_file@6752a305d109 a_file@5f327c854c02 That's rev 3 we should be using, with contents "AAA"! And this all gets passed down correctly to filemerge, which decides: if fca == fco: # backwards, use working dir parent as ancestor fca = fcd.parents()[0] This is a bit of a layering violation. Filemerge shouldn't be trying to make these decisions - they should all be getting made before we add things to the resolve state. Filemerge doesn't have enough information to be making these sorts of decisions. (Also, == here is doing something not quite right. It's using the file level hash for comparison and deciding that fca does equal fco even though the file contexts are from different csets. And that's where the bug actually comes from. But the whole check is wrong to start with.) Patch in stable shortly..
Fixed by http://hg.intevation.org/mercurial/crew/rev/fad5ed0ff997 Matt Mackall <mpm@selenic.com> merge: move reverse-merge logic out of filemerge (issue2342)
issue2364 (Crash during update when working directory contains files of target version) is caused by fad5ed0ff997.
issue2422 (exception IndexError in update after revert) is also caused by fad5ed0ff997.
--- Bug imported by bugzilla@serpentine.com 2012-05-12 09:11 EDT --- This bug was previously known as _bug_ 2342 at http://mercurial.selenic.com/bts/issue2342 Imported an attachment (id=1444)