0

From time to time our custom merge driver is executed on files that did not conflict (They don't have any conflicts if you remove the merge driver, so in the merge driver you can just do a git merge-file and everything works great).

We are using Git 2.5.1

My perception of Git merge drivers was that they are only executed for conflicting files?

The .gitattributes:

* merge=keeplocalversion

The .gitconfig entry:

[merge "keeplocalversion"]
        name = "Keep local pom version"
        driver = /home/atlstash/pommergetreiber/pommergedriver.sh %A %B %O %P

pommergedriver.sh:

#!/bin/bash
echo "==== STARTING MERGE DRIVER ===="

echo $1
echo $2
echo $3
echo $4

# CURRENT = destination branch (checked out branch)
CURRENT=$1
# OTHER = source branch
OTHER=$2
# ANCESTOR = common parent commit
ANCESTOR=$3

FULL_BRANCH_NAME="$(git symbolic-ref HEAD )"
if [ "$?" -ne "0" ]; then
        echo "Detecting branch name failed!"
        exit 1
fi
DESTINATION_BRANCH="$(echo $FULL_BRANCH_NAME | sed 's%refs/heads/%%')"
if [ "$?" -ne "0" ]; then
        echo "Transforming destination branch failed!"
        exit 1
fi

DESTINATION_BRANCH="$(echo $FULL_BRANCH_NAME | sed 's%refs/heads/%%')"
git merge-file --diff3 --marker-size=25 -L $DESTINATION_BRANCH -L "COMMON BASE" -L "SOURCE BRANCH" "${CURRENT}" "${ANCESTOR}" "${OTHER}"

What leads to the following behaviour:

<stash>@<machine>:<project>> git merge origin/feature/<branch>
==== STARTING MERGE DRIVER ====
.merge_file_bm9SCU
.merge_file_MU9B7n
.merge_file_IsOa8q
<project>/...BusinessLogicPositionImpl.java
==== STARTING MERGE DRIVER ====
.merge_file_RjSwel
.merge_file_WvT0MO
.merge_file_baS3FR
<project>/...AbstimmungRestServiceImpl.java
==== STARTING MERGE DRIVER ====
.merge_file_ZWlr2L
.merge_file_22faFf
.merge_file_14SIpi
<project>/...AbstimmungRestService.java
==== STARTING MERGE DRIVER ====
.merge_file_yd2o1c
.merge_file_zf9wHG
.merge_file_5UohlJ
<project>/...WPDAbstimmposten.java
Auto-merging <project>/...BusinessLogicPositionImpl.java
CONFLICT (content): Merge conflict in <project>/...BusinessLogicPositionImpl.java
Auto-merging <project>/...AbstimmungRestServiceImpl.java
CONFLICT (content): Merge conflict in <project>/...AbstimmungRestServiceImpl.java
Auto-merging <project>/...AbstimmungRestService.java
Auto-merging <project>/...WPDAbstimmposten.java
Automatic merge failed; fix conflicts and then commit the result.

The two conflicting files have real conflicts, the two merged files have not.

Why is the merge driver beeing executed for these two files?

BlackEye
  • 775
  • 11
  • 25

1 Answers1

2

Custom merge drivers are run whenever a 3-way merge is needed, i.e. whenever a file has changed in both merge parents since the merge base. If you only want to run your logic in case of conflicts, you can call git merge-file -p and (if the exit code is 0) overwrite $1 with the result or (if the exit code is not 0) run your special conflict resolution logic.

David Deutsch
  • 17,443
  • 4
  • 47
  • 54
  • So it's the definition of a conflict, that was misleading for me. I always thought a conflict is only when the automatic merge on a file failed. – BlackEye Feb 19 '16 at 10:13
  • 1
    @BlackEye, that definition is correct. It is just that custom merge drivers aren't only run for conflicts. – David Deutsch Feb 19 '16 at 11:37
  • What would the commandline for his driver look like then in this instance? `git merge-file -p %A %O %B || /home/atlstash/pommergetreiber/pommergedriver.sh %A %B %O %P`? – Danny Jul 02 '18 at 11:49
  • To answer my question (I think), it looks like `git merge-file -p %A %O %B > /dev/null && git merge-file %A %O %B || /home/atlstash/pommergetreiber/pommergedriver.sh %A %B %O %P` would do what I want. – Danny Jul 02 '18 at 12:46