.gitattributes & individual merge strategy for a file
I have a master and a test branch of my (web) application. These projects are almost the same, except for one file which sets up the application, say "setup".
Whenever I merge one branch into the other, I would like that branch to keep its version of setup. That is, git should not attempt to merge the changes to that file.
I followed the guidance from the Pro Git book and created a .gitattributes file, with the line "setup merge=ours". However, this does not work - neither with fast forward merges not if I introduce conflicts.
(To be precise:
$: mkdir gitest
$: cd gittest
$: git init
$: echo "setup merge=ours" >> .gitattributes
$: echo "master" >> setup
$: git add setup .gitattributes
$: git commit -a -m ...
$: git branch test
$: git checkout test
$: echo "test" >> setup
$: git commit -a -m ...
$: git checkout master
$: git merge test
Expected result: setup contains the word "master", instead git performs a ff merge and setup is "test'.)
I had the same error and it can be solved just defining an "ours" merge driver in .git/config:
[merge "ours"]
name = "Keep ours merge"
driver = true
Since true always return 0 the temporary file holding the current state will not be changed and will stay as the final version.
You can read more about merge driver in here: http://www.kernel.org/pub/software/scm/git/docs/gitattributes.html#_defining_a_custom_merge_driver
Addendum:
This works any time the driver is actually called and this seems to occur only when there are commits changing the same files (git the merge attribute). If there are changes in a single branch the driver is not going to be called.
I found that if I modified the files on both branches and committed the modifications to each branch, and then tried the merge, it would invoke the merge driver and listen to my .gitattributes
which specifies merge=ours
. After this, the two files always differ on the two branches and so the merge driver will always be invoked, so I didn't need to have a custom merge driver that touches the file. It was only necessary to have both modified initially.
The merge driver is only called in non-trivial cases, i.e. if both master and test have touched setup (and you need to define the merge driver ours
first):
git init
git config merge.ours.name '"always keep ours" merge driver'
git config merge.ours.driver 'touch %A'
echo "setup merge=ours" >> .gitattributes
echo "master" >> setup
git add setup .gitattributes
git commit -a -m ...
git branch test
git checkout test
echo "test" >> setup
git commit -a -m ...
git checkout master
echo "more content" >> setup
git commit -a -m ...
git merge test
Having said that I wonder if it's sensible to have setup in the repository at all. If you really want it under version control you could use submodules or the subtree merge strategy to keep common files in sync.
Have a smudge clean script in stead of separate branches. The script can be different depending on what machine you are on.