Home » Git » Add a git merge driver to the repository?

Add a git merge driver to the repository?

Posted by: admin November 15, 2021 Leave a comment

Questions:

I’m creating a merge driver. I have defined a .gitattributes file as follows:

filename merge=mergeStrategy

I have created the merge driver in $PROJECT/.git/config as follows:

[merge "mergeStrategy"]
    name = My merge strategy
    driver = scripts/mergeScript.sh

This works fine locally, but I would like to commit this merge driver to the git repository so that the merge strategy is in effect for everyone.

Is there a way I can add this (or other Git configuration options) to the repository itself?

Answers:

You could simply add and commit (and push) script/mergeScript (along with the .gitattributes file, of course)

That would work as long as:

  • mergeScript is somehow in the $PATH of the user executing the merge driver.
  • mergeScript is executable, chmod +x
  • mergeScript is without extension, to allow you to later change its content (from a bash shell to a Perl script to a C executable to …) if needed.

(Thank you, MestreLion, for the last two points, as he mentioned them in the comment)

That was the case for you locally, as I suspect that ‘.‘ was in your $PATH, but you cannot assume that for everybody.

However, the local config file (.git/config) won’t be pushed/cloned (as Alexandr Priymak points out in the comment), so the users still need to replicate the declaration of the custom merge driver.

This is a basic safety measure, in order for you to not push a potential "harmful" script which would then be automatically executed at the next merge.

An alternative method using Makefile

An another option is to keep all the git drivers and .gitattributes in the version history and also include something that easily activates all the drivers. For example, one project used Makefile that had special target make gitdrivers that activated all the git drivers in the repo.

This is needed because git considers custom drivers as potential security vulnerability and you need to do something to grant trust to any new drivers. The merge drivers and other hooks are executable code running on your user credentials that start automatically as a side-effect on git actions, so obviously extra care must be taken before running that code.

Running code that changes .git/config to activate the drivers is the git style of granting the trust.

In practice, you can use Makefile for that (but you could use whatever build system or script that suits your project). For Ubuntu Linux hosts, you can simply do it like follows (example with three drivers):

In file .gitattributes:

[attr]POFILE merge=merge-po-files
[attr]IMAGE diff=image
[attr]BINARY diff=binary -merge -text

locale/*.po POFILE
data/*.img BINARY
*.png IMAGE

and in Makefile (indent should be done with U+0009 TAB character only but stackoverflow.com doesn’t support it here):

developer-dependencies:
        sudo apt install required-package1 required-package2

submodules:
        @echo "Overwriting submodules with committed versions..."
        git submodule sync
        git submodule update --init

gitdrivers: developer-dependencies submodules
        @echo "Overwriting git drivers with current version..."
        git config merge.merge-po-files.driver "./bin/merge-po-files %A %O %B"
        # show rough thumbnails in text mode for images
        git config diff.image.textconv "./bin/image-textconv"
        git config diff.image.binary "true"
        git config diff.image.cachetextconv "true"
        # show some extra information about binary files
        git config diff.binary.textconv "./bin/binary-textconv"
        git config diff.binary.binary "true"
        @echo "All git drivers done."

Where files merge-po-files, image-textconv and binary-textconv are suitable executables in the project subdirectory bin. If you have a project that needs to work on multiple platforms, you could have an extra dependency to build/link correct binary for the current platform.

The example config tells git to render ASCII presentation of images in diffs, merge gettext .PO files with special merge driver and prevent merging selected binary files even if git heuristics declare those as text. Instead require selecting one version or the other for files marked as BINARY. And show special user visible summary for the BINARY files in diffs.

This way all developers just need to run make gitdrivers once after doing the initial clone. And they automatically get updates to drivers that they’ve already installed when they merge or rebase their working copy later. And if they’re not sure if they have the latest drivers, they can simply re-run the same command at any time. Note that the example above will reset all submodules you have which may or may not what you really want.

TL;DR: .git/config is not included in the repository but you can include a script that re-creates suitable config using git config commands. For UNIX-like systems a shell script is great. If your project needs building the code you can hook installing the required drivers to build process if needed. Also note that it’s much safer to use git config ... commands instead of trying to directly modify the config file because those commands will keep working even if the file format of that config file changed in the future.