В git-репозитории dbt-проекта живёт только код: модели, тесты, YAML, макросы. Всё остальное — артефакты, локальные настройки, секреты — должно быть исключено. В этом уроке разбираемся, что и почему.
Стандартный .gitignore для dbt
Минимальный набор:
# dbt artifacts
target/
dbt_packages/
logs/
# dbt user-specific
.user.yml
# Credentials (CRITICAL)
profiles.yml
.dbt/
*.duckdb # локальный DuckDB файл с данными
# Python venv
.venv/
venv/
__pycache__/
*.pyc
# IDE
.vscode/
.idea/
*.swp
# OS
.DS_Store
Thumbs.db
Этот файл лежит в корне проекта рядом с dbt_project.yml. После git init обычно создаётся автоматически шаблоном dbt init, но содержимое стоит проверить.
Разбор каждой строки
target/ — артефакты dbt
После каждого dbt run, dbt compile, dbt build папка target/ пересоздаётся. Внутри:
compiled/— финальный SQLrun/— SQL с CREATE-обёрткойmanifest.json— структура проектаrun_results.json— результаты последнего runcatalog.json— метаданные warehouse
Это локальные артефакты для тебя. У каждого разработчика и в CI они свои. Не должны быть в git.
Исключение: в CI manifest.json от main-билда сохраняется как production-artifact в S3 / GitHub Actions Artifacts — но это не в git-repo, а в внешнее storage. См. модуль 17 про state:modified.
dbt_packages/ — установленные пакеты
После dbt deps пакеты из packages.yml скачиваются в dbt_packages/. Это зависимости, как node_modules/ или vendor/. Не для git.
Установка воспроизводится: после git clone ты делаешь dbt deps, и dbt_packages/ восстанавливается из packages.yml + package-lock.yml.
package-lock.yml (если есть) — в git. Он содержит точные версии для воспроизводимости. dbt_packages/ — нет.
logs/ — лог-файлы
logs/dbt.log пишется каждым запуском dbt. У каждого разработчика свой, в CI свой. Логи могут содержать чувствительные данные (env_var values, PII в SELECT’ах если ты неаккуратно). Никогда не commit.
В CI логи сохраняются как artifact (S3 / GitHub Actions) для post-mortem дебага.
.user.yml — user-specific overrides
.user.yml содержит per-developer настройки dbt: какой target по умолчанию, какой schema-name pattern. Каждый разработчик заводит свой. Не commit.
profiles.yml — СЕКРЕТЫ
Это самый критичный файл. Содержит:
- Пароли к warehouse
- API-токены (Snowflake account ID, BigQuery service account)
- Connection strings
НИКОГДА не commit profiles.yml в git, даже в private-репо. Причины:
- Утечка через git history. Один раз commit — и пароль есть в истории. Удалить из истории сложно (rewrite + force push, ломает чужие checkouts).
- CI/CD доступ. GitHub Actions имеют свой profiles через secrets — не из репо.
- Compliance. Большинство compliance-стандартов (SOC2, ISO 27001) требуют отсутствие секретов в git.
Куда тогда profiles.yml?
- Локально у каждого разработчика — в
~/.dbt/profiles.yml. Это user-home, не в проекте. - В CI — генерируется на лету из CI-secrets (GitHub Actions secrets, GitLab CI variables, etc).
- В Cloud — настраивается через UI, dbt Cloud хранит креды.
.dbt/ — иногда внутри проекта
Некоторые команды размещают profiles.yml в .dbt/ внутри проекта (для удобства multi-environment). Это OK, но всю папку — в .gitignore.
*.duckdb — локальные данные DuckDB
Если у тебя DuckDB-проект, файл jaffle_shop.duckdb (или как назвал) — это данные. Может содержать sensitive customer info. Никогда не commit.
Размер — ещё одна причина: на больших данных duckdb-файл может быть несколько ГБ.
В CI/prod используется отдельный warehouse (Snowflake/BigQuery), не локальный DuckDB.
Python и IDE
.venv/, __pycache__/, *.pyc — стандартная Python-гигиена. .vscode/, .idea/ — IDE-настройки твоей машины.
.DS_Store, Thumbs.db — мусорные файлы от macOS / Windows. Не должны быть в репо.
Что должно быть в git
В git коммитятся:
dbt_project.yml— конфиг проектаpackages.yml— зависимости (для воспроизводимости через dbt deps)package-lock.yml— pinned versions (если используется)models/**/*.sql— моделиmodels/**/*.yml— YAML с тестами и descriptionstests/**/*.sql— singular тестыmacros/**/*.sql— макросыseeds/**/*.csv— сидовые CSV (но осторожно с большими и с PII)snapshots/**/*.sql— снэпшотыanalyses/**/*.sql— analysis filesREADME.md— описание проекта.gitignore— сам файл.pre-commit-config.yaml— pre-commit конфиг.github/workflows/*.ymlили.gitlab-ci.yml— CI пайплайныdbt-project-evaluator/или другие quality конфигиdocs/— кастомные docs-блоки (для{% docs %})
В сумме — только код проекта и его декларативные конфиги.
Работа с секретами через env_var
Чтобы profiles.yml не содержал реальные пароли, dbt предоставляет функцию env_var():
# ~/.dbt/profiles.yml
jaffle_shop:
target: dev
outputs:
dev:
type: duckdb
path: './jaffle_shop.duckdb'
prod:
type: snowflake
account: "{{ env_var('SNOWFLAKE_ACCOUNT') }}"
user: "{{ env_var('SNOWFLAKE_USER') }}"
password: "{{ env_var('SNOWFLAKE_PASSWORD') }}"
warehouse: "{{ env_var('SNOWFLAKE_WAREHOUSE') }}"
database: "{{ env_var('SNOWFLAKE_DATABASE') }}"
schema: "{{ env_var('SNOWFLAKE_SCHEMA') }}"
threads: 8
Теперь profiles.yml сам по себе не содержит секреты — только указания «возьми из env-переменной».
Локально перед dbt run:
export SNOWFLAKE_ACCOUNT='xy12345.us-east-1'
export SNOWFLAKE_USER='dbt_user'
export SNOWFLAKE_PASSWORD='secret_password_here'
dbt run --target prod
Или через .env файл + direnv / python-dotenv:
# .env (тоже в .gitignore!)
SNOWFLAKE_ACCOUNT=xy12345.us-east-1
SNOWFLAKE_USER=dbt_user
SNOWFLAKE_PASSWORD=secret_password_here
source .env && dbt run --target prod
В CI секреты передаются через CI-secrets:
# .github/workflows/dbt.yml
- name: Run dbt
env:
SNOWFLAKE_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }}
SNOWFLAKE_USER: ${{ secrets.SNOWFLAKE_USER }}
SNOWFLAKE_PASSWORD: ${{ secrets.SNOWFLAKE_PASSWORD }}
run: |
dbt build --target prod
GitHub Actions secrets — это encrypted storage, который инъектится в env только во время билда. Никогда не появляется в логах в plain text.
env_var в моделях
Иногда env_var нужен в моделях (не только в profiles). Например, фильтр по дате endpoint:
{{ config(materialized='table') }}
select * from {{ ref('stg_orders') }}
where order_date >= '{{ env_var("DATE_FROM", "2020-01-01") }}'
env_var('KEY', 'default') — второй аргумент это default, если переменной нет. Без default — dbt упадёт при отсутствии переменной.
Внимание: значение env_var попадает в compiled SQL в plain text! Если ты используешь env_var('DB_PASSWORD') в модели и compile — увидишь пароль в target/compiled/.../*.sql. Это не для секретов.
Правило: env_var для секретов — только в profiles.yml. В моделях — только нечувствительные значения (даты, флаги, configs).
Для секретов в моделях используют dbt vars через CLI:
dbt run --vars '{"api_key": "secret"}'
Хотя это всё равно попадёт в compiled SQL. Чистый путь — секреты живут в warehouse-side secrets (Snowflake Secret Functions, BigQuery Secret Manager) и читаются из SQL напрямую.
Что делать если случайно закоммитил profiles.yml
Сценарий: ты сделал git add . && git commit -m "..." не глядя, и потом понял, что profiles.yml попал в коммит.
Если ещё НЕ push-нул
# Откатить последний коммит
git reset HEAD~1
# Добавить в .gitignore
echo "profiles.yml" >> .gitignore
# Закоммитить .gitignore
git add .gitignore
git commit -m "chore: add profiles.yml to gitignore"
Файл остаётся локально, в коммите его нет. ОК.
Если уже push-нул
Тут хуже. Файл в git history.
# Удалить файл из истории через git filter-repo (новый инструмент)
pip install git-filter-repo
git filter-repo --invert-paths --path profiles.yml
# Force push (ВНИМАНИЕ: переписывает историю)
git push origin --force --all
КРИТИЧНО: после этого ОБЯЗАТЕЛЬНО смени все пароли, попавшие в commit. История git кэшируется (GitHub web UI, локальные клоны коллег, mirroring), и предположить, что пароль никто не увидел — нельзя. Always rotate.
Альтернатива (для GitHub):
- Делай через secrets scanning — GitHub сам найдёт известные форматы паролей в commits.
- Используй GitGuardian или подобный — alerting при commit’ах с secrets.
Pre-commit для предотвращения
Pre-commit hook до коммита проверяет:
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
detect-secrets сканирует diff на pattern’ы паролей, API ключей, AWS keys. Если что-то нашёл — commit не создаётся.
pip install pre-commit
pre-commit install
Теперь каждый git commit проверяет diff на secrets. Если find — фейл, фикс, retry. Это лучший способ не закоммитить случайно.
Большие и чувствительные seeds
seeds/ коммитятся в git. Но:
-
Не больше 1 МБ на файл. Большие CSV замедляют git и pull. Если seed >1 МБ — это уже source, не seed. Перенести в warehouse.
-
Без PII в seeds. Customer emails, phone numbers — в seeds недопустимо. Это test fixtures с фейковыми данными.
-
С header row. dbt seed читает первую строку как имена колонок.
-
UTF-8 без BOM. Excel часто экспортирует с BOM, dbt падает с ошибкой парсинга. Открой в текст-редакторе, пересохрани без BOM.
Попробуй сам
-
Открой
.gitignoreв своём dbt-проекте. Проверь, что там есть все ключевые строки:target/,dbt_packages/,logs/,profiles.yml,*.duckdb. -
Запусти
git status. Убедись, что среди untracked нетtarget/илиdbt_packages/. -
Создай
.envфайл с тестовыми переменными, добавь в.gitignore, проверь, что не виден вgit status. -
Установи pre-commit:
pip install pre-commit detect-secrets pre-commit installСоздай
.pre-commit-config.yamlс detect-secrets. Попробуй закоммитить файл с фальшивым «паролем» — увидишь блок. -
Перенеси
profiles.ymlиз проекта в~/.dbt/profiles.yml. Проверь, чтоdbt debugвсё ещё работает.
Чек-лист
- В
.gitignore:target/,dbt_packages/,logs/,profiles.yml,*.duckdb,.venv/, IDE-файлы. - В git: только код проекта + декларативные конфиги (
dbt_project.yml,packages.yml,package-lock.yml). - Секреты — через
env_var()вprofiles.yml. Никогда в git. - В CI секреты через GitHub Actions secrets / GitLab CI variables.
- В моделях — env_var только для нечувствительных значений (дат, флагов).
- Случайно закоммитил secret? Откат + rotate password — ОБЯЗАТЕЛЬНО.
- Pre-commit + detect-secrets — для предотвращения.
- Seeds: менее 1 МБ, без PII, UTF-8 без BOM.