Инструменты
Что такое .gitignore и как его правильно настроить
.gitignore говорит Git, какие файлы не коммитить в репозиторий. Разбираем синтаксис, готовые шаблоны и типичные ошибки.
Рано или поздно разработчик упирается в этот выбор: настраиваете пайплайн CI/CD, пишете docker-compose.yml или решаете, в чём хранить настройки своего приложения — в .env-файле, JSON, YAML или TOML. Три формата конфигурации — YAML, JSON и TOML — внешне похожи (текст, вложенные структуры, пары «ключ — значение»), но по синтаксису, типам данных и рискам использования различаются сильно. Разбираем, чем они отличаются и какой выбрать для своего проекта: наравне с .gitignore, это один из файлов, с которым разработчик сталкивается в каждом репозитории.
Коротко: JSON — строгий формат для машин и API, без комментариев, с минимумом сюрпризов. YAML — человеко-читаемый формат с поддержкой комментариев и глубокой вложенности, но чувствительный к отступам — выбор для CI/CD, Docker Compose и Kubernetes. TOML — плоский формат для конфигов, которые человек редактирует руками: строгая типизация, читаемый синтаксис, пример — pyproject.toml и Cargo.toml. Сомневаетесь — берите JSON: он самый предсказуемый.

JSON (JavaScript Object Notation) — текстовый формат обмена данными на основе пар «ключ — значение» и вложенных объектов/массивов в фигурных и квадратных скобках. Формат строго определён в RFC 8259: он не зависит от языка программирования, не поддерживает комментарии и требует точных кавычек и запятых — ни одного «лишнего» символа формат не прощает.
YAML (YAML Ain't Markup Language) — формат сериализации данных, который делает ставку на читаемость человеком: вложенность задаётся отступами, а не скобками, поддерживаются комментарии через #, якоря и ссылки на повторяющиеся блоки. Технически YAML — надмножество JSON: любой корректный JSON-документ одновременно является валидным YAML.
TOML (Tom's Obvious, Minimal Language) создавался специально для конфигурационных файлов. По официальной спецификации TOML, цель формата — однозначно (без двусмысленностей) маппиться в хэш-таблицу и при этом легко читаться и писаться человеком. TOML поддерживает комментарии через #, строгие типы (строки, целые и дробные числа, булевы значения, дата/время, массивы, таблицы) и секции вида [section] для группировки настроек.
Отдельно стоит JSON Lines — построчный вариант JSON для потоковой обработки данных, мы разбирали его в статье «Что такое JSONL»; к конфигурационным файлам он отношения не имеет, это формат для логов и датасетов.
Главные практические различия — в том, что формат «прощает», а что требует точности до символа.
| Параметр | JSON | YAML | TOML |
|---|---|---|---|
| Комментарии | Нет | Да, через # | Да, через # |
| Вложенность | Скобки {}/[] | Отступы (пробелы, без табов) | Секции [section], плоская структура удобнее глубокой |
| Кавычки у строк | Обязательны двойные | Опциональны в большинстве случаев | Обязательны (одинарные или двойные — разный смысл экранирования) |
| Даты «из коробки» | Нет — только строка | Есть (ISO-формат распознаётся автоматически) | Есть, нативный тип datetime |
| Якоря и ссылки на блоки | Нет | Есть (&anchor, *ref) | Нет |
| Чувствительность к отступам | Нет | Критична — лишний пробел ломает документ | Нет |
| Глубокая вложенность | Нормально читается | Нормально читается | Неудобна — секции приходится повторять целиком ([a.b.c]) |
Отдельный случай — сравнение структурированных форматов данных вообще, без привязки к конфигам: если интересует, чем JSON отличается не от YAML/TOML, а от XML, — у нас есть отдельный разбор «Чем отличается JSON от XML».
JSON — формат для машинной генерации и машинного чтения в первую очередь: REST API, ответы серверов, обмен данными между сервисами. Его главные плюсы для этой роли — строгая, однозначная грамматика (почти в каждом языке программирования есть встроенный парсер) и отсутствие двусмысленных конструкций.
Минус для ручного редактирования — отсутствие комментариев. Если конфиг пишет и читает человек, а не только программа, отсутствие возможности оставить пояснение рядом с настройкой быстро становится неудобством. Поэтому JSON реже выбирают для файлов, которые правят вручную и часто, — там, где нужна читаемость, обычно идут YAML или TOML.
YAML — стандарт де-факто для конфигураций с глубокой вложенной структурой, которые при этом должен понимать человек: пайплайны CI/CD (GitLab CI, GitHub Actions), docker-compose.yml, манифесты Kubernetes. Комментарии и человеко-читаемый синтаксис делают такие файлы самодокументируемыми — рядом с настройкой можно сразу объяснить, зачем она нужна.
Минус — обратная сторона той же читаемости: вложенность держится на отступах, и случайный лишний пробел (или смешение пробелов с табуляцией) меняет структуру документа без явной ошибки синтаксиса. Отладка такой проблемы в большом YAML-файле иногда занимает больше времени, чем написание самого конфига. Если нужно просто открыть и посмотреть отдельный .yaml-файл без контекста проекта — см. отдельный разбор «Чем открыть YAML».
TOML проектировался как формат именно для конфигов приложений, которые человек редактирует руками, — отсюда и его растущая популярность в экосистемах с явной статической типизацией: pyproject.toml в Python, Cargo.toml в Rust. Строгие типы данных и отсутствие неявных преобразований (строка не превратится в число незаметно) снижают число ошибок конфигурации.
Минус проявляется при росте вложенности: в TOML секции описываются путём повторения полного пути ([database.connection.pool]), и чем глубже структура, тем многословнее и менее читаемым становится файл по сравнению с YAML, где вложенность видна просто по отступу.
В библиотеке PyYAML функция yaml.load(), вызванная без явного Loader, исторически умела разворачивать специальные теги (например, !python/object/new) в произвольные объекты Python — а значит, и выполнять код при загрузке чужого файла.
Это не гипотетический риск, а конкретная задокументированная уязвимость: карточка CVE-2017-18342 на сайте Red Hat описывает, что в PyYAML до версии 5.1 функция yaml.load() позволяла выполнение произвольного кода через вредоносный YAML-документ с такими тегами. Проблема не в формате YAML как таковом, а в том, как некоторые библиотеки его разбирают по умолчанию.
По документации PyYAML, начиная с версии 5.1 вызов yaml.load() без явного аргумента Loader считается устаревшим и предупреждает об этом, а с версии 6.0 требует указать загрузчик явно. Безопасная альтернатива для разбора недоверенного YAML — функция yaml.safe_load() (или явный yaml.load(data, Loader=yaml.SafeLoader)): она разбирает только базовые типы Python и не позволяет конструировать произвольные объекты.
Никогда не загружайте YAML из недоверенного источника (пользовательская загрузка, внешний API, чужой репозиторий) функцией yaml.load() без явного безопасного Loader. Для JSON и TOML такого класса уязвимостей в принципе нет — у обоих форматов нет механизма «тегов», разворачивающихся в произвольные объекты языка.
Если проект уже использует один формат, а нужно получить другой (например, выгрузить JSON-конфиг из YAML-манифеста), порядок действий одинаковый независимо от инструмента:
PyYAML + json (встроенный модуль) + tomllib/tomli; в Node.js — пакеты js-yaml и @iarna/toml; для разовой задачи без установки софта подойдёт любой онлайн-конвертер формата.:, # и кавычек внутри значений по-разному требуют экранирования в каждом формате — конвертер должен сделать это автоматически, но результат стоит визуально сверить.#-комментарии теряются безвозвратно — если они важны, сохраните исходный файл отдельно.YAML категорически не допускает символы табуляции для отступов — только пробелы, и количество пробелов на каждом уровне должно быть одинаковым. Смешение табов и пробелов — одна из самых частых причин «необъяснимой» ошибки парсинга.
JSON не прощает запятую после последнего элемента массива или объекта (в отличие от JavaScript-литералов) и требует запятую между каждой парой «ключ — значение». Обе ошибки — классика невалидного JSON, которую не всегда легко заметить глазами в большом файле.
Число, записанное в YAML или TOML без кавычек, при ручном переносе в JSON иногда случайно превращается в строку (и наоборот) — особенно если конвертация делается вручную, копированием, а не инструментом.
Двойные квадратные скобки [[section]] в TOML означают не одну секцию, а элемент массива таблиц — при повторении такой записи каждая новая создаёт ещё один элемент массива, а не перезаписывает предыдущий. Это частый источник конфигов с неожиданно размножившимися записями.
Если проблема не в самом формате, а в том, что текстовый файл при открытии показывает нечитаемые символы вместо кириллицы или спецсимволов, — это отдельная тема, разобранная в статье «Кракозябры: кодировка текстового файла».
Можно, и это не ошибка: YAML формально является надмножеством JSON, поэтому валидный JSON-фрагмент внутри YAML-файла будет разобран корректно. Обратное — вставить YAML-синтаксис (например, с комментариями) в чистый JSON-файл — не сработает: JSON-парсер такое отклонит.
Ничем на уровне формата — это два равнозначных расширения для одного и того же YAML. Короткое .yml исторически прижилось из-за ограничения в три символа в старых файловых системах Windows (вроде FAT), сейчас оба расширения используются одинаково часто.
Нет, это сознательное решение автора спецификации Дугласа Крокфорда — комментарии не входят в JSON ни в каком виде. Для конфигов, которым нужны пояснения, выбирают YAML или TOML либо используют отдельное поле вроде "_comment" как обходной путь.
Манифесты Kubernetes описывают глубоко вложенные структуры (спецификации подов, сервисов, деплойментов), а TOML неудобен именно на такой глубине — секции приходится прописывать полным путём на каждом уровне. YAML с его отступами читается в этом случае заметно компактнее.
Сам по себе просмотр YAML-файла в текстовом редакторе безопасен. Риск появляется, когда файл загружает и разбирает программа небезопасной функцией вроде yaml.load() без явного безопасного загрузчика — именно так эксплуатируется уязвимость из CVE-2017-18342, описанная выше.
Проще всего — локальным линтером или встроенной проверкой в IDE (большинство редакторов подсвечивает синтаксические ошибки всех трёх форматов прямо при редактировании) либо pre-commit хуком, который прогоняет файл через стандартный парсер формата перед коммитом.