Reputation: 3923
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?
Upvotes: 8
Views: 6421
Reputation: 21
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
Upvotes: 1
Reputation: 13
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
Upvotes: 1
Reputation: 12140
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
Upvotes: 4