How to retrieve branch names in a custom Git merge driver?

假装没事ソ 提交于 2019-12-04 04:41:31

Yes, this is as close as you can get in a merge driver.

A merge strategy gets the correct name by looking up each GITHEAD_%s where each %s argument is filled in from the argument(s) given to the merge strategy, one per "remote head". See my answer to a related question for details. This is not documented anywhere, it's just from the source. Unfortunately, by the time you get down to a merge driver, this information is lost: there are no % directives that retrieve those names, even though there could be. (Adding some % directives should be easy: just increase the size of the dictionary and add appropriate directives and strbuf objects.)

If you're handling a normal two-heads-and-a-base merge, there's only one GITHEAD_* variable and it's the other head, but if you are handling an octopus merge, you are out of luck.

I have been handling this task for a few weeks and I have found a few corner cases that are not correctly handled by this script. Searching around and taking a look at Git sources I have arrived at this script:

#!/bin/bash 
# ${1} is the base common file 
# ${2} is the file as modified by the base branch, and where the results must be 
# ${3} is the file as modified by the incoming branch / stash
# ${4} is the path of the file being merged

# does not support octopus merge.

branch=$(git symbolic-ref --short HEAD || git name-rev --name-only HEAD)
githeadNum=$(env | grep GITHEAD | wc -l) # pathces do not create any GITHEAD var


# get a GITHEAD with message 'Stashed changes'
# if we are applying a stash, it must exist.
# see https://github.com/git/git/blob/2d08f3deb9feb73dc8d21d75bfd367839fc1322c/git-stash.sh#L616
stash=$(env | grep -E 'GITHEAD_[0-9a-f]{40}\b*=\b*Stashed changes' | wc -l) # e.g. GITHEAD_<sha>=Stashed changes 

if [ "$stash" -eq "1" ]
then
    # we are in a stash 
else
    if [ "$githeadNum" -eq "0" ]
    then
        # we are in a patch
    else
        # normal merge

        # only one GITHEAD, merging
        gitHeadName=$(env | grep GITHEAD)
        source="${gitHeadName##*=}"
    fi
fi

exit 1 

I recover the destination branch as

$(git symbolic-ref --short HEAD || git name-rev --name-only HEAD)

I found the first part failing for rebase, so in case of a rebase the second part should work.

For the source, I parse the GITHEAD env variable but check for patches or stash application, since I want to handle those cases differently (and patches do not leave GITHEAD)

For stash apply:

stash=$(env | grep -E 'GITHEAD_[0-9a-f]{40}\b*=\b*Stashed changes' | wc -l)

$stash will be 1 in case we are in a stash, 0 otherwhise

For patches I count number of GITHEAD, which must be zero:

githeadNum=$(env | grep GITHEAD | wc -l)
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!