Перейти к основному содержимому
Отдельные темы04ГЛАВА 04Анатомия взрослого репозиторияREADME.md

Анатомия взрослого репозитория

Прочитано0%
Квизы0/6
Тренажёрыне пройден0/2
Уровень 1 · Новичок

Зачем это нужно​

Код, который работает, и репозиторий, который не стыдно показать, — это две разные вещи, и вторая почти никогда не получается сама собой. Проект живёт в голове автора: он помнит, что запускать надо python main.py из папки src, что перед этим нужен pip install -r requirements.txt, что папка old — это мусор, а test2.py — на самом деле рабочий файл. Ничего из этого не знает человек, который открыл твой репозиторий: ни судья на чемпионате, ни преподаватель, ни работодатель, ни ты сам через полгода.

Эта глава — про то, что лежит в корне репозитория и почему каждый из этих файлов там оказался. Ни одного нового инструмента: ни новых команд git, кроме одной, ни новых языков. Только набор решений, которые превращают папку с кодом в проект. Слова коммит, ветка, push, PR дальше используются без объяснений — они разобраны в главах про git.

«Работает» — это только половина​

Есть простой мысленный эксперимент, который сразу расставляет всё по местам. Представь: незнакомый человек открыл твой репозиторий на GitHub. Он не знает ни тебя, ни задачу. У него на решение «разбираться или закрыть вкладку» уходит примерно тридцать секунд — ровно столько, сколько нужно, чтобы окинуть взглядом список файлов и пролистать то, что GitHub показывает под ним.

Что он видит в эти тридцать секунд:

  1. Название репозитория. project1, test-repo, новая папка — уже минус к доверию. weather-cli, pgk-schedule-bot — уже понятно, о чём речь.
  2. Список файлов в корне. Аккуратные src/, tests/, README.md — или тридцать файлов вперемешку с .DS_Store, venv/ и фото.jpg.
  3. README, который GitHub рисует прямо под списком файлов. Это единственный текст, который человек прочитает гарантированно.
  4. Даты и количество коммитов. Один коммит «init» на весь проект — сигнал, что код принесли откуда-то целиком.
ПЕРВЫЕ 30 СЕКУНД ЧУЖОГО ВЗГЛЯДАсвалкаnew 1.pyпроект_финал(2).pytest.pyvenv/.envскрин.pngни README, ни .gitignoreсобранный кореньREADME.mdLICENSE.gitignore.env.examplesrc/tests/видно, что за проект и как запустить«не буду разбираться»«похоже на рабочий проект»
Одинаковый по качеству код, два разных первых впечатления: свалка в корне против собранного корня, где сразу видно, что за проект и как его запустить.

Ключевая мысль главы: оформление репозитория ничего не говорит о качестве кода — и именно поэтому оно так сильно работает. Читатель ещё не открыл ни одного файла с кодом, оценить его он физически не успел. Всё, чем он в этот момент располагает, — косвенные признаки: аккуратно ли разложено, объяснено ли, что это. И по этим признакам он решает, стоит ли тратить время на остальное.

Обратная сторона тоже правда: красивый README не спасёт неработающий проект. Речь не о том, чтобы обмануть впечатление, а о том, чтобы не терять баллы и внимание на пустом месте — там, где работа уже сделана, но её не видно.

Хорошая новость: весь набор файлов из этой главы делается один раз за проект и занимает минут двадцать. Плохая — двадцать минут, которых почти никогда нет в конце, потому что в конце дедлайн. Поэтому правильный момент собрать корень репозитория — первый день проекта, а не последний.

Совет

Проверка, которая занимает минуту и ловит почти всё: открой свой репозиторий в браузере в режиме инкогнито (или просто выйди из аккаунта). Ты увидишь его глазами чужого человека, без подсветки «это моё» и без памяти о том, что где лежит. Если за тридцать секунд ты сам не можешь ответить «что за проект и как его запустить» — README ещё не готов.

README: единственный текст, который прочитают​

README (по-английски буквально «прочти меня») — файл README.md в корне репозитория. GitHub автоматически показывает его содержимое под списком файлов, отрендеренным из Markdown. Никакой магии, никакой настройки: положил файл с таким именем в корень — он появился на главной странице.

Обязательный минимум​

Пять пунктов, без которых README не выполняет свою работу:

  1. Что это, одной строкой. Не «Мой проект по программированию», а «Телеграм-бот, который присылает расписание пар для группы колледжа».
  2. Зачем. Какую задачу решает и для кого. Одного-двух предложений хватает.
  3. Как запустить. Команды подряд, которые можно скопировать и выполнить, ничего не додумывая.
  4. Стек. На чём написано: язык, версия, ключевые библиотеки, база данных.
  5. Скриншот или пример вывода. Картинка интерфейса или блок с реальным выводом в терминале.

