Перейти к содержанию

8. Git в CI/CD и автоматизации

Цель темы: понимать, как Git используется в пайплайнах: клонирование (в том числе shallow, по ветке/тегу), теги для релизов, типовые сценарии checkout → build и переменные окружения в CI; основы подмодулей и безопасность (токены, секреты).


Определения терминов

Shallow clone (неглубокий клон)

Shallow clone — клонирование с ограниченной глубиной истории (например, только последний коммит или последние N коммитов). Задаётся опцией --depth. Ускоряет clone и экономит место на агентах CI, но не все операции (например, полный git log или некоторые merge) могут быть доступны без «углубления» репозитория.

Тег (tag)

Тег — именованная ссылка на коммит, которая не двигается (в отличие от ветки). Обычно используется для релизов: v1.0.0, release-2024-01. В CI по тегу часто собирают воспроизводимый артефакт и деплоят.

Подмодуль (submodule)

Подмодуль — отдельный Git-репозиторий, подключённый как подкаталог в другом репозитории. Родительский репо хранит только ссылку на конкретный коммит подмодуля. В CI при клонировании нужно явно инициализировать и обновить подмодули (git submodule update --init).

Sparse checkout

Sparse checkout — проверка только выбранных каталогов/файлов репозитория. Уменьшает объём данных при clone и ускоряет работу в больших репо. Настраивается через git sparse-checkout (Git 2.25+).


Клонирование в CI

Обычный clone

git clone https://github.com/org/repo.git
cd repo

В CI часто используют URL с токеном или SSH-ключом для доступа к приватному репо (см. раздел «Безопасность»).

Shallow clone (ограничение глубины)

git clone --depth 1 https://github.com/org/repo.git

Только последний коммит; история не подтягивается. Для сборки по текущей ветке этого обычно достаточно.

git clone --depth 50 https://github.com/org/repo.git

Последние 50 коммитов. Удобно, если в пайплайне нужен неглубокий, но не единственный коммит (например, для git describe или неглубокого лога).

Практика

В CI по умолчанию используйте shallow clone для скорости. Если нужна полная история (bisect, полный changelog), клонируйте без --depth или увеличьте глубину.

Клон конкретной ветки или тега

git clone --branch main https://github.com/org/repo.git
git clone --branch v1.0.0 https://github.com/org/repo.git

Сразу после clone будет проверена указанная ветка или тег. Комбинируют с --depth 1 для экономии времени.

Checkout по коммиту (воспроизводимая сборка)

Пайплайн часто получает хеш коммита из триггера (push, merge request). Проверка этого коммита даёт воспроизводимую сборку:

git fetch origin
git checkout $CI_COMMIT_SHA
# или после shallow clone по ветке:
git fetch --depth 1 origin $CI_COMMIT_SHA
git checkout $CI_COMMIT_SHA

Артефакт можно тегировать хешем: app:$CI_COMMIT_SHA или app:${CI_COMMIT_SHORT_SHA}.


Sparse checkout (только нужные каталоги)

В больших репозиториях можно вытянуть только часть дерева:

git clone --filter=blob:none --sparse https://github.com/org/repo.git
cd repo
git sparse-checkout set path/to/app docs

Дальнейшая работа только с указанными путями; остальное не загружается. Поддерживается в Git 2.25+; в старых версиях — через core.sparseCheckout и .git/info/sparse-checkout.


Теги (tags)

Создание и отправка тегов

git tag v1.0.0
git tag -a v1.0.0 -m "Release 1.0.0"
git push origin v1.0.0

Тег без -a — «лёгкий» (lightweight), только указатель на коммит. С -a — аннотированный тег (сообщение, автор, дата); для релизов обычно используют аннотированные.

Семантическое версирование

Распространённая схема: vMAJOR.MINOR.PATCH (например, v1.2.3). В CI по такому тегу собирают релизный артефакт и деплоят.

Удаление тега

git tag -d v0.9
git push origin --delete v0.9

Checkout по тегу в CI

git clone --depth 1 --branch v1.0.0 https://github.com/org/repo.git
# или после обычного clone:
git fetch origin tag v1.0.0
git checkout v1.0.0

Production

Релизный пайплайн запускается при push тега v*. Скрипт клонирует репо по этому тегу, собирает образ/артефакт с версией из тега и публикует в registry. Деплой идёт из того же тега — воспроизводимость гарантирована.


Подмодули (submodules) — кратко

Добавление подмодуля

git submodule add https://github.com/org/lib.git path/to/lib
git add path/to/lib
git commit -m "Add lib as submodule"

