Merge branch 'en/ort-becomes-the-default'

Use `ort` instead of `recursive` as the default merge strategy.

* en/ort-becomes-the-default:
  Update docs for change of default merge backend
  Change default merge backend from recursive to ort
This commit is contained in:
Junio C Hamano 2021-08-30 16:06:01 -07:00
commit 8778fa8b4f
8 changed files with 78 additions and 65 deletions

View file

@ -352,8 +352,8 @@ See also INCOMPATIBLE OPTIONS below.
-s <strategy>:: -s <strategy>::
--strategy=<strategy>:: --strategy=<strategy>::
Use the given merge strategy, instead of the default Use the given merge strategy, instead of the default `ort`.
`recursive`. This implies `--merge`. This implies `--merge`.
+ +
Because 'git rebase' replays each commit from the working branch Because 'git rebase' replays each commit from the working branch
on top of the <upstream> branch using the given strategy, using on top of the <upstream> branch using the given strategy, using
@ -366,7 +366,7 @@ See also INCOMPATIBLE OPTIONS below.
--strategy-option=<strategy-option>:: --strategy-option=<strategy-option>::
Pass the <strategy-option> through to the merge strategy. Pass the <strategy-option> through to the merge strategy.
This implies `--merge` and, if no strategy has been This implies `--merge` and, if no strategy has been
specified, `-s recursive`. Note the reversal of 'ours' and specified, `-s ort`. Note the reversal of 'ours' and
'theirs' as noted above for the `-m` option. 'theirs' as noted above for the `-m` option.
+ +
See also INCOMPATIBLE OPTIONS below. See also INCOMPATIBLE OPTIONS below.
@ -527,7 +527,7 @@ The `--rebase-merges` mode is similar in spirit to the deprecated
where commits can be reordered, inserted and dropped at will. where commits can be reordered, inserted and dropped at will.
+ +
It is currently only possible to recreate the merge commits using the It is currently only possible to recreate the merge commits using the
`recursive` merge strategy; different merge strategies can be used only via `ort` merge strategy; different merge strategies can be used only via
explicit `exec git merge -s <strategy> [...]` commands. explicit `exec git merge -s <strategy> [...]` commands.
+ +
See also REBASING MERGES and INCOMPATIBLE OPTIONS below. See also REBASING MERGES and INCOMPATIBLE OPTIONS below.
@ -1216,16 +1216,16 @@ successful merge so that the user can edit the message.
If a `merge` command fails for any reason other than merge conflicts (i.e. If a `merge` command fails for any reason other than merge conflicts (i.e.
when the merge operation did not even start), it is rescheduled immediately. when the merge operation did not even start), it is rescheduled immediately.
By default, the `merge` command will use the `recursive` merge By default, the `merge` command will use the `ort` merge strategy for
strategy for regular merges, and `octopus` for octopus merges. One regular merges, and `octopus` for octopus merges. One can specify a
can specify a default strategy for all merges using the `--strategy` default strategy for all merges using the `--strategy` argument when
argument when invoking rebase, or can override specific merges in the invoking rebase, or can override specific merges in the interactive
interactive list of commands by using an `exec` command to call `git list of commands by using an `exec` command to call `git merge`
merge` explicitly with a `--strategy` argument. Note that when explicitly with a `--strategy` argument. Note that when calling `git
calling `git merge` explicitly like this, you can make use of the fact merge` explicitly like this, you can make use of the fact that the
that the labels are worktree-local refs (the ref `refs/rewritten/onto` labels are worktree-local refs (the ref `refs/rewritten/onto` would
would correspond to the label `onto`, for example) in order to refer correspond to the label `onto`, for example) in order to refer to the
to the branches you want to merge. branches you want to merge.
Note: the first command (`label onto`) labels the revision onto which Note: the first command (`label onto`) labels the revision onto which
the commits are rebased; The name `onto` is just a convention, as a nod the commits are rebased; The name `onto` is just a convention, as a nod

View file

@ -275,7 +275,7 @@ best to always use a regular merge commit.
[[merge-two-revert-one]] [[merge-two-revert-one]]
If I make a change on two branches but revert it on one, why does the merge of those branches include the change?:: If I make a change on two branches but revert it on one, why does the merge of those branches include the change?::
By default, when Git does a merge, it uses a strategy called the recursive By default, when Git does a merge, it uses a strategy called the `ort`
strategy, which does a fancy three-way merge. In such a case, when Git strategy, which does a fancy three-way merge. In such a case, when Git
performs the merge, it considers exactly three points: the two heads and a performs the merge, it considers exactly three points: the two heads and a
third point, called the _merge base_, which is usually the common ancestor of third point, called the _merge base_, which is usually the common ancestor of

View file

@ -144,7 +144,7 @@ endif::git-pull[]
Use the given merge strategy; can be supplied more than Use the given merge strategy; can be supplied more than
once to specify them in the order they should be tried. once to specify them in the order they should be tried.
If there is no `-s` option, a built-in list of strategies If there is no `-s` option, a built-in list of strategies
is used instead (`recursive` when merging a single head, is used instead (`ort` when merging a single head,
`octopus` otherwise). `octopus` otherwise).
-X <option>:: -X <option>::