Пятый пункт недооценивают чаще всего, а он самый сильный. Скриншот доказывает, что проект действительно работает, за полсекунды — быстрее любого абзаца. Для консольной программы «скриншот» — это просто блок с реальным выводом команды, скопированный из терминала.

README · ПОРЯДОК РАЗДЕЛОВ СВЕРХУ ВНИЗ# Название + одна строка «что это»читают всегда — даже когда дальше не листаютЗачем и для когокакую задачу решает, кому пригодитсяСкриншот или пример выводабыстрее любого абзаца текстаКак запуститькоманды подряд, копируются без правокСтек и структурана чём написано, где что лежитсверху то, что нужно чужому человеку в первую минуту; подробности — ниже
Порядок разделов README сверху вниз: сначала то, что чужой человек должен узнать в первую минуту, — что это, зачем, как выглядит и как запустить. Подробности — ниже.

Порядок разделов важнее их количества​

Люди читают README сверху вниз и бросают в любой момент. Значит, самое важное — первым. Рабочий порядок:

# Название проекта

Одна строка: что это.

## Зачем
Пара предложений: какую задачу решает и для кого.

## Как выглядит
Скриншот или пример вывода.

## Запуск
Команды подряд.

## Стек
Язык, версия, библиотеки, база.

## Структура
Что в каких папках лежит.

## Автор / лицензия

Разделы «Планы на будущее», «Благодарности», «История версий» — не запрещены, но им место в самом низу: они никому не нужны раньше, чем человек понял, что за проект перед ним.

Разбор живого README построчно​

Вот README небольшого учебного проекта целиком. Читаем его по строчкам и разбираемся, почему каждая написана именно так.

# weather-cli

Консольная утилита: показывает погоду в указанном городе через API OpenWeatherMap.

## Зачем

Чтобы посмотреть погоду, не открывая браузер: одна команда в терминале
вместо сайта с рекламой. Написана как учебный проект по работе с HTTP API.

## Как выглядит

```
$ python -m weather_cli Самара
Самара: +18 °C, облачно с прояснениями
ветер 3 м/с, влажность 61%
```

## Запуск

```bash
git clone https://github.com/example/weather-cli.git
cd weather-cli
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # вписать свой ключ OpenWeatherMap
python -m weather_cli Самара
```

Нужен Python 3.10 или новее и бесплатный ключ API с openweathermap.org.

## Стек

Python 3.10, requests, python-dotenv. Тесты — pytest.

## Структура

- `weather_cli/` — код: клиент API и форматирование вывода
- `tests/` — тесты
- `.env.example` — шаблон файла с ключом API

## Лицензия

MIT — см. файл LICENSE.

Что здесь сделано правильно:

  • Заголовок — название репозитория, не «Мой проект». Совпадение имени файла-заголовка с именем репозитория звучит мелочью, но избавляет читателя от вопроса «я туда попал?».
  • Первая строка объясняет всё. «Консольная утилита: показывает погоду… через API OpenWeatherMap» — тип программы, что делает, откуда данные. Три факта в одном предложении.
  • Раздел «Зачем» отвечает на невысказанный вопрос «а почему не просто открыть сайт». Даже для учебного проекта честный ответ лучше, чем его отсутствие.
  • Пример вывода настоящий, а не выдуманный. Скопирован из терминала со всеми пробелами и знаками. Выдуманный пример почти всегда отличается от реального — и это замечают.
  • Блок запуска копируется целиком. Клонирование, окружение, зависимости, конфиг, запуск — по порядку, ни одного шага «ну это же очевидно». Комментарий рядом с cp .env.example .env говорит, что дальше нужно вписать свой ключ.
  • Требования названы явно: Python 3.10+ и ключ API. Это ровно те две вещи, из-за которых у чужого человека «не запустилось».
  • Структура — три строки, а не дерево на экран. Задача раздела — не перечислить все файлы, а объяснить логику раскладки.

