Juan Juan - 2 months ago 7
Git Question

How to prevent pushing conflicts with a pre-receive hook placed on the remote bare repo?

I have two branches on my bare repo, Master and "desarrollo" which is development in spanish. I want to create a pre-receive hook to avoid pushing conflicts to the central bare. This hook would be positioned on the central bare. This is what I have:

#!/bin/bash

protected_branch='master'





# check each branch being pushed


while read local_ref local_sha remote_ref remote_sha

do

if git diff "$old_sha" "$new_sha" | grep -qE '^+?(<<<<<|>>>>>)'; then
echo "Saw a conflict marker in $(basename "$refname")."
exit 1
fi

remote_branch=$(echo $remote_ref | sed -e 's,.*/\(.*\),\1,')

if [ $protected_branch = $remote_branch ]

then

echo "ABORT PUSH: Not allowed to push directly to $protected_branch."

exit 1 # push will not execute

fi

done

exit 0


The first part is to prevent push of conflicted files, and the second part is to prevent pushing to master, I only allow pushes to desarrollo branch. The second part works perfectly, but the first part is not preventing the pushs, but it doesn't throw errors either when I try to upload a file with markups either. I want the transaction to fail altogether, not just reject the conflicted file but the whole push in case there is even a single file in conflict:

if git diff "$old_sha" "$new_sha" | grep -qE '^+?(<<<<<|>>>>>)'; then
echo "Saw a conflict marker in $(basename "$refname")."
exit 1
fi


I must say I copied both parts from different sources, so there must be something wrong with the variable names, I just want to know is old_sha and new_sha variables are the reason of why this is failing since I'm not particularly good at making hooks

EDIT: I changed the string comparision from 5 to 7 '<<<<<<<' and now it works perfectly, the final script is

#!/bin/bash

protected_branch='master'


# check each branch being pushed


while read old_sha new_sha refname
do

if git diff "$old_sha" "$new_sha" | grep -qE '^+?(<<<<<<<|>>>>>>>)'; then
echo "Saw a conflict marker in $(basename "$refname")."
exit 1
fi

remote_branch=$(echo $refname | sed -e 's,.*/\(.*\),\1,')

if [ $protected_branch = $remote_branch ]

then

echo "ABORT PUSH: Not allowed to push directly to $protected_branch."

exit 1 # push will not execute

fi

done

exit 0

Answer

Your while seems to be wrong. As you can see on git help hooks in the section about pre-receive, the input is <old-value> SP <new-value> SP <ref-name> LF per line, so your while should probably be while read old_sha new_sha refname. Then your original conflict check should be correct and you adapt the branch protection to use $refname instead of $remote_ref, then everything should probably work.

You probably copied this part from a pre-push script where the input is <local ref> SP <local sha1> SP <remote ref> SP <remote sha1> LF per line.