tags:

views:

134

answers:

2

I have a binary file in my_branch, and when I need to make changes to it, git will of course not merge it.

So what I do now is:

git checkout my_branch
# make a change to gui.bin
mv gui.bin ~/
git commit -a
mv ~/gui.bin .
git commit -a
# git rebase to 1 commit
git checkout master
git merge my_branch

But is there an easier way?

+1  A: 

you could use the built-in binary merge driver:

binary: Keep the version from your branch in the work tree, but
leave the path in the conflicted state for the user to sort out.

example .gitattributes line:

*.bin -crlf -diff merge=binary

tells git not to add line endings, not to diff, and to keep the local version

http://www.kernel.org/pub/software/scm/git/docs/gitattributes.html

that only preserves your working copy...

another way is to use a custom merge driver:

[merge "binmerge"]
  name = my binary merge script
  driver = binmerge.sh %O %A %B

That could check the conflicting file against a list of files that should always be overwritten by your local version...

to use a merge driver, define it in the config, then specify what paths it should be used on in .gitattributes, like so:

*.bin -crlf -diff merge=binmerge

binmerge.sh will be called to handle the merge. it can essentially just do something like:

#!/bin/sh
echo "Performing merge of binary object ($1, $2, $3)"
touch $2
exit 0
jspcal
Okay, drivers for git is completely new for me. Is it something I put in .git config file?
Louise
yep, that would go in ~/.gitconfig or .git/config
jspcal
Very interesting. So should I just change driver = gui.bin ?
Louise
yep you can do that, the script can exit with 0 to indicate that the merge was successful
jspcal
+2  A: 

I'm not quite sure what your test case is driving at. You seem to be moving gui.bin out of the way and then putting it back the way it was...

Often, binary files don't need to be merged, you just want to chose a definitive version from one place or another. Where they genuinely have to be merged you either need a custom merge tool, or use some sort of editor and lots of manual intervention.

I notice that you use commit -a in your example. One first step to avoid unnecessary conflicts is to not commit any binaries that might be touched incidentally unless you want to commit them. If you just git add the files you need to commit and commit without -a then this will help. Alternatively, if there is just one file that you don't want to commit you could add -u and reset it before making a commit.

git add -u
git reset -- dontcommit.dat
git commit

When you do merge branches that have both change a binary you may want to keep one version and not the other. After a merge where git tells you that their are conflicts in your binary you can tell git to use the version in the branch that you were on like this:

git checkout --ours binary.dat
git add binary.dat

or from the branch that you are merging in like this:

git checkout --theirs binary.dat
git add binary.dat
Charles Bailey
Now this look really good. So just to clarify. If I have done "git checkout master". Then I should use the last code block with "theirs" and then merge?
Louise
Your question isn't 100% clear to me. If you're on `master` (after a successful checkout), and you `git merge otherbranch`, if this produces conflicts in just `binary.dat` then the last two commands in my answer will choose the version from `otherbranch` and mark the conflict as resolved. You can then `git commit` to commit the resolved conflict.
Charles Bailey
Excellent. Thanks =)
Louise