Pull to refresh

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

Reading time 2 min
Views 23K

Контекст


Предположим мы поддерживаем небольшой 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 можно добавить вызов какого либо скрипта, выполнение которого необходимо для полного развертывания кода. Например, очистка кэша, сборка файлов локали, обновление БД и т.д…

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


Tags:
Hubs:
+6
Comments 9
Comments Comments 9

Articles