View file

@ -6,21 +6,23 @@ backend 'merge strategies' to be chosen with `-s` option. Some strategies
can also take their own options, which can be passed by giving `-X<option>` can also take their own options, which can be passed by giving `-X<option>`
arguments to `git merge` and/or `git pull`. arguments to `git merge` and/or `git pull`.
recursive:: ort::
This can only resolve two heads using a 3-way merge This is the default merge strategy when pulling or merging one
algorithm. When there is more than one common branch. This strategy can only resolve two heads using a
ancestor that can be used for 3-way merge, it creates a 3-way merge algorithm. When there is more than one common
merged tree of the common ancestors and uses that as ancestor that can be used for 3-way merge, it creates a merged
the reference tree for the 3-way merge. This has been tree of the common ancestors and uses that as the reference
reported to result in fewer merge conflicts without tree for the 3-way merge. This has been reported to result in
causing mismerges by tests done on actual merge commits fewer merge conflicts without causing mismerges by tests done
taken from Linux 2.6 kernel development history. on actual merge commits taken from Linux 2.6 kernel
Additionally this can detect and handle merges involving development history. Additionally this strategy can detect
renames. It does not make use of detected copies. This and handle merges involving renames. It does not make use of
is the default merge strategy when pulling or merging one detected copies. The name for this algorithm is an acronym
branch. ("Ostensibly Recursive's Twin") and came from the fact that it
was written as a replacement for the previous default
algorithm, `recursive`.
+ +
The 'recursive' strategy can take the following options: The 'ort' strategy can take the following options:
ours;; ours;;
This option forces conflicting hunks to be auto-resolved cleanly by This option forces conflicting hunks to be auto-resolved cleanly by
@ -36,16 +38,6 @@ theirs;;
This is the opposite of 'ours'; note that, unlike 'ours', there is This is the opposite of 'ours'; note that, unlike 'ours', there is
no 'theirs' merge strategy to confuse this merge option with. no 'theirs' merge strategy to confuse this merge option with.
patience;;
Deprecated synonym for `diff-algorithm=patience`.
diff-algorithm=[patience|minimal|histogram|myers];;
Use a different diff algorithm while merging, which can help
avoid mismerges that occur due to unimportant matching lines
(such as braces from distinct functions). See also
linkgit:git-diff[1] `--diff-algorithm`. Defaults to the
`diff.algorithm` config setting.
ignore-space-change;; ignore-space-change;;
ignore-all-space;; ignore-all-space;;
ignore-space-at-eol;; ignore-space-at-eol;;
@ -74,11 +66,6 @@ no-renormalize;;
Disables the `renormalize` option. This overrides the Disables the `renormalize` option. This overrides the
`merge.renormalize` configuration variable. `merge.renormalize` configuration variable.
no-renames;;
Turn off rename detection. This overrides the `merge.renames`
configuration variable.
See also linkgit:git-diff[1] `--no-renames`.
find-renames[=<n>];; find-renames[=<n>];;
Turn on rename detection, optionally setting the similarity Turn on rename detection, optionally setting the similarity
threshold. This is the default. This overrides the threshold. This is the default. This overrides the
@ -95,19 +82,39 @@ subtree[=<path>];;
is prefixed (or stripped from the beginning) to make the shape of is prefixed (or stripped from the beginning) to make the shape of
two trees to match. two trees to match.
ort:: recursive::
This is meant as a drop-in replacement for the `recursive` This can only resolve two heads using a 3-way merge
algorithm (as reflected in its acronym -- "Ostensibly algorithm. When there is more than one common
Recursive's Twin"), and will likely replace it in the future. ancestor that can be used for 3-way merge, it creates a
It fixes corner cases that the `recursive` strategy handles merged tree of the common ancestors and uses that as
suboptimally, and is significantly faster in large the reference tree for the 3-way merge. This has been
repositories -- especially when many renames are involved. reported to result in fewer merge conflicts without
causing mismerges by tests done on actual merge commits
taken from Linux 2.6 kernel development history.
Additionally this can detect and handle merges involving
renames. It does not make use of detected copies. This was
the default strategy for resolving two heads from Git v0.99.9k
until v2.33.0.
+ +
The `ort` strategy takes all the same options as `recursive`. The 'recursive' strategy takes the same options as 'ort'. However,
However, it ignores three of those options: `no-renames`, there are three additional options that 'ort' ignores (not documented
`patience` and `diff-algorithm`. It always runs with rename above) that are potentially useful with the 'recursive' strategy:
detection (it handles it much faster than `recursive` does), and
it specifically uses `diff-algorithm=histogram`. patience;;
Deprecated synonym for `diff-algorithm=patience`.
diff-algorithm=[patience|minimal|histogram|myers];;
Use a different diff algorithm while merging, which can help
avoid mismerges that occur due to unimportant matching lines
(such as braces from distinct functions). See also
linkgit:git-diff[1] `--diff-algorithm`. Note that `ort`
specifically uses `diff-algorithm=histogram`, while `recursive`
defaults to the `diff.algorithm` config setting.
no-renames;;
Turn off rename detection. This overrides the `merge.renames`
configuration variable.
See also linkgit:git-diff[1] `--no-renames`.
resolve:: resolve::
This can only resolve two heads (i.e. the current branch This can only resolve two heads (i.e. the current branch
@ -131,13 +138,13 @@ ours::
the 'recursive' merge strategy. the 'recursive' merge strategy.
subtree:: subtree::
This is a modified recursive strategy. When merging trees A and This is a modified `ort` strategy. When merging trees A and
B, if B corresponds to a subtree of A, B is first adjusted to B, if B corresponds to a subtree of A, B is first adjusted to
match the tree structure of A, instead of reading the trees at match the tree structure of A, instead of reading the trees at
the same level. This adjustment is also done to the common the same level. This adjustment is also done to the common
ancestor tree. ancestor tree.
With the strategies that use 3-way merge (including the default, 'recursive'), With the strategies that use 3-way merge (including the default, 'ort'),
if a change is made on both branches, but later reverted on one of the if a change is made on both branches, but later reverted on one of the
branches, that change will be present in the merged result; some people find branches, that change will be present in the merged result; some people find
this behavior confusing. It occurs because only the heads and the merge base this behavior confusing. It occurs because only the heads and the merge base

View file

@ -3190,7 +3190,7 @@ that *updated* thing--the old state that you added originally ends up
not being pointed to by any commit or tree, so it's now a dangling blob not being pointed to by any commit or tree, so it's now a dangling blob
object. object.
Similarly, when the "recursive" merge strategy runs, and finds that Similarly, when the "ort" merge strategy runs, and finds that
there are criss-cross merges and thus more than one merge base (which is there are criss-cross merges and thus more than one merge base (which is
fairly unusual, but it does happen), it will generate one temporary fairly unusual, but it does happen), it will generate one temporary
midway tree (or possibly even more, if you had lots of criss-crossing midway tree (or possibly even more, if you had lots of criss-crossing

View file

@ -88,9 +88,9 @@ static int autostash;
static int no_verify; static int no_verify;
static struct strategy all_strategy[] = { static struct strategy all_strategy[] = {
{ "recursive", DEFAULT_TWOHEAD | NO_TRIVIAL }, { "recursive", NO_TRIVIAL },
{ "octopus", DEFAULT_OCTOPUS }, { "octopus", DEFAULT_OCTOPUS },
{ "ort", NO_TRIVIAL }, { "ort", DEFAULT_TWOHEAD | NO_TRIVIAL },
{ "resolve", 0 }, { "resolve", 0 },
{ "ours", NO_FAST_FORWARD | NO_TRIVIAL }, { "ours", NO_FAST_FORWARD | NO_TRIVIAL },
{ "subtree", NO_FAST_FORWARD | NO_TRIVIAL }, { "subtree", NO_FAST_FORWARD | NO_TRIVIAL },
@ -1485,6 +1485,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
fast_forward = FF_NO; fast_forward = FF_NO;
} }
if (!use_strategies && !pull_twohead &&
remoteheads && !remoteheads->next) {
char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM");
if (default_strategy)
append_strategy(get_strategy(default_strategy));
}
if (!use_strategies) { if (!use_strategies) {
if (!remoteheads) if (!remoteheads)
; /* already up-to-date */ ; /* already up-to-date */

View file

@ -1713,7 +1713,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
int i; int i;
if (!options.strategy) if (!options.strategy)
options.strategy = "recursive"; options.strategy = "ort";
strbuf_reset(&buf); strbuf_reset(&buf);
for (i = 0; i < strategy_options.nr; i++) for (i = 0; i < strategy_options.nr; i++)

View file

@ -636,7 +636,7 @@ static int do_recursive_merge(struct repository *r,
for (i = 0; i < opts->xopts_nr; i++) for (i = 0; i < opts->xopts_nr; i++)
parse_merge_opt(&o, opts->xopts[i]); parse_merge_opt(&o, opts->xopts[i]);
if (opts->strategy && !strcmp(opts->strategy, "ort")) { if (!opts->strategy || !strcmp(opts->strategy, "ort")) {
memset(&result, 0, sizeof(result)); memset(&result, 0, sizeof(result));
merge_incore_nonrecursive(&o, base_tree, head_tree, next_tree, merge_incore_nonrecursive(&o, base_tree, head_tree, next_tree,
&result); &result);
@ -3988,7 +3988,7 @@ static int do_merge(struct repository *r,
o.branch2 = ref_name.buf; o.branch2 = ref_name.buf;
o.buffer_output = 2; o.buffer_output = 2;
if (opts->strategy && !strcmp(opts->strategy, "ort")) { if (!opts->strategy || !strcmp(opts->strategy, "ort")) {
/* /*
* TODO: Should use merge_incore_recursive() and * TODO: Should use merge_incore_recursive() and
* merge_switch_to_result(), skipping the call to * merge_switch_to_result(), skipping the call to