Git багато хуків корисних та різних

Коли перед нами ставиться завдання при зміні кодбейсу, наприклад, в Github-репозиторії виконати перескладання/перезапуск якого-небудь програми на якомусь нашому оточенні, то перше, що спадає на думку як можливий тригер такого перескладання, це механізм, що надається тим же гітхабом. веб-хуків: при настанні будь-якої події з нашим віддаленим репозиторієм (т.к. поява нового комміту в якійсь його гілці, що відстежується) гітхаб задіє відповідний веб-хук і «дернет» вказаний у його налаштуваннях сервіс, який і запустить процес перескладання/перезапуску нашої програми. Це стандартний широко використовується і простий механізм для таких випадків, все так роблять, і таке інше…

Але що, якщо наша програма живе на хості, доступ до якого з якихось причин гітхабу не покладено? Наприклад, хост знаходиться у закритій мережі або за NAT'ом і недоступний з Інтернету? У цьому випадку можна скористатися механізмом локальних хуків самого Git, про який (механізм), як з'ясовується, мало хто знає навіть із тих, хто використовує Git вже досить тривалий час.

Коли ми створюємо локальний репозиторій (ініціалізуємо порожній, клонуємо віддалений, . ), то в папці .git, що в його корені, або в самому корені, якщо це bare-репозиторій, є папка hooks. Після ініціалізації репозиторію в цій папці зберігаються шаблони хуків для різних подій, таких як, наприклад: post-merge, post-receive, post-update та ін.

Повний опис підтримуваних подій для хуків можна знайти, наприклад, тут.

Ми скористаємося цим механізмом і реалізуємо простеньку push-to-deploy схему для нашої бідолашної програми.

Нам знадобиться два локальні репозиторії. Створимо їх, наприклад, за вказаними шляхами:

1. /opt/repo-dev/example-repo/ 2. /opt/repo-remote.git/

Перший репозиторій – це клон нашого віддаленого репозиторію example-repo на гітхабі. Другий - це bare репозиторій, копія першого, який буде служити нам виключно для обробки події post-update з появою оновлень у віддаленому репозиторії. Отже, як ми це реалізуємо?

Схема дуже проста (припустимо, ми відстежуємо гілку test, а додаток наш це node.js, керований менеджером pm2):

1. Періодично оновлюємо перший локальний репозиторій до стану, що повністю відповідає стану віддаленого репозиторію. 2. З першого локального репозиторію оновлюємо другий. 3. Як тільки HEAD у нас перемістився - з'явився новий коміт - у другому репозиторії буде задіяний хук post-update, який виконується при появі будь-яких змін у репозиторії, і який виконає необхідні дії з ребілду та рестарту програми.

Для цього ми робимо таке:

1. У першому локальному репозиторії додаємо remote - другий локальний репозиторій:

Тепер ми можемо виконувати git push з першого локального репозиторію до другого.

2. У папці /opt/repo-remote.git/hooks/ створюємо файл post-update та робимо його виконуваним:

Це звичайний шов-скрипт, але згідно з внутрішньою конвенцією Gitбез розширення .sh! Давайте додамо до нього кілька команд:

Що робить скрипт? Спочатку просто вивантажує working tree нашого bare репозиторію в папку з нашим працюючим додатком, а потім перезбирає залежності та рестартує сервіси pm2. Як бачите, жодної магії.

3. Налаштовуємо cron, який кожні n хвилин оновлюватиме перший репозиторій з віддаленого:

Т.о. тепер наш хост буде регулярним ініціатором перевіркидистанційного репозиторію — а чи не з'явилися там оновлення?

Прошу помітити, що оновлюємо локальний репозиторій ми шляхом git pull, а шляхом git reset --hard. Робиться це для того, щоб унеможливити необхідність мерджів за певного вмісту чергового комміту — ми робимо локальний репозиторій повною копією віддаленого.

4. Відразу після синхронізації першого локального репозиторію з віддаленим ми робимо пуш всіх змін до нашого псевдо-видаленого другого локального репозиторію:

Ось і все. Як тільки наш псевдо-видалений локальний репозиторій отримує ненульові зміни, Git смикає свій хук post-update, який виконує відповідний скрипт. І ми отримуємо простеньку робочу схему push-to-deploy, яку за бажання можна й надалі удосконалити відповідно до наших потреб.

«Навіщо городити таку незручну монструозну схему?!» — спитайте ви. Я спочатку ставив це ж питання, але виявилося, що з існуючим переліком хуків Git'а тільки так ми зможемо викликати необхідну обробку при будь-якому оновленні нашої гілки у віддаленому репозиторії. Потрібний нам хук post-update призначений для виконання на remote репозиторії (а частина хуків призначена для виконання на локальному репозиторії). І ми таким ось не дуже витонченим способом це псевдо-видалений репозиторій і симулювали. Можливо незабаром з'явиться ще якийсь зручніший хук, що виконується локально, і схему можна буде спростити. Але поки що так.

Буду радий будь-яким зауваженням та уточненням по суті.

Доброго всім дня!

Ви можете допомогти і перевести небагато коштів на розвиток сайту