Путь кода до продакшена
локально -> ветка -> PR -> CI (тесты) -> ревью -> main -> сборка -> staging -> prodGit здесь — единый источник правды: что лежит в main, то готово к выкату, а тег фиксирует, что именно выехало.
Локальные проверки: Git hooks
Хуки — скрипты, которые Git запускает на определенных событиях. Лежат в .git/hooks, но туда не попадают в репозиторий. Чтобы хуки были общими, храните их в папке проекта:
mkdir .githooksgit config core.hooksPath .githooks.githooks/pre-commit:
#!/bin/sh./gradlew spotlessCheck || exit 1chmod +x .githooks/pre-commitОсновные хуки:
| Хук | Когда запускается |
|---|---|
pre-commit | перед коммитом: форматирование, линтер |
commit-msg | проверка сообщения коммита |
pre-push | перед push: быстрые тесты |
Хуки можно обойти (--no-verify), поэтому настоящие проверки должны дублироваться в CI.
CI: непрерывная интеграция
CI автоматически собирает проект и запускает тесты на каждый push и Pull Request. Пример для GitHub Actions: .github/workflows/ci.yml:
name: CIon: push: branches: [main] pull_request: branches: [main]jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: distribution: temurin java-version: 21 cache: gradle - run: ./gradlew buildВ Branch protection сделайте задачу test обязательной: PR с красными тестами нельзя будет слить.
CD: непрерывная доставка
После слияния в main выкладываем автоматически. Пример деплоя по SSH на VPS: .github/workflows/deploy.yml:
name: Deployon: push: branches: [main]jobs: deploy: runs-on: ubuntu-latest environment: production steps: - uses: actions/checkout@v4 - name: Prepare SSH run: | mkdir -p ~/.ssh echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 ssh-keyscan -H ${{ secrets.DEPLOY_HOST }} >> ~/.ssh/known_hosts - name: Upload run: rsync -az --delete --exclude .git ./ ${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}:/var/www/app/ - name: Restart run: ssh ${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }} "sudo systemctl restart app"Секреты задаются в GitHub: Settings → Secrets and variables → Actions. В репозитории их хранить нельзя.
Параметр environment: production позволяет включить ручное подтверждение деплоя и отдельные секреты для окружения.
Окружения
| Окружение | Назначение | Откуда выкатывается |
|---|---|---|
| dev | разработка и эксперименты | ветки, автоматически |
| staging | копия прода для проверки | main, автоматически |
| production | реальные пользователи | тег или ручное подтверждение |
Настройки окружений (адреса баз, ключи) задаются через переменные окружения, а не коммитятся в код.
Релизы и версии
Релиз помечается тегом:
git switch maingit pullgit tag -a v1.4.0 -m "Release 1.4.0"git push origin v1.4.0Пример workflow, который собирает релиз по тегу:
name: Releaseon: push: tags: ['v*']jobs: release: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v4 - run: ./gradlew build - uses: softprops/action-gh-release@v2 with: files: build/libs/*.jar generate_release_notes: trueЧерез GitHub CLI:
gh release create v1.4.0 --generate-notesВерсии выбирайте по семантическому версионированию. Changelog можно генерировать из Conventional Commits.
Релизные ветки
Если нужно поддерживать старую версию, делайте ветку от тега:
git switch -c release/1.3 v1.3.0git push -u origin release/1.3Исправления сначала вливаются в main, затем переносятся в релизную ветку через cherry-pick.
Hotfix: срочное исправление
Критичная ошибка на проде:
git switch maingit pullgit switch -c hotfix/payment-timeoutgit add .git commit -m "fix(payment): increase gateway timeout"git push -u origin hotfix/payment-timeoutДальше: PR в main с ускоренным ревью, зеленый CI, слияние, выкат, тег v1.4.1. Если используется Git Flow, hotfix вливается и в main, и в develop.
Не правьте код прямо на сервере: исправление потеряется при следующем деплое, а история не сохранится.
Откат
Если релиз сломал прод, есть два пути.
1. Выкатить предыдущий тег. Самый быстрый и надежный способ:
git switch --detach v1.3.0В CD обычно запускают деплой старого тега или артефакта через кнопку или команду.
2. Revert сломанных изменений:
git switch maingit pullgit revert -m 1 хэш-слиянияgit pushПосле push CI выкатит исправленное состояние. Историю main не переписывайте (reset --hard и push --force запрещены).
После отката разберитесь в причине и вернитесь к исправлению в отдельной ветке.
Секреты
- Не коммитьте пароли, токены, приватные ключи,
.env. - Храните секреты в GitHub Secrets, Vault, менеджере секретов облака.
- Для локальной разработки используйте
.envв.gitignoreи.env.exampleв репозитории. - Включите Secret scanning и Push protection на GitHub.
- Если секрет попал в репозиторий: сразу замените его, затем чистите историю.
Безопасность репозитория
- Включите двухфакторную аутентификацию.
- Используйте SSH-ключи или токены с минимальными правами.
- Подписывайте коммиты (
git config --global commit.gpgsign true) там, где это требуется. - Следите за обновлениями зависимостей: Dependabot.
- Ограничьте, кто может пушить в
mainи создавать теги релизов.
Чек-лист перед продом
- Тесты и линтеры зеленые в CI.
- PR прошел ревью, ветка актуальна.
- Миграции базы проверены и обратимы.
- Секреты и настройки окружения заданы.
- Известно, как откатить релиз.
- Релиз помечен тегом, есть описание изменений.
- После выката проверены логи и метрики.
