`git merge -s theirs` needed but it does not exist

Many thanks to @VonC for suggesting the use of the merge=custom-driver attribute in the .gitattributes file. While this will work, I'm reluctant to pollute my workspace with .git files, and while I could use $GIT_DIR/info/attributes to avoid the pollution, I'm bothered by the need for 2 rules to catch dot-files and non-dot files.

After a bit of experimentation I managed to get a solution with the merge.default configuration variable (mentioned in the gitattributes(5) manpage) working. The trick I missed was that merge.default takes the name of a custom driver you have defined previously; you don't give it the custom command directly. Here's what works for me...

First define your copy-merge custom driver. You can use shell commands directly; there's no need for an external script (just make sure you get your shell meta-character quoting right):

git config merge.copy-merge.name   'Copy Merge'
git config merge.copy-merge.driver 'mv %B %A'

Note that mv returns 0 on success, 1 on failure, meeting the criteria for reporting merge "success" back to git.

Now tell git that ALL merges are copy-merges:

git config merge.default copy-merge

Hey Presto! Job done. git merge <branch> will now copy-merge everything so the branch you're on contains exact copies of all files on <branch>. QED.

If you want to do a non-copy-merge then simply reset the default merge driver:

git config --unset merge.default

If you do want to be more selective then leave merge.default unset and use attributes as @VonC says:

cd path/to/copy-merge/in
echo '* merge=copy-merge'  >  .gitattributes
echo '.* merge=copy-merge' >> .gitattributes

Do this at the top of every subtree you want to copy-merge in. If there's a sub-subtree that you DON'T want to copy-merge in, you can turn it off again:

cd path/to/copy-merge/in/path/to/normal-merge/in
echo '* merge'  >  .gitattributes
echo '.* merge' >> .gitattributes

WARNING: littering your working tree with lots of .gitattributes files is bound to lead to confusion, especially if you also use things like "*.bin -merge" in other directories to force all merges of .bin files to fail with conflicts. It may be better to use $GIT_DIR/info/attributes for this sort of thing, as it has the highest precedence.


Ran into this problem the other day:

http://seanius.net/blog/2011/02/git-merge-s-theirs/

git merge -s ours ref-to-be-merged
git diff --binary ref-to-be-merged | git apply -R --index
git commit -F .git/COMMIT_EDITMSG --amend

(update 2011:
The answer " git command for making one branch like another " lists all the possible ways to simulate a git merge -s theirs`)


For the specific files/trees you want to copy-merge, you could setting up a gitattributes value like the one I mention in this SO question, defining a custom merge driver.
The script associated with the merge attribute would ensure always keeping the remote file as the merge result (see this SO answer for an illustration, albeit for the opposite scenario -- keeping the local version).

echo * merge=keepTheir > dirWithCopyMerge\.gitattributes
git config merge.keepTheir.name "always keep theirduring merge"
git config merge.keepTheir.driver "keepTheir.sh %O %A %B"

By setting a .gitattribute on top of the sub-tree you want to be copy-merged, with '* merge=keepTheir' as its content, you effectively attribute a custom merge driver to all files of that subtree (note the use of the '*' wildcard here).

With keepTheir.sh as:

mv -f $3 $2
exit 0

you do not have to modify any "default" merge driver, and you apply your own only on the files you want.


In version 1.7.1 of Git, you can pass a "theirs" strategy to merge with and "-Xtheirs" argument.

git merge -Xtheirs otherBranch

Not sure if that applies to what you are trying to do, but it's probably worth a shot.

(See also this related question)