Git отличная распределенная система управления версиями. Помимо возможности нескольким пользователям разрабатывать код, она позволяет быстро и легко откатывать внесенные неудачные изменения обратно. Особенно это актуально, если были закомичены какие-то фатальные правки и код выкачен в продакшн.
Но все же лучше предотвращать попадание таких комитов в центральный репозиторий, нежели поспешно откатываться на предыдущую стабильную версию. Для реализации этой возможности в системе управления версиями GIT существуют хуки (hooks). Под катом приведен пример систем использующейся в одном из наших проектов.
Общее
В рамказ данной статьи рассмотрим “pre-receive“ хук. Он является наиболее интересным для нас, поскольку позволяет, при попытке разработчиком закомитить свои изменения, просмотреть их и отклонить, если не будет выполнятся какое-то из условий. Благодаря этому можно реализовать две простые, но очень полезные вещи:
- Проверка синтаксиса.
- Запрет комитита миграций БД, которые содержат в себе операции типа “ALTER”, “DELETE”, “DROP”, “TRUNCATE”.
Обработчик “pre-receive” события
#!/bin/sh
# Pre-receive hook executerif [ -z “$GIT_DIR” ]; then
echo “Don’t run this script from the command line.” >&2
exit 1
fi
while read OLDREV NEWREV REFNAME ; do
for script in `find $PWD/hooks/pre-receive.d/ -perm -100 ! -type d`
do
$script “$OLDREV” “$NEWREV” “$REFNAME” || exit $?
done
done
exit 0
Проверка синтаксиса PHP
#!/bin/sh
# A pre-receive hook to disallow php syntax errors to be
# committed by running php -l (lint) on them.EXT=”0″
NOREV=”0000000000000000000000000000000000000000″
OLDREV=$1
NEWREV=$2
REFNAME=$3
TMP_DT=$(mktemp /tmp/git.php-syntax-check.XXXXXX)
git diff-tree -r “$OLDREV” “$NEWREV” > $TMP_DT
while read old_mode new_mode old_sha1 new_sha1 status name
do
# Skip lines showing parent commit
if [ -z “$new_sha1” ]; then continue; fi
# Skip deletions
if [ “$new_sha1” = “$NOREV” ]; then continue; fi
# Check only .php files
if [ `echo $name | grep “\.php$” | wc -l` -ne 0 ]
then
CHK=`git cat-file blob $new_sha1 | /usr/local/bin/php -l`
RET=$?
if [ $RET -ne 0 ]
then
echo
echo “!!!! PUSH REJECTED !!!!”
echo
echo “Errors parsing $name.”
echo “LOL! Check your syntax.”
echo
EXT=”1″
fi
fi
done < $TMP_DT
rm -f $TMP_DT
exit “$EXT”
Проверка миграций mysql
Источник#!/bin/sh
# Pre-receive hook discarding DELETE, ALTER, DROP and TRUNCATE table migrations
EXT=”0″
NOREV=”0000000000000000000000000000000000000000″
OLDREV=$1
NEWREV=$2
REFNAME=$3
TMP_DT=$(mktemp /tmp/git.discard-alter-table.XXXXXX)
git diff-tree -r “$OLDREV” “$NEWREV” > $TMP_DT
while read old_mode new_mode old_sha1 new_sha1 status name
do
# Skip lines showing parent commit
if [ -z “$new_sha1” ]; then continue; fi
# Skip deletions
if [ “$new_sha1” = “$NOREV” ]; then continue; fi
# Check only .sql files
if [ `echo $name | grep “\.sql$” | wc -l` -ne 0 ]
then
if [ `git cat-file blob $new_sha1 | egrep -i “delete|alter|drop|truncate” | wc -l` -ne 0 ]
then
echo
echo “!!!! PUSH REJECTED !!!!”
echo
echo “DELETE, ALTER, DROP & TRUNCATE TABLE operations are not allowed.”
echo “Please contact system administrator.”
echo
EXT=”1″
fi
fi
done < $TMP_DT
rm -f $TMP_DT
exit “$EXT”