Чем плох README из одного слова. Файл с текстом «Проект» (или, чаще, # project1 и пустая строка) хуже, чем отсутствие README вовсе, по одной причине: отсутствие честно говорит «автор не дошёл», а односложный README говорит «автор дошёл, посмотрел на пустой файл и решил, что и так сойдёт». Первое — незаконченная работа, второе — отношение к работе. Судьи и работодатели читают этот сигнал одинаково.

Важно

Самая частая поломка README — команды запуска, которые не работают на чистой машине. Автор пишет их по памяти, а память хранит уже настроенное окружение: виртуальное окружение создано, переменные заданы, база поднята. Проверка одна: скопировать блок «Запуск» и выполнить его в пустой папке, как чужой человек. Всё, что придётся дописать руками, — недостающие строки README.

Отвечено вопросов: 0 из 4
Какой раздел README важнее всего поставить в самое начало?
Зачем в README скриншот или пример вывода?
Как проверить, что раздел «Запуск» действительно рабочий?
Почему README из одного слова хуже, чем отсутствие README?
Отвечено верно: 0 из 4

.gitignore: что в репозиторий не попадает​

Второй по важности файл корня — .gitignore. Это простой текстовый список правил: какие файлы git должен не замечать. Файл, подходящий под правило из .gitignore, не появляется в git status, не попадает в git add . и, значит, не уезжает в репозиторий.

Зачем это нужно, если можно просто аккуратно добавлять файлы руками: потому что руками никто не добавляет. Все набирают git add ., и без .gitignore в репозиторий уезжает всё, что лежит в папке, — включая то, чего там быть не должно.

Что попадает в .gitignore​

Четыре категории, и у каждой своя причина:

ЧтоПримерыПочему не в репозиторий
Результаты сборкиbuild/, dist/, *.class, *.o, __pycache__/получаются из исходников автоматически; хранить их — как хранить рядом с текстом его же распечатку
Файлы IDE и ОС.idea/, .vscode/, .DS_Store, Thumbs.dbэто настройки твоего редактора и мусор твоей системы, у коллеги свои
Зависимостиnode_modules/, venv/, .venv/, vendor/ставятся одной командой из файла зависимостей; весят сотни мегабайт
Секреты и локальные настройки.env, *.key, secrets.json, local.propertiesих разглашение — реальная проблема, отдельный раздел ниже

Самый наглядный пункт — зависимости. node_modules в среднем проекте — это десятки тысяч файлов и сотни мегабайт. Они однозначно восстанавливаются командой npm install из package.json, который весит пару килобайт. Закоммитить node_modules — значит сделать репозиторий неподъёмным для клонирования ради данных, которые и так есть.

Синтаксис файла минимальный:

# комментарий начинается с решётки

__pycache__/ # папка: слеш в конце
*.log # любой файл с расширением .log
.env # конкретное имя
build/ # результаты сборки
!important.log # восклицательный знак — исключение из правила выше

Готовые шаблоны вместо выдумывания​

Список игнорируемого для каждого языка давно составлен и поддерживается: репозиторий github/gitignore — официальная коллекция шаблонов GitHub. Там лежат Python.gitignore, Node.gitignore, Java.gitignore и ещё сотня файлов, каждый — выверенный список того, что в проекте на этом языке порождается автоматически.

Пользоваться можно двумя способами:

  • При создании репозитория на GitHub в форме есть выпадающий список «Add .gitignore» — выбираешь язык, файл создаётся сразу правильным.
  • В существующем проекте — открыть нужный шаблон в репозитории github/gitignore и скопировать содержимое в свой .gitignore, дописав снизу своё.

Оба варианта лучше, чем писать список по памяти: шаблон помнит про .pytest_cache/, *.egg-info/ и десяток других папок, о которых новичок узнаёт, только когда они попадают в коммит.

Мусор уже закоммичен: git rm --cached​

Частая ситуация: .gitignore добавили не сразу, и venv/ или .env уже уехали в репозиторий. Добавление правила в .gitignore задним числом ничего не исправит — правила действуют только на файлы, которые git ещё не отслеживает. Уже отслеживаемый файл продолжает отслеживаться, сколько правил ни пиши.

Убирают файл с учёта отдельной командой:

Нажми на часть выражения

Полная последовательность действий:

echo "venv/" >> .gitignore # 1. добавить правило
git rm --cached -r venv/ # 2. снять с учёта (файлы на диске остаются)
git commit -m "не отслеживать venv"

После этого git status перестанет показывать содержимое venv/, а новые коммиты его не потащат.

МУСОР УЖЕ ЗАКОММИЧЕН · GIT RM --CACHEDрабочая папка.env остаётся у тебяrm --cachedиндекс gitпустофайл больше не отслеживаетсяистория коммитов.env всё ещё тутлюбой старый коммитотдаёт его целикомутёкший ключ спасает только отзыв ключа — не удаление файла и не приватность репозиторияgit rm --cached снимает файл с учёта на будущее; прошлые коммиты остаются нетронутыми
git rm --cached убирает файл из индекса и из будущих коммитов, но история остаётся нетронутой: старые коммиты по-прежнему отдают файл целиком.

И теперь самое важное про эту команду — то, чего она не делает. git rm --cached не стирает файл из истории. Все коммиты, в которых файл уже был, остаются как есть, и любой человек, склонировавший репозиторий, достанет содержимое файла из старого коммита одной командой:

git log --oneline -- .env # найти коммиты, где файл был
git show a1f9c3d:.env # прочитать его содержимое из любого из них

Для мусора вроде venv/ это не проблема: репозиторий останется тяжёлым, но ничего страшного не случится. Для секретов — это разница между «убрал» и «кажется, что убрал», и об этом следующий раздел.

Отвечено вопросов: 0 из 4
Почему node_modules и venv не коммитят?
Ты добавил venv/ в .gitignore, но git по-прежнему показывает его файлы в git status. Почему?
Что делает флаг --cached в команде git rm --cached .env?
Где взять правильный .gitignore для своего языка, не выдумывая его?
Отвечено верно: 0 из 4

Секреты: чего нельзя коммитить никогда​

Отдельный раздел, потому что цена ошибки здесь другая. Всё остальное в этой главе — про впечатление и удобство. Утёкший ключ — про деньги, доступ к чужим данным и дисциплинарные последствия.

Что нельзя коммитить ни при каких обстоятельствах:

  • Токены и ключи API — Telegram-бота, платёжного шлюза, облака, почтового сервиса.
  • Пароли — от базы данных, от админки, от сервера.
  • Приватные SSH-ключи (id_ed25519 без .pub) и файлы сертификатов.
  • Данные пользователей — дампы базы, выгрузки, файлы с персональными данными.

Почему это происходит регулярно, хотя все всё понимают: ключ нужен в коде, чтобы код работал. Ты вписываешь его прямо в файл «пока, на минутку», потом задача уезжает дальше, а git add . не спрашивает, что за строку он отправляет.

Приём: .env плюс .env.example​

Стандартное решение — вынести все секреты из кода в один файл, а сам файл не коммитить. Файл .env — это просто список пар «имя = значение»:

# .env — НЕ коммитится, лежит только на твоей машине
WEATHER_API_KEY=8f14e45fceea167a5a36dedd4bea2543
DB_PASSWORD=super-secret-2026

Код читает эти значения из переменных окружения (в Python — библиотека python-dotenv, в Node.js — dotenv), а .env попадает в .gitignore первой же строкой.

Но тогда возникает проблема: чужой человек склонировал репозиторий и не знает, какие переменные вообще нужны. Её решает файл-близнец .env.example — та же структура, но без значений, и вот он как раз коммитится:

# .env.example — коммитится, служит шаблоном
WEATHER_API_KEY=
DB_PASSWORD=

Дальше в README пишется одна строка: cp .env.example .env и впиши свои значения. Человек сразу видит список необходимых переменных, а секретов в репозитории нет.

Совет

Проверять .env.example на пустоту нужно глазами каждый раз. Самая обидная утечка — когда файл-шаблон делают копированием рабочего .env и забывают стереть значения. Формально всё правильно: .env в .gitignore, .env.example в репозитории — только внутри него лежит настоящий ключ.

Почему «сделаю репозиторий приватным» не спасает​

Логика «ключ утёк, сейчас переключу репозиторий в private, и никто не увидит» кажется убедительной и почти всегда ошибочна. Причин несколько:

  • Публичный репозиторий успевают проиндексировать за минуты. Поисковые и специализированные боты постоянно сканируют новые коммиты на GitHub именно в поисках ключей. Речь идёт о минутах, а не о днях: ключ, полежавший в публичном репозитории полчаса, следует считать скомпрометированным.
  • Форки и клоны живут своей жизнью. Любая копия, сделанная до переключения, остаётся у того, кто её сделал, и смена видимости оригинала на неё не влияет.
  • История остаётся историей. Как разобрано выше, git rm --cached и новый коммит не стирают ключ из старых коммитов — он достаётся оттуда одной командой.

Единственное правильное действие — отозвать ключ: зайти в панель того сервиса, которому этот ключ принадлежит, удалить скомпрометированный и выпустить новый. После отзыва старая строка в истории превращается в бессмысленный набор символов, и её судьба перестаёт волновать кого-либо.

Порядок действий при утечке — по важности, а не по удобству:

  1. Отозвать и перевыпустить ключ. Прямо сейчас, до всего остального.
  2. Убрать файл из отслеживания (git rm --cached) и добавить в .gitignore, чтобы не повторилось.
  3. Проверить, что ещё лежало рядом: часто вместе с одним ключом уезжает целый конфиг.
  4. Только потом, если нужно, — думать про чистку истории. GitHub описывает этот путь в статье про удаление чувствительных данных, но переписывание истории — операция тяжёлая, и она не отменяет первый пункт.
Интересный факт

GitHub сам сканирует публичные репозитории на известные форматы ключей — это называется secret scanning. Если бот распознает в коммите, скажем, токен облачного провайдера, GitHub уведомляет и владельца репозитория, и сам сервис; крупные провайдеры на такое уведомление автоматически отзывают ключ. Механизм полезный, но полагаться на него нельзя: он знает форматы популярных сервисов, а не любой самодельный пароль в конфиге.

Отвечено вопросов: 0 из 3
Ключ API случайно попал в публичный репозиторий. Какое действие обязательно?
Зачем нужен файл .env.example, если .env не коммитится?
Почему смена видимости репозитория на приватную не спасает утёкший ключ?
Отвечено верно: 0 из 3

LICENSE: молчание — это запрет​

Файл LICENSE в корне — текст лицензии, на которой ты отдаёшь свой код. Пункт, который пропускают чаще всех остальных, и при этом единственный, у которого есть юридическое значение.

Главный факт, противоречащий интуиции: отсутствие лицензии не означает «берите свободно». По умолчанию произведение защищено авторским правом автора — то есть все права остаются за тобой, и никто другой не имеет права легально использовать, изменять или распространять твой код. Публикация на GitHub этого не отменяет: она даёт другим право смотреть код и форкать его в пределах платформы, но не более того.

Из этого следует практический вывод, который многих удивляет: репозиторий без файла LICENSE — самый закрытый вариант из возможных, а не самый открытый. Если ты выкладываешь учебный проект в портфолио и хочешь, чтобы им можно было пользоваться, лицензию нужно добавить явно.

MIT против Apache-2.0 в двух словах​

Две самые распространённые открытые лицензии для небольших проектов:

MITApache-2.0
Длинаоколо 20 строк, читается за минутунесколько страниц
Сутьделайте что угодно, сохраняйте копию лицензии и имя автора; автор ничего не гарантируетто же самое плюс явная передача патентных прав и требование помечать изменения
Когда братьучебные проекты, небольшие библиотеки, портфолиопроекты, где важна юридическая аккуратность вокруг патентов, корпоративная разработка

Для учебного проекта и портфолио разумный выбор по умолчанию — MIT: короткая, всем знакомая, ни к чему не обязывает. Apache-2.0 берут, когда рядом есть корпоративный контекст или патентные соображения.

Отдельно стоит знать про существование лицензий с «копилефтом» (GPL и родственники): они требуют, чтобы производные работы распространялись на той же лицензии. Это не хуже и не лучше — это другой замысел: MIT говорит «пользуйтесь как хотите», GPL — «пользуйтесь, но и ваш код должен остаться открытым».

Как это делается на GitHub​

Выдумывать текст лицензии не нужно и вредно — юридический текст берут дословно. Два надёжных пути:

  • Сайт choosealicense.com — официальный проект GitHub: несколько вопросов, короткое сравнение и готовый текст на выходе.
  • Прямо в репозитории. Кнопка «Add file» → «Create new file», ввести имя LICENSE — GitHub сам предложит выбрать шаблон лицензии и подставит текст, включая год и твоё имя.

Единственное, что нужно сделать руками, — проверить, что в строке Copyright (c) 2026 Имя Фамилия стоят твой год и твоё имя, а не заглушка из шаблона.

Структура каталогов: корень — это витрина​

Файлы разобраны, остаётся вопрос раскладки. Правило одно и простое: в корне лежат «документы» проекта, а код живёт в папках.

Документы корня — это как раз всё, что разобрано выше: README.md, LICENSE, .gitignore, .env.example, .editorconfig, файл зависимостей (requirements.txt, package.json, build.gradle). Их немного, они все объяснимы, и человек пробегает их взглядом за секунду.

Код и всё остальное раскладывают по папкам с говорящими именами:

weather-cli/
├── README.md
├── LICENSE
├── .gitignore
├── .env.example
├── requirements.txt
├── weather_cli/ # код проекта
│ ├── __init__.py
│ ├── api.py
│ └── format.py
├── tests/ # тесты, отдельно от кода
│ └── test_format.py
└── docs/ # длинные тексты и картинки
└── screenshot.png
РАСКЛАДКА КАТАЛОГОВ · КОРЕНЬ ЭТО ВИТРИНАв корне — только «документы»README.mdLICENSE.gitignore.editorconfigsrc/весь код проектаtests/проверки, отдельно от кодаdocs/длинные тексты и картинкиимена латиницей, без пробеловuser_service.py, не «Новый 1.py»по названию папки понятно, что внутри — без чтения файлов
Корень — витрина: только README, лицензия и конфиги. Код, тесты и документация разъезжаются по папкам с говорящими именами.

Почему плоская свалка в корне мешает — три конкретных последствия, а не эстетика:

  1. Ничего не найти взглядом. Тридцать файлов в корне — это тридцать строк, среди которых README теряется наравне с тест2.py. Читатель не ищет, он закрывает вкладку.
  2. Непонятно, что здесь главное. В структуре src/ и tests/ роль каждого файла задана его местом. В плоском списке helpers.py, test_helpers.py и helpers_old.py выглядят равноправно, и приходится открывать каждый.
  3. Растёт риск закоммитить лишнее. Когда всё свалено в одну кучу, git add . подхватывает и черновики, и мусор — их просто не видно среди прочего.

Именование файлов​

Правила, которые экономят часы чужого и своего времени:

  • Только латиница, без пробелов. user_service.py, не Сервис пользователя.py. Кириллица в именах ломается при переносе между системами, а пробелы требуют кавычек в каждой команде терминала.
  • Стиль в проекте один. snake_case в Python, camelCase или kebab-case в JS — важно не какой именно, а чтобы не вперемешку.
  • Имя описывает содержимое. api_client.py вместо utils2.py. Слово utils в имени — почти всегда признак файла, куда сваливают всё подряд.
  • Никаких final, new, old, _v2 в именах. Версии хранит git, а не имя файла. main_final_final2.py — это не версия, это признак, что автор не пользуется системой контроля версий по назначению.

.editorconfig: единый стиль без споров​

Проблема, знакомая любой команде из двух и более человек: один пишет с отступом в 4 пробела, второй — табами, третий сохраняет файлы с окончаниями строк Windows. В git diff это выглядит как переписанный файл целиком, хотя менялась одна строка.

Файл .editorconfig в корне решает это без единого спора. Его формат понимают почти все редакторы и IDE (часть — сразу, часть — с плагином), и настройки применяются автоматически, независимо от личных предпочтений каждого:

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

[*.{js,ts,json,yml}]
indent_size = 2

[*.md]
trim_trailing_whitespace = false

Что здесь написано построчно:

  • root = true — «выше не искать»: редактор перестаёт подниматься по папкам в поисках других .editorconfig.
  • [*] — правила для всех файлов; [*.{js,ts,json,yml}] — переопределение для перечисленных расширений.
  • end_of_line = lf — тот самый пункт, который снимает «весь файл изменился» между Windows и macOS/Linux.
  • insert_final_newline и trim_trailing_whitespace — убирают из диффов пустой шум: невидимые пробелы в конце строк и отсутствие перевода строки в конце файла.
  • trim_trailing_whitespace = false для Markdown стоит не случайно: два пробела в конце строки в Markdown означают перенос строки, и вычищать их нельзя.

Полминуты на файл — и половина мелких конфликтов в командной работе исчезает до того, как появится.

CONTRIBUTING.md и папка .github​

Два файла, которые в учебном репозитории кажутся избыточными, — и всё-таки полезны.

CONTRIBUTING.md — инструкция для того, кто хочет что-то в проект добавить. В большом открытом проекте это обязательный документ; в учебном он выполняет другую функцию: заставляет автора сформулировать собственные правила. Как называются ветки? Как оформляются коммиты? Что нужно запустить перед PR? Пока это в голове, оно нестабильно; записанное — становится соглашением, которое соблюдает даже команда из двух человек.

Минимальный вариант на десять строк уже работает:

# Как участвовать

1. Ветка от `main`, имя вида `feat/название` или `fix/название`.
2. Коммиты по-русски, повелительным наклонением: «добавь парсер», а не «добавил».
3. Перед PR запустить `pytest` — все тесты должны проходить.
4. PR описывает, что и зачем изменено, одним абзацем.

Папка .github/ — служебная, GitHub читает из неё шаблоны:

  • .github/ISSUE_TEMPLATE/bug_report.md — форма, которая подставляется, когда кто-то создаёт issue о баге: шаги воспроизведения, ожидаемое и фактическое поведение, окружение.
  • .github/pull_request_template.md — текст, которым автоматически заполняется описание нового pull request.

Смысл шаблонов не в бюрократии, а в том, что вопрос «а что писать?» решается заранее. Issue из одной строки «не работает» бесполезен всем, включая того, кто его создал; шаблон превращает его в отчёт, с которым можно работать. В командном проекте на чемпионате это ещё и способ не тратить время на переспрашивание.

Учебный репозиторий с CONTRIBUTING.md и шаблонами читается как проект, у которого есть процесс, а не только код. Это ровно тот сигнал, ради которого написана вся глава.

Отвечено вопросов: 0 из 4
Что означает отсутствие файла LICENSE в публичном репозитории?
Какая лицензия — разумный выбор по умолчанию для учебного проекта и портфолио?
Зачем в проекте .editorconfig?
Почему имя файла main_final_final2.py — плохой признак?
Отвечено верно: 0 из 4

Типичные ошибки и чем они кончаются​

Пять реальных сценариев с последствиями — не гипотетических, а тех, что случаются каждый учебный год.

Ключ Telegram-бота в config.py. Проект выложен в публичный репозиторий, ключ лежит открытой строкой. Через несколько часов бота используют чужие люди: рассылают спам от твоего имени, а Telegram блокирует бота за нарушение правил. Восстановление — отзыв токена и перевыпуск, но переписка и подписчики уже потеряны. Профилактика: .env в .gitignore с первого дня.

node_modules в репозитории. Репозиторий распухает до сотен мегабайт, клонирование занимает минуты, любой git status тормозит. Отдельная неприятность — в PR попадают диффы на тысячи файлов, и ревьюер физически не может найти в них твои двадцать строк. Профилактика: .gitignore из шаблона github/gitignore до первого коммита.

README написан в последний час. Команды запуска пишутся по памяти, проверить их некогда. У проверяющего проект не запускается: не хватает шага с установкой зависимостей. Работавший код получает оценку «не запустилось». Профилактика: README пишется в первый день и проверяется на чистой папке.

Один коммит «init» на весь проект. Формально всё на месте, но история пуста: нельзя посмотреть, как проект развивался, нельзя откатиться к рабочей версии, нельзя понять, кто что делал в команде. В учебном контексте это ещё и вопрос «а точно ли ты это писал». Профилактика: коммит на каждый законченный кусок работы.

Файл .env.example со значениями внутри. Шаблон сделан копированием рабочего .env, значения стереть забыли. Внешне всё правильно, .env в .gitignore — а настоящий ключ уехал в репозиторий в файле, который коммитится специально. Профилактика: после создания .env.example открыть его и убедиться, что справа от знака равенства пусто.

Важно

Общее у всех пяти ошибок — они делаются в первые полчаса проекта, а обнаруживаются в последний час. Ни одна из них не чинится быстро: отзыв ключа, чистка репозитория и переписывание README требуют времени, которого в конце нет. Поэтому корень репозитория собирают до того, как написана первая строка кода: .gitignore, README-заготовка и .env.example — это буквально пять минут в самом начале.

Практика: наведи порядок в чужом репозитории​

Перед тобой корень репозитория, который бросили на полпути: код есть, а всё остальное — как получилось. В нём лежит закоммиченный .env с настоящим ключом, нет ни .gitignore, ни .env.example, а README называется как попало. Приведи корень в порядок: секрет из репозитория убери, вместо него оставь пример без значений, добавь .gitignore и нормальный README.md.

Задание: Оставь в корне README.md, .gitignore и .env.example, а .env и readme.txt убери
  • ○ README.md
  • ○ .gitignore
  • ○ .env.example
  • ○ .env — не должно существовать
  • ○ readme.txt — не должно существовать
Учебный терминал. Введите help, чтобы увидеть список команд.
student@pgk:~$
Как это устроено под капотом
Никакого настоящего Linux здесь нет: файловая система — обычный JS-объект в памяти браузера, где папка — это вложенный объект, а файл — строка с содержимым. Команды ls, cd, mkdir, rm и остальные — функции, которые читают и меняют этот объект, а cp -r — просто глубокое копирование куска JSON. После каждой команды проверка квеста проходит по требуемым путям и смотрит, существуют ли они в этом дереве. Перезагрузишь страницу — «диск» создастся заново с нуля, так что ломать тут можно безнаказанно.
Совет

Файл с текстом создаётся не только через touch: echo "# Проект" > README.md сразу кладёт внутрь строку. Удалить лишнее — rm .env. А чтобы посмотреть, что получилось, включая скрытые файлы с точкой в начале, пригодится ls -a.

Теперь набери вслепую команды, которыми этот порядок наводят в настоящем репозитории. Здесь важен каждый символ: git rm --cached без --cached удалит файл с диска, а не только из индекса.

Цель: точность ≥ 90%

git rm --cached .env

Чек-лист: репозиторий готов к показу​

Пройди по списку перед тем, как отдавать ссылку судьям, преподавателю или работодателю.

ПунктПроверка
Имя репозиторияговорит, что внутри: weather-cli, а не project1
README.mdесть, и первая строка объясняет, что за проект
Запуск в READMEкоманды скопированы и проверены в пустой папке
Скриншот или пример выводаесть картинка либо реальный вывод в блоке кода
.gitignoreесть, взят из шаблона github/gitignore под язык проекта
Мусорvenv/, node_modules/, build/, .idea/, .DS_Store в репозитории отсутствуют
Секретыни одного ключа, пароля и токена; .env игнорируется
.env.exampleесть, и значения в нём пустые
LICENSEесть, год и имя подставлены свои
Структуракод в папке, тесты отдельно, корень не завален
Имена файловлатиница, без пробелов, без final/old/_v2
.editorconfigесть, отступы и end_of_line заданы
История коммитовбольше одного коммита, сообщения осмысленные
Взгляд со стороныоткрыть в инкогнито: за 30 секунд понятно, что это и как запустить

На чемпионате: как оформление превращается в баллы​

На чемпионате репозиторий — это не приложение к работе, а сама работа: эксперт видит её через ссылку на репозиторий, а не через твой экран. Как это влияет на результат:

  • Критерии оценки часто содержат прямые пункты про оформление. Наличие README, отсутствие лишних файлов, читаемая структура, осмысленные коммиты — это отдельные строки в ведомости, которые набираются гарантированно, независимо от того, доделан ли функционал. Терять их — самый дешёвый способ отдать баллы конкурентам.
  • Секреты в репозитории — это не «минус аккуратность», а нарушение. В заданиях, где выдаются реальные ключи доступа к тестовым сервисам, закоммиченный токен читается как несоблюдение требований безопасности, а такие пункты обычно весят больше косметических.
  • Проект, который не запустился у эксперта, считается незапустившимся. Никто не будет догадываться, что не хватает pip install -r requirements.txt. Точная инструкция в README — единственная страховка от того, что рабочий проект получит ноль за демонстрацию.
  • Первое впечатление влияет на всё последующее чтение. Эксперт смотрит десятки работ подряд. Собранный корень настраивает на «здесь человек знает, что делает», свалка — на поиск ошибок. Это не предвзятость, а обычное восприятие, и оно работает на тебя или против тебя.
  • В командных заданиях структура экономит время самой команде. Договорённость о папках и именах, записанная в CONTRIBUTING.md в первые десять минут, дешевле, чем разбор конфликтов из-за того, что двое положили одинаковый по смыслу код в разные места.

Практический вывод по таймингу: первые пять минут любого чемпионатного задания уходят не на код, а на .gitignore, заготовку README и первый коммит. Эти пять минут возвращаются на защите и никогда не находятся в конце, когда время уже кончилось.

Отвечено вопросов: 0 из 3
Когда правильнее всего собирать корень репозитория (.gitignore, README, .env.example)?
Проект работает, но у эксперта не запустился: в README не хватало шага установки зависимостей. Как это оценивается?
Почему в репозитории плохо смотрится единственный коммит «init»?
Отвечено верно: 0 из 3

Что должен уметь​

  • Объяснять, что видит и по каким признакам судит человек, впервые открывший репозиторий.
  • Писать README с обязательным минимумом: что это, зачем, как выглядит, как запустить, стек — и в правильном порядке.
  • Проверять раздел «Запуск» выполнением команд в чистой папке.
  • Составлять .gitignore на основе шаблона github/gitignore и понимать, что в него попадает и почему.
  • Снимать с учёта уже закоммиченный мусор через git rm --cached и объяснять, почему это не стирает файл из истории.
  • Хранить секреты через пару .env и .env.example и знать единственно верное действие при утечке ключа — отзыв.
  • Объяснять, что значит отсутствие LICENSE, и выбирать между MIT и Apache-2.0 для своего случая.
  • Раскладывать проект по папкам и называть файлы так, чтобы структура читалась без открытия файлов.
  • Добавлять .editorconfig, CONTRIBUTING.md и шаблоны в .github/ и объяснять, зачем они даже в учебном проекте.
  • Проходить чек-лист готовности репозитория перед сдачей работы.
Углубиться

Профильный README на GitHub. Репозиторий, названный ровно как твой ник на GitHub, — особенный: его README GitHub показывает на странице профиля. Это бесплатная витрина портфолио, которую видит любой, кто открыл твой профиль, — и заполняют её единицы.

Бейджи в README. Картинки-статусы вверху README («build passing», покрытие тестами, версия) — не украшение, а ссылка на живое состояние проекта: они генерируются сервисом и меняются сами. Полезны, когда за ними правда что-то стоит; три бейджа над проектом без единого теста дают обратный эффект.

Файл .gitattributes. Родственник .gitignore, отвечающий не за игнорирование, а за то, как git обращается с файлами: нормализация окончаний строк, пометка бинарных форматов, настройка правил слияния. Нужен реже, но в кроссплатформенной команде решает те же проблемы с окончаниями строк, что и .editorconfig, только на стороне git.

Монорепозиторий против нескольких репозиториев. Когда проект вырастает, встаёт вопрос: держать фронтенд, бэкенд и мобильное приложение в одном репозитории или в трёх. У обоих подходов есть цена — в первом случае сложнее права доступа и сборка, во втором — синхронизация версий между частями. Правильного ответа нет, есть решение конкретной команды.

История и её чистка. Если секрет всё-таки нужно вырезать из истории (а не просто отозвать), это делается специальными инструментами переписывания истории, которые меняют хеши всех последующих коммитов. Операция описана в документации GitHub, но она ломает форки и локальные копии у всех участников — и не заменяет отзыв ключа, а только дополняет его.

Дальше по теме:

Сводная проверка по всей главе: 12 вопросов, 5:00 на всё, без подсказок по ходу. Вопросы показываются по одному, ответ изменить нельзя. Если время выйдет — экзамен завершится с тем, что успел ответить. Пересдавать можно сколько угодно раз.

Куда дальше: проверенные ресурсы​

Видео по теме

ВидеоКак Оформить README-Файл На GitHub | Основы MarkdownPyLounge - программирование на Python и всё о Айти
Видео#15 Уроки Git+GitHub - Создание файла README.md синтаксис MarkdownITDoctor
ВидеоGIT. Урок 4. Использование .gitignore файла | QA START UPSerhii Hlivinskyi - QA START UP
ВидеоPython и переменные окружения | Где и как хранить секреты в коде | .env, .gitignorePythonToday
ВидеоСравнение лицензий с открытым исходным кодом GPL / MIT / ApachePracticU - онлайн IT курсы

Комментарии

Обсуждение живёт в GitHub Discussions и грузится с чужого домена — поэтому только по нажатию.