As Edward Thomson said in his answer , and you guessed that you should put this git-merge-mystrategy.sh in a file that Git can find via $PATH . This file should be executable ( chmod +x on Unix / Linux, I I have no idea what on Windows) and is found through the name git-merge-mystrategy if you run it as git merge -s mystrategy . (You can run git merge -s mystrategy.sh to search for $PATH for git-merge-mystrategy.sh .)
The big problem is that the right merge strategy is not easy to write. It:
merge-file -q --ours "$2" "$1" "$3";
will not work. Your strategy will be invoked using specific arguments computed with git merge , but none of them are file names. I will illustrate this with the non-functional merge strategy script here.
If you run:
git merge
your script will be called with four (!) arguments. If you run:
git merge -s mystrategy -Xa -Xkcd=12
your script will receive seven arguments:
$ cat ~/scripts/git-merge-silly #! /bin/sh echo "I got $# arguments..." for i do printf "%s\n" "$i" done read junk $ chmod +x ~/scripts/git-merge-silly $ git merge -s silly -Xa -Xkcd=12 -X find-renames=35 b1 I got 7 arguments... --a --kcd=12 --find-renames=35 4f95ecf496de9dfe175e7ed4dd97972adf0ca625 -- HEAD 439e327bc8f8e78d74b27ae89f433451eec09111
(at this point, the script reads the junk variable from stdin, so everything pauses, and I can press CTRL + C to break it and stop the fictitious merge).
Here is what the argument is and what they mean:
--whatever : this goes through an advanced strategy, -X whatever . As you can see, there is no verification of these arguments: they are really just arbitrary strings (what would the -Xkcd parameter -Xkcd ?).- Hash, or in some cases several hashes, before
-- : is the merge base or the merge base, if there are more, from the heads that need to be combined. -- : This separates the merge bases from the strings that determine which heads should be combined.HEAD : this is always the next argument; it compiled into git merge . This is a local leader and for a strategy such as -s ours (or -s theirs , if one exists), it has a little extra significance, but for most merge strategies you should treat it the same way as the remaining arguments.- One or more hash identifiers: this is what Git calls to merge the remote heads. In this case, by running
git merge ... develop , Git allowed develop specific commit identifier, which is a commit tip of your branch named develop , and that commit is a remote HEAD.
As a merge strategy, your task now:
- find the changes from the merge base (s) from each of the different heads (HEAD plus each of the remotes)
- merge these changes by writing the resulting merged files to the index and working tree
- exit with a status indicating your success or failure status.
Perhaps the easiest way is to simply specify the source of git merge here :
At this point, we need a real merger. No matter what strategy we use, it will act on the index, possibly affecting the working tree, and if properly resolved to have the desired tree in the index - this means that the index must be in synchronization with the fixation of the head. Strategies are responsible to ensure this.
and a little later :
The backend exits from 1 when conflicts remain to be resolved, from 2 when it does not handle this merge at all.
If you specify several -s options on the command line, the git merge code will (in Git) run git stash for you, and then do git reset --hard and git stash apply between each strategy - try until one of them succeeds completely, exiting with 0-status - in this case Git takes its result - or it ends the strategy attempts. Leaving the strategies, if some of them went from 1 instead of 2, Git chooses the one that produced the βbestβ result, where the βbestβ is a somewhat odd measure: the smallest numerical sum of the modified files (against the HEAD commit) and the serene files are counted " the best "result. (It seems to me that perhaps serene files should be more balanced, here.) Then he will run this better merge again after another hard reset.
In any case, the thing is that you need to work hard in the merge strategy. It is reasonable to make sure that the index and the working tree are in a reasonable restored state before continuing, and reject the merge (using "please commit or record your changes"), if not. Strongly, if there are several merge bases, you can completely abandon the attempt to use exit 2 , but otherwise you must do something with several merge bases. (The resolve strategy selects one of them and ignores the rest, which is a valid option, although not always the best. The recursive strategy combines the merge bases and uses the resulting commit as a new merge base.)
Then for each head β your own regular HEAD head plus each remote head β you must find the change. Regular recursive strategies and solution strategies that refuse to run if there are exactly two heads, run git diff with the default 50% rename, allowing the -X arguments to change this to detect creation, deletion, and renaming in each head compared to base. Then they merge them at a high level or do not merge them, leaving a high level conflict in the index - and for each pair of files identified in the base-to-each-head, merge these files at a lower level using git merge-file .
In your strategy, you will need to do all the same work, except that for one specific file you should use git merge-file -q --ours way you want it here.