Choosing between the ort and recursive strategies Jump to heading
Git replaced its default merge strategy in version 2.33, and most people noticed only that large merges got faster. The two strategies solve the same problem β a three-way merge with possibly several merge bases β and they agree on the vast majority of inputs. Where they differ is rename detection, directory handling and performance, and those differences show up exactly when a merge is already difficult. This recipe explains when the distinction matters, within merge strategies and gitattributes.
When to use this approach Jump to heading
- A merge conflicted and you suspect the strategy is involved.
- Someone has proposed pinning the strategy in team configuration.
- Large merges are slow and you want to know whether the strategy is the cause.
- A directory was renamed on one side and files were added to it on the other.
- If your merges are small and mostly clean, the default is correct and this page is background reading.
Step 1 β Establish which strategy you are using Jump to heading
git --version # ort is the default from 2.33
git config --get pull.twohead # a value here overrides the default
git config --get merge.default # rarely set; the same effect # Confirm on an actual merge, with verbosity turned up
git -c merge.verbosity=5 merge --no-commit --no-ff other-branch 2>&1 | head -8
git merge --abort # Verification: no configuration is pinning the old strategy
git config --show-origin --get-regexp 'merge\.|pull\.twohead' || echo "using the default" Step 2 β Reproduce the merge with each strategy Jump to heading
The only reliable way to know whether the strategy matters for a specific merge is to run both.
git switch -c probe/ort main
git merge -s ort --no-commit --no-ff feature 2>&1 | tail -5
git diff --name-only --diff-filter=U | tee /tmp/ort-conflicts.txt | wc -l
git merge --abort && git switch main && git branch -D probe/ort git switch -c probe/recursive main
git merge -s recursive --no-commit --no-ff feature 2>&1 | tail -5
git diff --name-only --diff-filter=U | tee /tmp/rec-conflicts.txt | wc -l
git merge --abort && git switch main && git branch -D probe/recursive # Verification: do they disagree at all?
diff /tmp/ort-conflicts.txt /tmp/rec-conflicts.txt && echo "identical conflict sets" If the conflict sets are identical β which they usually are β the strategy is not your problem and the conflict is genuine.
Step 3 β Understand the directory-rename case Jump to heading
This is the difference most likely to affect you, and it is the one that produces a merge result people describe as βGit lost my fileβ.
# On one branch: a directory is renamed
git switch -c rename main
git mv src/util src/helpers && git commit -m 'refactor: rename util to helpers'
# On the other: a new file is added to the old directory
git switch -c addition main
printf 'export const clamp = (n) => n;\n' > src/util/clamp.ts
git add src/util/clamp.ts && git commit -m 'feat: add clamp' # ort follows the directory rename; recursive leaves the new file behind
git switch rename && git merge -s ort --no-commit addition
git status --short | grep clamp
git merge --abort # Verification: where did the file land under each strategy?
git merge -s recursive --no-commit addition && git status --short | grep clamp; git merge --abort Step 4 β Decide whether to pin anything Jump to heading
The short answer is no, and the cases for the long answer are narrow.
# If you must pin for a specific merge β never globally
git merge -s recursive other-branch
# Pinning globally, for reference. Almost always a mistake.
# git config --global pull.twohead recursive # Verification: check that nothing has pinned it accidentally
git config --global --get pull.twohead && echo "PINNED β is this deliberate?" || echo "default in use" SAFETY WARNING β pinning the old strategy in shared configuration means everyone gets worse rename handling and slower merges to preserve behaviour that almost never differs. If a specific merge genuinely needs it, pass the flag for that merge and say why in the commit message. A pinned strategy in a team configuration file outlives the reason for it by years.
Step 5 β Attack the real cause instead Jump to heading
When a merge is painful, the strategy is rarely the lever that helps. The three that do are attributes, conflict style and branch lifetime.
# Conflict style: see the common ancestor rather than guessing
git config --global merge.conflictStyle zdiff3 # Attributes: stop conflicting on files with a deterministic resolution
git check-attr merge -- package-lock.json CHANGELOG.md # Branch lifetime: how far has this branch diverged?
git rev-list --left-right --count main...feature The third bar is deliberately zero: conflict style does not prevent conflicts, it makes the ones you get decidable by showing what the common ancestor said. That is a different kind of win and usually the highest-value single setting available β see 3-way merge fundamentals.
Validation checklist Jump to heading
Frequently Asked Questions Jump to heading
Is there any reason to use recursive today? Jump to heading
Only to reproduce historical behaviour β investigating how a merge from three years ago produced its result, for example. For new merges the newer strategy is better in every dimension that has been measured, and the differences in outcome are limited to cases where its handling is more correct rather than merely different.
What about the resolve and octopus strategies? Jump to heading
resolve handles a single merge base and is a curiosity now. octopus merges more than two heads at once and is genuinely useful for merging several independent topic branches in one commit, though the result is hard to bisect through and it refuses to run if any pair conflicts.
Does the strategy affect rebase and cherry-pick? Jump to heading
Yes β both replay commits using the merge machinery, so the same strategy and the same rename detection apply. A rebase that produces surprising results across a directory rename is usually the same phenomenon described in Step 3.
Related Jump to heading
- Merge Strategies & gitattributes β the parent topic and the three levels of control.
- 3-Way Merge Fundamentals β the model both strategies implement.
- Resolving Whitespace Conflicts With Strategy Options β the options worth reaching for instead.