Быстрое развертывание небольших web-приложений на сервере посредством git push

в 16:27, , рубрики: Git, Веб-разработка, развертывание, метки: ,

Контекст

Предположим мы поддерживаем небольшой web-проект. У нас есть песочница для разработки с git'ом, отладчиками и прочими полезными вещами. Сайт уже запущен, и код скопирован из песочницы на удаленный сервер. Код приходится иногда (а возможно и частенько) обновлять и дорабатывать. Любые изменения естественно обкатать в песочнице. И тут возникает вопрос: как максимально просто и удобно обновить код на сервере?

Первым же решением, пришедшим в голову, оказывается простая команда git push: мы пушаем в удаленный репозиторий и получаем обновленную версию кода на сервере. Но не все так просто.

В порыве энтузиазма настраиваем репозиторий на сервере, аккуратно прячем папочку .git от web-сервера. Однако не все так просто: после первого же изменения в песочнице заветный git push server master вернет нам что-то наподобие:

remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require 'git reset --hard' to match
remote: error: the work tree to HEAD.
remote: error: 
remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in some
remote: error: other way.
remote: error: 
remote: error: To squelch this message and still keep the default behaviour, set
remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.

Общий смысл данного сообщения: «нельзя пушать в текущую ветку non-bare репозитория, так как рабочее дерево не будет соответствовать состоянию ветки».

Стоит отметить что для bare-репозиториев такой ошибки не возникнет. Но подобный тип репозитория для наших целей совершенно не подходит.

Также ошибок не будет если мы пушаем не в текущую ветку. Результат данной операции еще дальше от нужного нам.

Концепция

Для решения возникшей проблемы воспользуемся возможностью git'а реагировать на производимые над репозиторием манипуляции посредством хуков (триггеров).

Для начала логинимся обратно на сервер и создаем продакшн ветку

git checkout -b production

Правим файл .git/hooks/post-receive. Содержимое должно быть таким:

#!/bin/sh
cd ..
env -i git merge --ff-only master

Такая настройка позволяет оставить удаленный репозиторий с текущей веткой production. А каждый push в этот репозиторий будет вызывать merge ветки master в production, что будет фактически обновлять файлы в рабочем каталоге.

Не забываем выставить разрешение на запуск скрипта:

chmod +x .git/hooks/post-receive

Радуемся и возвращаемся в песочницу. Теперь можно обновлять продакшн простой командой git push server master.

Приятные дополнения

В конец файла .git/hooks/post-receive можно добавить вызов какого либо скрипта, выполнение которого необходимо для полного развертывания кода. Например, очистка кэша или сборка файлов локали.

Источники вдохновения

Автор: foxel

Поделиться

* - обязательные к заполнению поля