Bug 2342 - merging can sometimes revert newer changes back
Summary: merging can sometimes revert newer changes back
Status: RESOLVED FIXED
Alias: None
Product: Mercurial
Classification: Unclassified
Component: Mercurial (show other bugs)
Version: unspecified
Hardware: All All
: critical bug
Assignee: Matt Mackall
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-08-19 11:09 UTC by Boris Figovsky
Modified: 2010-10-05 16:34 UTC (History)
8 users (show)

See Also:
Python Version: ---


Attachments
(34 bytes, application/octet-stream)
2010-08-19 11:09 UTC, Boris Figovsky
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Boris Figovsky 2010-08-19 11:09 UTC
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...)
Comment 1 Boris Figovsky 2010-08-19 11:10 UTC
small correction: heads are 8 and 7...
Comment 2 kiilerix 2010-08-19 15:28 UTC
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?
Comment 3 Benoit Boissinot 2010-08-19 16:42 UTC
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.
Comment 4 Matt Mackall 2010-08-21 09:39 UTC
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..
Comment 5 HG Bot 2010-08-21 12:00 UTC
Fixed by http://hg.intevation.org/mercurial/crew/rev/fad5ed0ff997
Matt Mackall <mpm@selenic.com>
merge: move reverse-merge logic out of filemerge (issue2342)
Comment 6 Thomas Arendsen Hein 2010-09-06 13:58 UTC
issue2364 (Crash during update when working directory contains files of
target version) is caused by fad5ed0ff997.
Comment 7 hynekcer 2010-10-05 16:34 UTC
issue2422 (exception IndexError in update after revert)
is also caused by fad5ed0ff997.
Comment 8 Bugzilla 2012-05-12 09:11 UTC

--- 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)