В репозитории сохраняется путь и фиксированный коммит подмодуля.

Клонирование репо с подмодулями в CI

git clone --recurse-submodules https://github.com/org/repo.git
# или после обычного clone:
git submodule update --init --recursive

Без --init/--recurse-submodules каталоги подмодулей будут пустыми, сборка может упасть.

Внимание

В CI при shallow clone родительского репо подмодули по умолчанию клонируются полностью. Для очень больших подмодулей можно задать глубину: git submodule update --init --depth 1.


Переменные и сценарии в CI

Типовые переменные окружения

В пайплайнах (GitHub Actions, GitLab CI, Jenkins и др.) после checkout часто доступны переменные, связанные с Git:

Переменная (пример) Описание
GIT_COMMIT / CI_COMMIT_SHA Хеш коммита
GIT_BRANCH / CI_COMMIT_REF_NAME Имя ветки или тега
GIT_TAG Тег (если сборка по тегу)
CI_COMMIT_SHORT_SHA Короткий хеш (7–8 символов)

Точные имена зависят от системы (см. документацию вашего CI).

Типовой сценарий в пайплайне

  1. Checkout — клонирование по ветке или получение коммита из триггера.
  2. Подмодули (если есть) — git submodule update --init --recursive.
  3. Сборка — сборка с передачей версии из Git (хеш или тег) в артефакт.
  4. Публикация — образ/артефакт с тегом, например app:${CI_COMMIT_SHORT_SHA} или app:v1.0.0.

Пример передачи версии в сборку (Docker):

docker build -t app:${CI_COMMIT_SHORT_SHA} --build-arg VERSION=${CI_COMMIT_SHORT_SHA} .

Безопасность

Не коммитить секреты

Пароли, ключи API, токены не должны попадать в репозиторий. Используйте .gitignore для локальных конфигов (.env, *.pem), секреты передавайте через переменные окружения CI и хранилища секретов (GitHub Secrets, GitLab CI Variables, Vault).

Токены для clone/push в CI

  • GitHub: Personal Access Token (PAT) или встроенный GITHUB_TOKEN в Actions; сохранять в Secrets, не в коде.
  • GitLab: Deploy token или CI Job Token; переменные с флагом «masked» для логов.
  • URL с токеном: https://oauth2:${TOKEN}@gitlab.com/org/repo.git — токен только в переменной окружения, не в скрипте.

Проверка истории на утёкшие секреты

В пайплайне можно запускать сканеры (например, gitleaks, truffleHog), которые ищут паттерны секретов в коде и истории. Лучше предотвращать попадание секретов через pre-commit и обучение, а сканер использовать как дополнительную проверку.


Паттерны использования

Паттерн Описание
Теги для релизов Везде использовать теги вида v1.0.0 для сборки и деплоя релизов; не деплоить «просто с main» без привязки к тегу/коммиту.
Shallow clone в CI По умолчанию клонировать с --depth 1 (или небольшим depth), чтобы ускорить пайплайн.
Версия артефакта из Git Вшивать в образ/артефакт хеш коммита или тег (через build-arg, метаданные), чтобы в проде было видно, что развёрнуто.
Триггер по ветке/тегу Запускать сборку только для нужных веток (main, release/*) или при push тега.

Антипаттерны

Антипаттерн Почему плохо Что делать
Хранить бинарники и артефакты в репо Раздувание репо, медленный clone. Артефакты собирать в CI и хранить в registry/артефактном хранилище.
Секреты в коде или в коммитах Утечка при доступе к репо и в логах. Секреты — только в переменных CI и .gitignore для локальных файлов.
Полный clone без необходимости Долго и тяжело на агентах. Использовать shallow clone или sparse checkout.
Деплой «с ветки» без фиксации коммита Ветка двигается, деплой невоспроизводим. Деплоить по тегу или по явному хешу коммита.

Примеры из production

Деплой по тегу

При push тега v* запускается release-пайплайн: clone по тегу → build → публикация образа с тегом v1.0.0 → деплой в staging/prod. Один тег = одна воспроизводимая версия.

Версирование артефактов

В метаданные Docker-образа или в приложение записывают GIT_COMMIT и при необходимости GIT_TAG. В проде по app --version или по лейблу образа видно точный коммит/тег.

Разные триггеры для веток

Сборка и тесты — на каждый push в main и в ветки MR. Деплой в prod — только при push тега или при merge в main с последующим созданием тега из пайплайна.


Дополнительные материалы