mercurial/helptext/internals/bid-merge.txt
author Matt Harbison <matt_harbison@yahoo.com>
Thu, 05 Jan 2023 17:38:14 -0500
branchstable
changeset 49883 e90767a71dc0
parent 45059 79f6f9fa18c1
permissions -rw-r--r--
histedit: byteify the help for the multifold action While there's some allowance for str in `_()`, it's commented to be for "goofy unicode docstrings in test", so no idea how well that works, but it should at least come back as bytes. With HGPLAIN, however, the str isn't touched and is returned as-is, so this seems like a real bug.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
45059
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
     1
Bid merge is a feature introduced in Mercurial 3.0, a merge algorithm for
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
     2
dealing with complicated merges.
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
     3
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
     4
Bid merge is controled  by the `merge.preferancestor` configuration option. The
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
     5
default is set to `merge.preferancetors=*` and enable bid merge. Mercurial will
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
     6
perform a bid merge in the cases where a merge otherwise would emit a note:
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
     7
using X as ancestor of X and X message.
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
     8
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
     9
Problem it is solving
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    10
=====================
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    11
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    12
Mercurial's core merge algorithm is the traditional "three-way merge". This
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    13
algorithm combines all the changes in two changesets relative to a common
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    14
ancestor. But with complex DAGs, it is often possible to have more than one
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    15
"best" common ancestor, with no easy way to distinguish between them.
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    16
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    17
For example, C and D has 2 common ancestors in the following graph::
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    18
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    19
  C   D
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    20
  |\ /|
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    21
  | x |
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    22
  |/ \|
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    23
  A   B
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    24
   \ /
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    25
    R
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    26
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    27
Mercurial used to arbitrarily chooses the first of these, which can result in
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    28
various issues:
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    29
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    30
* unexpected hard 3-way merges that would have been completely trivial if
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    31
  another ancestor had been used
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    32
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    33
* conflicts that have already been resolved may reappear
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    34
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    35
* changes that have been reversed can silently oscillate
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    36
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    37
One common problem is a merge which with the "right" ancestor would be trivial
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    38
to resolve because only one side changed. Using another ancestor where the same
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    39
lines are different, it will give an annoying 3-way merge.
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    40
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    41
Other systems like Git have attacked some of these problems with a so-called
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    42
"recursive" merge strategy, that internally merges all the possible ancestors
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    43
to produce a single "virtual" ancestor to merge against. This is awkward as the
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    44
internal merge itself may involve conflicts (and possibly even multiple levels
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    45
of recursion), which either requires choosing a conflict disposition (e.g.
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    46
always choose the local version) or exposing the user to extremely confusing
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    47
merge prompts for old revisions. Generating the virtual merge also potentially
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    48
involves invoking filters and extensions.
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    49
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    50
Concept
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    51
=======
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    52
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    53
(Bid merge is pretty much the same as Consensus merge.)
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    54
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    55
Bid merge is a strategy that attempts to sensibly combine the results of the
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    56
multiple possible three-way merges directly without producing a virtual
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    57
ancestor. The basic idea is that for each ancestor, we perform a top-level
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    58
manifest merge and generate a list of proposed actions, which we consider
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    59
"bids". We then make an "auction" among all the bids for each file and pick the
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    60
most favourable. Some files might be trivial to merge with one ancestor, other
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    61
files with another ancestor.
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    62
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    63
The most obvious advantage of considering multiple ancestors is the case where
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    64
some of the bids for a file is a "real" (interactive) merge but where one or
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    65
more bids just take on of the parent revisions. A bid for just taking an
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    66
existing revision is very simple and low risk and is an obvious winner.
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    67
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    68
The auction algorithm for merging the bids is so far very simple:
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    69
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    70
* If there is consensus from all the ancestors, there is no doubt what to do. A
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    71
  clever result will be indistinguishable from just picking a random bid. The
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    72
  consensus case is thus not only trivial, it is also already handled
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    73
  perfectly.
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    74
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    75
* If "keep local" or "get from other" actions is an option (and there is only
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    76
  one such option), just do it.
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    77
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    78
* If the auction doesn't have a single clear winner, pick one of the bids
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    79
  "randomly" - just as it would have done if only one ancestor was considered.
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    80
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    81
This meta merge algorithm has room for future improvements, especially for
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    82
doing better than picking a random bid.
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    83
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    84
Some observations
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    85
=================
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    86
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    87
Experience with bid merge shows that many merges that actually have a very
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    88
simple solution (because only one side changed) only can be solved efficiently
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    89
when we start looking at file content in filemerge ... and it thus also
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    90
requires all ancestors passed to filemerge. That is because Mercurial includes
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    91
the history in filelog hashes. A file with changes that ends up not changing
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    92
the content (could be change + backout or graft + merge or criss cross merges)
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    93
still shows up as a changed file to manifestmerge. (The git data model has an
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    94
advantage here when it uses hashes of content without history.) One way to
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    95
handle that would be to refactor manifestmerge, mergestate/resolve and
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    96
filemerge so they become more of the same thing.
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    97
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    98
There is also cases where different conflicting chunks could benefit from using
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
    99
multiple ancestors in filemerge - but that will require merge tools with fancy
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
   100
support for using multiple ancestors in 3+-way merge. That is left as an
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
   101
exercise for another day. That seems to be a case where "recursive merge" has
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
   102
an advantage.
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
   103
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
   104
The current manifest merge actions are very low level imperative and not
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
   105
symmetrical. They do not only describe how two manifests should be merged, they
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
   106
also describe a strategy for changing a context from a state where it is one of
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
   107
the parents to the state where it is the result of the merge with the other
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
   108
parent. I can imagine that manifestmerge could be simplified (and made more
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
   109
suitable for in memory merges) by separating the abstract merge actions from
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
   110
the actual file system operation actions. A more clever wcontext could perhaps
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
   111
also take care of some of the branchmerge special cases.
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
   112
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
   113
We assume that the definition of Mercurial manifest merge will make sure that
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
   114
exactly the same files will be produced, no matter which ancestor is used. That
79f6f9fa18c1 documentation: add some internals documentation about bid merge
Pierre-Yves David <pierre-yves.david@octobus.net>
parents:
diff changeset
   115
assumption might be wrong in very rare cases that really not is a problem.