1.2 · Репозиторий для учёбы: git, notes/, структура
Неделя 1 · Подготовка · ⏱ ~1,5 ч · Практика
Зачем это AI-инженеру
Заголовок раздела «Зачем это AI-инженеру»К концу курса этот репозиторий станет портфолио: проекты, таблицы evals, заметки, по которым видно, как мы думаем. Работодатель смотрит GitHub раньше резюме, и аккуратная история коммитов с понятной структурой говорит больше, чем строчка «знаю RAG». Кроме того, в AI-проектах много секретов (ключи API) и больших данных (базы, эмбеддинги — векторы, в которые модель превращает тексты, неделя 4), и привычку не коммитить лишнее лучше выработать в первый день. В этой главе превращаем папку с упражнениями главы 1.1 в git-репозиторий: договариваемся о структуре, настраиваем, что git должен игнорировать, и отправляем первый коммит в приватный репозиторий на GitHub.
1. Один репозиторий на всю учёбу — monorepo
Заголовок раздела «1. Один репозиторий на всю учёбу — monorepo»Варианты: репозиторий на каждый проект или один на всё. Для учёбы удобнее один (ai-engineering-journey), где каждый крупный проект — отдельная папка со своим окружением (изолированный набор библиотек проекта; как его создаёт uv, разберём в главе 1.3). Позже лучшие проекты можно вынести в отдельные публичные репозитории для портфолио (или сделать этот публичным, предварительно проверив историю на секреты и личные данные).
ai-engineering-journey/├── README.md # the plan + progress log├── .gitignore├── .env.example # variable NAMES only, no values├── notes/│ ├── python-cheatsheet.md # AIL-1│ ├── llm-basics.md # AIL-3│ └── week-01.md # daily notes, Friday review├── exercises/│ ├── week-01/│ │ ├── pricing.py│ │ ├── orders.csv│ │ └── stats.py│ └── week-02/└── projects/ ├── 01-shop-analyst-bot/ # own pyproject.toml, own README ├── 02-support-kb-rag/ └── 04-order-investigator-agent/Принципы:
notes/— заметки своими словами. Это не мусор: перед собеседованием перечитывать будем именно их.exercises/week-NN/— короткие упражнения, можно с одним общим окружением на неделю или на весьexercises/.projects/NN-name/— у каждого проекта свойpyproject.toml(описание проекта и зависимостей),uv.lock(точные версии библиотек),README.md,tests/. Номер в имени сохраняет порядок.
Структура готова; дальше решаем, что из этих папок git хранить не должен.
2. Что такое .gitignore и чего он не делает
Заголовок раздела «2. Что такое .gitignore и чего он не делает».gitignore — список шаблонов путей, которые git не предлагает добавить. Синтаксис:
.venv/ # directory anywhere*.db # by extension, anywhere/build # only at repo root!keep.db # exception from a previous ruleВажно: .gitignore не действует на файлы, которые уже отслеживаются. Если .env уже закоммичен, добавление его в .gitignore ничего не убирает из истории. Нужно git rm --cached .env (перестать отслеживать, файл на диске остаётся), а если там был ключ — отозвать ключ (подробно в гл. 1.5), потому что из истории он никуда не делся.
Проверка, что файл игнорируется и каким правилом: git check-ignore -v .env.
3. Что игнорировать в Python/AI-репозитории
Заголовок раздела «3. Что игнорировать в Python/AI-репозитории»Зная синтаксис, составим список. В Python/AI-проекте лишнее бывает трёх видов: то, что генерируется автоматически (окружение, кеши), то, что опасно (секреты, данные), и то, что просто велико (базы, веса моделей):
| Категория | Шаблоны | Почему |
|---|---|---|
| Окружение | .venv/, venv/ |
создаётся uv sync, как node_modules в JavaScript |
| Кеши Python | __pycache__/, *.pyc, .pytest_cache/, .ruff_cache/, .mypy_cache/ |
генерируются автоматически |
| Секреты | .env, .env.*, но !.env.example |
ключи API |
| Базы данных | *.db, *.sqlite, *.sqlite3, *.db-wal, *.db-shm |
снимки базы магазина, векторные индексы; WAL-файлы рядом с базой |
| Данные | data/raw/, *.parquet (по ситуации) |
большие файлы, могут быть личными |
| Ноутбуки | .ipynb_checkpoints/ |
автосохранения Jupyter (гл. 1.4) |
| Система/IDE | .DS_Store, .idea/ |
мусор macOS и IDE |
uv.lock коммитить нужно — это lock-файл, как package-lock.json или go.sum: он делает окружение воспроизводимым. .vscode/ — по вкусу: settings.json с выбором интерпретатора полезно хранить, личное — нет.
Готовый шаблон GitHub: Python.gitignore. Можно взять его и дописать снизу свой блок (секреты, базы).
4. .env.example — контракт без секретов
Заголовок раздела «4. .env.example — контракт без секретов»Ключи API и настройки, которые отличаются от машины к машине, программа читает из переменных окружения. Чтобы не задавать их руками в каждом терминале, их держат в файле .env в корне проекта — строки ИМЯ=значение, которые библиотека загружает при старте программы (как именно — в главе 1.5). .env в git не попадает (правило выше), но тогда коллега не узнает, какие переменные нужны. Эту проблему решает .env.example:
# .env.example — copy to .env and fill in# main: DeepSeek (cloud, cheap) + Ollama (local, free)DEEPSEEK_API_KEY=DEEPSEEK_MODEL=OLLAMA_BASE_URL=http://localhost:11434/v1OLLAMA_MODEL=# optional, for comparisonANTHROPIC_API_KEY=OPENAI_API_KEY=В git лежит только список имён переменных (и несекретные значения по умолчанию вроде адреса локальной Ollama). Коллега (или мы сами через полгода) клонирует репозиторий, копирует файл в .env и вписывает свои значения. Сами ключи появятся в главе 1.5 · Видео Карпатого + ключи API.
5. Особый случай: данные магазина
Заголовок раздела «5. Особый случай: данные магазина»В проектах курса (бот-аналитик на неделе 3, MCP-сервер на неделе 9) мы работаем с базой учебного интернет-магазина «Полка»: заказы, товары, оплаты, клиенты с именами и телефонами. Это SQLite — база в одном файле .db. Базу мы сгенерируем в главе 3.1 и положим на уровень выше репозитория, в ../shop-live/; она играет роль боевой (production — та, с которой работает «настоящий» магазин). Данные выдуманы, но обращаемся с ними как с настоящими — эта привычка понадобится на работе. Правила с первого дня:
- в учебный репозиторий никогда не попадает ни «боевая» база из
../shop-live/, ни её снимки, ни выгрузки заказов и клиентов; - для работы берётся снимок базы через
VACUUM INTO— команду SQLite, которая записывает целостную копию базы в новый файл. Обычныйcpне подходит: база работает в режиме WAL (свежие изменения сначала пишутся в соседний файл-walи лишь потом переносятся в основной), и копия одного файла может оказаться несогласованной. Лежит снимок вне репозитория или в игнорируемой папке (data/); - для публичного портфолио — только выдуманные демо-данные без личных данных, сгенерированные скриптом (в git — скрипт, а не база).
Если есть свои данные и право их использовать, можно работать с ними вместо базы «Полки» — правила те же. Правило *.db в .gitignore — страховка, а не замена этой дисциплине.
6. Коммиты, которые приятно читать
Заголовок раздела «6. Коммиты, которые приятно читать»Когда понятно, что в репозиторий не попадает, остаётся договориться, как в нём фиксировать работу.
- Один коммит — одна логическая единица: «week-01: pricing and csv stats exercises», а не «update».
- Коммитим каждый день в конце сессии, в пятницу — обзор недели в
notes/week-NN.md. - Перед каждым коммитом:
git statusиgit diff --staged— глазами, что именно уходит. Это 10 секунд, которые ловят случайный.envили дамп базы.
7. Приватный удалённый репозиторий
Заголовок раздела «7. Приватный удалённый репозиторий»Создать можно в веб-интерфейсе GitHub (New repository → Private) или через GitHub CLI: gh repo create ai-engineering-journey --private --source=. --remote=origin. Ветки в учебном репозитории не обязательны — работаем в main; ветка пригодится для экспериментов, которые могут не взлететь.
DeepSeek и Ollama: как это сделать у нас
Заголовок раздела «DeepSeek и Ollama: как это сделать у нас»Учимся мы на DeepSeek (облако, дёшево, OpenAI-совместимый API, серверы в Китае) и Ollama (локальные модели); Claude и OpenAI — для сравнения. Для репозитория это меняет три мелочи:
.env.exampleперечисляетDEEPSEEK_API_KEYи имена моделей как основные, ключи Anthropic/OpenAI — как необязательные (шаблон выше). Имена моделей держим в окружении, не в коде: у DeepSeek они меняются.- Веса моделей в репозиторий не попадают. Веса — файлы с параметрами модели, гигабайты чисел. Ollama хранит модели в
~/.ollama, вне репозитория, — так и оставляем. Но на неделе 11 (LoRA) появятся свои файлы весов и адаптеров:*.gguf,*.safetensorsи папкуmodels/стоит добавить в игнор заранее — это гигабайты. - Граница данных проходит и через заметки. Ответы DeepSeek на учебные вопросы можно сохранять в
notes/. А всё, что касается личных данных клиентов магазина (и, на работе, рабочего кода и всего, что нельзя показывать посторонним), идёт только через локальную Ollama — ни в одну облачную модель. Результаты таких прогонов (даже «просто вывод модели») — в игнорируемую папку, потому что модель пересказывает имена, телефоны и суммы.
| Claude / OpenAI | DeepSeek | Ollama | |
|---|---|---|---|
Секрет в .env |
ANTHROPIC_API_KEY, OPENAI_API_KEY |
DEEPSEEK_API_KEY |
нет (адрес localhost — не секрет) |
| Что может попасть в git по ошибке | ключ | ключ | веса модели, вывод по реальным данным |
| Что игнорировать | .env |
.env |
*.gguf, *.safetensors, models/, outputs/ с реальными данными |
Маршрут изучения
Заголовок раздела «Маршрут изучения»- Если git уверенно знаком — пропускаем. Иначе открываем Pro Git на русском → глава 2 «Основы Git» (разделы 2.1–2.5: запись изменений, игнорирование файлов, просмотр истории, удалённые репозитории) (≈40 мин). Особенно важны раздел про
.gitignoreиgit rm --cached. - Открываем шаблон Python.gitignore → пробегаем глазами (≈5 мин): там уже есть
.venv,__pycache__,.env, а баз данных нет. - (По желанию) Pro Git, глава 3 «Ветвление в Git», разделы 3.1–3.2 (≈20 мин) — пригодится для экспериментов на неделе 8.
- Ollama на macOS → раздел о расположении файлов (≈5 мин; для Linux и Windows в документации есть такие же разделы). Берём оттуда: модели и логи лежат в
~/.ollama, вне репозитория; модели весят от гигабайта до сотен гигабайт. Саму установку делаем в главе 1.5 (гл. 1.5).
На что обратить внимание
Заголовок раздела «На что обратить внимание»- Сначала
.gitignore, потомgit add. Если сделатьgit add .до создания.gitignore, в индекс попадут.venvи всё остальное. git add .— опасная привычка в репозитории с данными. Добавлять стоит осознанно или хотя бы смотретьgit statusперед коммитом.- Уже закоммиченный секрет не исправляется новым коммитом. История хранит всё; даже переписанная история могла уйти в форк или кеш. Единственная надёжная мера — отозвать ключ.
- Большие файлы. GitHub отклоняет файлы больше 100 МБ, и даже меньшие раздувают историю навсегда. Датасеты и индексы — в игнор, в README — команда, как их пересоздать.
- Вывод ноутбуков может содержать данные и даже значения переменных окружения, если их напечатали. Об этом в гл. 1.4.
- Личные данные в заметках. Если репозиторий станет публичным, в
notes/не должно быть реальных сумм, имён клиентов, телефонов, названий аккаунтов.
Практика
Заголовок раздела «Практика»- Инициализируем git в папке из главы 1.1 (если её ещё нет, команда её создаст):
Окно терминала mkdir -p ~/ai-engineering-journey && cd $_ # $_ = last argument of the previous commandgit init -b mainmkdir -p notes exercises/week-01 projects - Создаём
.gitignore: берём содержимое Python.gitignore и дописываем снизу свой блок:# --- secrets ---.env.env.*!.env.example# --- databases (never commit shop data or its copies) ---*.db*.sqlite*.sqlite3*.db-wal*.db-shm# --- model weights and outputs on real data ---*.gguf*.safetensorsmodels/outputs/# --- notebooks, OS ---.ipynb_checkpoints/.DS_Store - Создаём
.env.exampleпо шаблону из теории: основныеDEEPSEEK_API_KEY=,DEEPSEEK_MODEL=,OLLAMA_BASE_URL=http://localhost:11434/v1,OLLAMA_MODEL=; необязательные (для сравнения)ANTHROPIC_API_KEY=иOPENAI_API_KEY=. - Переносим план: в
README.mdв корне репозитория выписываем недели курса (по оглавлению книги) и добавляем в начало раздел «Прогресс» — список недель с галочками. - Проверяем, что шпаргалка
notes/python-cheatsheet.mdи упражнения из гл. 1.1 лежат вnotes/иexercises/week-01/; если они создавались в другом месте — переносим. - Проверка игнора — создаём ловушки и убеждаемся, что git их не видит:
Окно терминала echo "DEEPSEEK_API_KEY=fake" > .envtouch test.db model.ggufgit status # .env, test.db, model.gguf must NOT be listedgit check-ignore -v .env test.db model.ggufrm test.db model.gguf - Первый коммит:
git add .gitignore .env.example README.md notes exercises, затемgit status,git diff --staged --statглазами,git commit -m "init: structure, gitignore, plan". - Создаём приватный репозиторий на GitHub, привязываем
origin, отправляемmain. Проверяем в веб-интерфейсе, что.envтам нет. - Заводим
notes/week-01.mdс шаблоном дня: «Что сделано / Что понято / Что не получилось / Вопросы».
Готово, когда
Заголовок раздела «Готово, когда»- Приватный репозиторий
ai-engineering-journeyесть на GitHub, первый коммит отправлен. - Структура
notes/,exercises/week-01/,projects/на месте,README.mdс планом в корне. -
git statusпри наличии.envи*.dbв папке их не показывает.
Тест для самопроверки
Заголовок раздела «Тест для самопроверки»Вопрос 1
.env с ключом закоммитили, потом добавили .env в .gitignore и закоммитили снова. Ключ в безопасности?
Нет. Ключ остался в истории первого коммита (и, если был push, на GitHub). Нужно немедленно отозвать ключ в консоли провайдера и выпустить новый.
Вопрос 2
Какая команда перестаёт отслеживать файл, не удаляя его с диска?
b. --cached убирает файл из индекса; git rm без флага удалит и с диска.
Вопрос 3
Нужно ли коммитить uv.lock? Почему?
Да. Это lock-файл, фиксирующий точные версии всех зависимостей (как package-lock.json или go.sum); без него окружение на нашей машине и на CI может отличаться.
Вопрос 4
Зачем !.env.example после .env.*?
Правило .env.* поймало бы и .env.example; ! делает исключение, чтобы шаблон с именами переменных попадал в git.
Вопрос 5
Почему в .gitignore стоит *.db-wal и *.db-shm?
SQLite в режиме WAL держит рядом с базой файлы журнала и общей памяти; в них могут быть свежие данные, и в git им не место, как и самой базе.
Вопрос 6
Что не так в последовательности команд?
git initgit add .git commit -m "init"echo ".venv/" > .gitignore.gitignore создан после git add .: в первый коммит уже попали .venv и всё остальное, включая возможные секреты. Сначала .gitignore, потом add.
Вопрос 7
Как узнать, каким именно правилом игнорируется файл?
git check-ignore -v <путь> — покажет файл и строку правила.
Вопрос 8
Почему снимок базы магазина нужно делать через VACUUM INTO, а не cp?
База в режиме WAL: часть данных может лежать в -wal, и простое копирование файла во время работы даёт несогласованную копию. VACUUM INTO делает целостный снимок средствами самого SQLite.
Вопрос 9
Какие данные можно класть в публичную версию проекта-аналитика магазина?
c. Только вымышленные данные. Даже снимок и «обезличенная» выгрузка раскрывают реальную активность (суммы, состав заказов, города) и не нужны для демонстрации.
Вопрос 10
Что делать с датасетом на 300 МБ, который нужен проекту?
Не коммитить: положить в игнорируемую папку data/ и описать в README, откуда его скачать или каким скриптом сгенерировать.
Вопрос 11
Какие из этих строк в .env.example нормальны, а какие нет: DEEPSEEK_API_KEY=, OLLAMA_BASE_URL=http://localhost:11434/v1, DEEPSEEK_API_KEY=sk-...? Почему у Ollama нет ключа?
Пустой DEEPSEEK_API_KEY= и адрес локальной Ollama — нормально: это имена и несекретное значение по умолчанию. Строка с настоящим ключом — утечка, ключ надо отозвать. У локальной Ollama нет аутентификации: она слушает только localhost, SDK openai требует какую-то строку в api_key, но Ollama её игнорирует.
Вопрос 12
Локальную модель Ollama прогнали по снимку базы магазина и сохранили её ответы в notes/orders-summary.md. Данные никуда не отправлялись. Можно это коммитить?
Нет. Локальная модель защищает данные от отправки наружу, но её ответ пересказывает заказы и личные данные клиентов; в git (а потом, возможно, в публичный репозиторий) он попадать не должен. Такие выводы — в игнорируемую папку (outputs/).
Что дальше
Заголовок раздела «Что дальше»Глава 1.3 · Python: uv, async, Pydantic: в exercises/ появится первый настоящий Python-проект с окружением, lock-файлом, тестами и линтером. Потом глава 1.4 · Jupyter-ноутбуки в VS Code подключит к нему Jupyter, а в главе 1.5 (гл. 1.5) мы заполним .env ключом DeepSeek и поставим Ollama.