The usual term for this is union merge; see the link in grg's comment. There is no -s
strategy, and no -X
eXtended-option to any of the existing strategies, to make the low level file merge use union merge. You can, however, create a .gitattributes
file and specify merge=union
there, and the git merge-file
command has a --union
option, as well as the --ours
and --theirs
options.
(Presumably no one put -X union
in as an extended argument to the existing recursive/resolve strategy because it is so relatively uncommon to want it.)
Discussion of merge strategies
The octopus strategy is very special: it implements a relatively simple merge that allows you to merge more than one other commit into the current (HEAD
) commit. It requires that this merge have no conflicts anywhere as it has no place to record all the temporary inputs. The resolve and recursive strategies handle merge conflicts by copying the three input files—merge base, --ours
, and --theirs
—into the index, in the three index slots, and then using the existing git merge-file
code1 to merge those three files, writing conflict markers into the final output version.
Note that the -s resolve
strategy, implemented by the git merge-resolve
command, is the same as git merge-recursive
(and implemented by the same underlying code) with one exception: if git merge-recursive
finds two or more merge base commits, git merge -s resolve
simply picks one of them at random, while git merge-recursive
first merges the merge bases to make a new commit, then uses the new commit as the merge base.
The -s subtree
strategy is the recursive strategy; it just does some file renaming along the way.
The remaining strategy (-s ours
) does not even compute a merge base since it is not actually doing any merging.
In effect, then, there are really only two merge strategies: recursive, and octopus. The remaining strategies are just modifications of recursive, or not merge operations at all (-s ours
).
You can write your own merge strategy. Simply write any command, in any source language, and name the executable binary git-merge-foo
or git-merge-xyzzy
or whatever. Running git merge -s foo
or git merge -s xyzzy
will now invoke your strategy, with undocumented arguments that you must puzzle out. These arguments should drive your selection of a merge base and your merging process. Everything is left to your own code, including how to define and implement the merge, and how to git add
the resulting files to the index, and how to run git commit
(if you're going to run it at all). To make a future commit record an actual merge, your command should leave the correct bread-crumb-trail files in the Git directory (git rev-parse --git-dir
) based on the current work-tree (since Git 2.5).
1It doesn't literally run git merge-file
: instead, the base code for doing merges is in various source files, and both git merge-file
and git merge-recursive
invoke that same base code. That code takes three inputs, and writes one output. For git merge-recursive
, the three inputs are stored in the index; for git merge-file
, the three are stored in three file-system files. The output in all cases is the work-tree copy of the file. If the merge succeeds without conflicts, git merge-recursive
moves that file to staging slot zero and proceeds without conflicts, but git merge-file
simply exits with a zero status. If that merge hits conflicts, or fails for other reasons, git merge-recursive
leaves the mess behind in the index and your work-tree and moves on to the next file as usual, while git merge-file
simply exits with a nonzero status.