Search code examples
gitgitattributes

Unable to configure the .gitattributes to have any effect for merges


The merge driver for .gitattributes has been configured:

git config --global merge.ours.driver true

$git config -l
push.default=current
pull.default=current
merge.ours.driver=true

Here is what is in the repo's gitattributes file (under .git/info/attributes):

$cat .git/info/attributes

keys_manager/* merge=ours
js/README.md merge=theirs

The keys_manager directory had been removed in the first branch (ours) and a change made to it in the second (theirs) branch. Changes have been made to a file inside of keys_manager on the remote end and to the js/README.md on both branches.

Let us now do a dry-run of the commit:

git merge --no-commit --no-ff origin/audiorec

The result:

CONFLICT (modify/delete): keys_manager/init_db.sql deleted in HEAD and modified in 
origin/audio-recorder. Version origin/audio-recorder of keys_manager/init_db.sql left in tree.

Auto-merging js/README.md
CONFLICT (content): Merge conflict in js/README.md
Automatic merge failed; fix conflicts and then commit the result.

These are not the expected .gitattributes influenced results but rather the vanilla results as if the .gitattributes did not exist. Why is it not taking effect?


Solution

  • Your merge driver would be used for keys_manager/init_db.sql if there were a low-level conflict. But in fact:

    CONFLICT (modify/delete): keys_manager/init_db.sql deleted in HEAD
    and modified in origin/audio-recorder ... [snip]
    

    you got a high-level or tree conflict, instead of a low-level conflict. That is, one side completely deleted the file, and the other side modified the file. The standard merge strategy always just leaves the modified file as the temporary (conflicted) result, and stops with a conflict. If you would like for the final result to have the file deleted, you may simply delete the file now.

    Meanwhile, this:

    Auto-merging js/README.md
    CONFLICT (content): Merge conflict in js/README.md
    

    is a low-level conflict, so your merge driver:

    js/README.md merge=theirs
    

    should have been invoked. You showed:

    merge.ours.driver=true
    

    but what is merge.theirs.driver set to? If not set, the instructions to use your own driver are ignored; Git uses its built-in low-level merge driver.