mercurialmergeancestor

Merge problems in mercurial because of wrong merge base: what's happening?


I have a repository in which two revisions (14321 and 14319) share a parent (14318) - both changesets are direct children of 14318. Nevertheless, the revision set query ancestor(14321, 14319) does not return 14318, but instead returns a much older changeset. What's happening?

Screenshot in TortoiseHg:

A diagram showing the odd results of query ancestor(14321, 14319)

Background: I encountered odd merge conflicts recently that turned out to be caused by mercurial trying to re-apply changes that had already been merged. I was able to track it down to an odd choice of merge base which caused both heads to include the same changes - but I don't understand why this happened and how I can prevent it in the future (I chose a DVCS partly to avoid these kinds of problems in the first place...)


Solution

  • The picture shows there are not one but two common ancestors. So, it looks like a criss-cross merge case where merge problems arise from chosing one or another common ancestor.

    References:

    There is a proposal for a new merge algorithm (https://www.mercurial-scm.org/wiki/ConsensusMerge). However, since Mercurial's 2.3 sprint this topic is stuck.

    To reduce this kind of problem, I suggest you to estabilish a client-server topology, so that developers only merge with the official repository. Maybe rebase could help also.

    A criss-cross merge is something like this:

       B --- D
      / \   / \
     /   \ /   \ 
    A     X     F 
     \   / \   /
      \ /   \ /
       C --- E
    

    In your case, it was:

               B
    -----------o----               } stable/production
          C     \   \       F
    ------o------o---\------o      } default
           \     D    \    /
            -----------o---        } feature
                       E
    
    A = ?
    B = 14318
    C = 14294
    D = 14319
    E = 14321
    F = ?
    

    To produce F, there are two possible circuits: B-D-E-F and C-D-E-F. Mercurial has chosen the latter.

    You could have avoided the criss-cross if you haven't merged production and feature branches. The hotfix could have been propagated to the feature branch via the default branch. The log would be:

               B
    -----------o               } stable/production
          C     \       F
    ------o------o------o      } default
           \    D \    /
            -------o---        } feature
                   E