I am trying to write a pre-receive hook to check the pattern of the commit messages using bash/shell.
I want to reject the entire push if any commit has issues. How to retrieve the commit messages?
There is an entire example, with explanations, in the git docs, that covers this. Link to the example.
Roughly translating the ruby example, we have:
#!/bin/bash
set -eo pipefail
refname="$0"
oldrev="$1"
newrev="$2"
echo "Enforcing Policies..."
# Iterate over all the commits
for commit in $(git rev-list 538c33..d14fc7); do
git cat-file commit "${commit}" | sed '1,/^$/d' | your-validator
done
After several attempts and fixing of issues and edge cases I ended with the next:
#!/bin/bash
# regexp sample to validate commit messages
COMMIT_MSG_PATTERN="^olala[0-9]{3}"
refname="$1"
oldrev="$2"
newrev="$3"
# list of commits to validate
if echo "$oldrev" | grep -Eq '^0+$'; then
# list everything reachable from $newrev but not any heads
#commits=$(git rev-list $(git for-each-ref --format='%(refname)' refs/heads/* | sed 's/^/\^/') "$newrev")
# or shorter version that also get list of revisions reachable from $newrev but not from any branche
commits=$(git rev-list $newrev --not --branches=*)
else
commits=$(git rev-list ${oldrev}..${newrev})
fi
# Iterate over all the commits
for commit in $commits; do
#echo "commit=$commit"
MSG=$(git cat-file commit "${commit}" | sed '1,/^$/d')
if echo "$MSG" | grep -qvE "$COMMIT_MSG_PATTERN" ;then
echo "$MSG"
echo "Your commit message must match the pattern '$COMMIT_MSG_PATTERN'"
exit 1
fi
done
I had a similar problem to solve and tried with the Answer from Petrov Andrey but this didn't work:
refname="$1"
oldrev="$2"
newrev="$3"
Maybe its just in newer versions but you have to read the variables from stdin
read oldrev newrev refname
echo "Old revision: $oldrev"
echo "New revision: $newrev"
echo "Reference name: $refname"
Also be carefull with:
if echo "$MSG" | grep -qvE "$COMMIT_MSG_PATTERN" ;then
echo "$MSG"
echo "Your commit message must match the pattern '$COMMIT_MSG_PATTERN'"
exit 1
fi
in a commit with multiple lines this will fail as it checks every line of the commit for the regexp. Better:
# if the regex finds no match the validation fails
if echo "$MSG" | grep -qE "$COMMIT_MSG_PATTERN" ;then
echo "Validation correct!"
else
echo "Validation failed!"
echo "Your commit message must match the pattern '$COMMIT_MSG_PATTERN'"
exit 1
fi