Анатомия взрослого репозитория
Зачем это нужно
Код, который работает, и репозиторий, который не стыдно показать, — это две разные вещи, и вторая почти никогда не получается сама собой. Проект живёт в голове автора: он помнит, что запускать надо python main.py из папки src, что перед этим нужен pip install -r requirements.txt, что папка old — это мусор, а test2.py — на самом деле рабочий файл. Ничего из этого не знает человек, который открыл твой репозиторий: ни судья на чемпионате, ни преподаватель, ни работодатель, ни ты сам через полгода.
Эта глава — про то, что лежит в корне репозитория и почему каждый из этих файлов там оказался. Ни одного нового инструмента: ни новых команд git, кроме одной, ни новых языков. Только набор решений, которые превращают папку с кодом в проект. Слова коммит, ветка, push, PR дальше используются без объяснений — они разобраны в главах про git.
- Зачем это нужно
- «Работает» — это только половина
- README: единственный текст, который прочитают
- .gitignore: что в репозиторий не попадает
- Секреты: чего нельзя коммитить никогда
- LICENSE: молчание — это запрет
- Структура каталогов: корень — это витрина
- .editorconfig: единый стиль без споров
- CONTRIBUTING.md и папка .github
- Типичные ошибки и чем они кончаются
- Практика: наведи порядок в чужом репозитории
- Чек-лист: репозиторий готов к показу
- На чемпионате: как оформление превращается в баллы
- Что должен уметь
- Куда дальше: проверенные ресурсы
«Работает» — это только половина
Есть простой мысленный эксперимент, который сразу расставляет всё по местам. Представь: незнакомый человек открыл твой репозиторий на GitHub. Он не знает ни тебя, ни задачу. У него на решение «разбираться или закрыть вкладку» уходит примерно тридцать секунд — ровно столько, сколько нужно, чтобы окинуть взглядом список файлов и пролистать то, что GitHub показывает под ним.
Что он видит в эти тридцать секунд:
- Название репозитория.
project1,test-repo,новая папка— уже минус к доверию.weather-cli,pgk-schedule-bot— уже понятно, о чём речь. - Список файлов в корне. Аккуратные
src/,tests/,README.md— или тридцать файлов вперемешку с.DS_Store,venv/ифото.jpg. - README, который GitHub рисует прямо под списком файлов. Это единственный текст, который человек прочитает гарантированно.
- Даты и количество коммитов. Один коммит «init» на весь проект — сигнал, что код принесли откуда-то целиком.
Ключевая мысль главы: оформление репозитория ничего не говорит о качестве кода — и именно поэтому оно так сильно работает. Читатель ещё не открыл ни одного файла с кодом, оценить его он физически не успел. Всё, чем он в этот момент располагает, — косвенные признаки: аккуратно ли разложено, объяснено ли, что это. И по этим признакам он решает, стоит ли тратить время на остальное.
Обратная сторона тоже правда: красивый README не спасёт неработающий проект. Речь не о том, чтобы обмануть впечатление, а о том, чтобы не терять баллы и внимание на пустом месте — там, где работа уже сделана, но её не видно.
Хорошая новость: весь набор файлов из этой главы делается один раз за проект и занимает минут двадцать. Плохая — двадцать минут, которых почти никогда нет в конце, потому что в конце дедлайн. Поэтому правильный момент собрать корень репозитория — первый день проекта, а не последний.
Проверка, которая занимает минуту и ловит почти всё: открой свой репозиторий в браузере в режиме инкогнито (или просто выйди из аккаунта). Ты увидишь его глазами чужого человека, без подсветки «это моё» и без памяти о том, что где лежит. Если за тридцать секунд ты сам не можешь ответить «что за проект и как его запустить» — README ещё не готов.
README: единственный текст, который прочитают
README (по-английски буквально «прочти меня») — файл README.md в корне репозитория. GitHub автоматически показывает его содержимое под списком файлов, отрендеренным из Markdown. Никакой магии, никакой настройки: положил файл с таким именем в корень — он появился на главной странице.
Обязательный минимум
Пять пунктов, без которых 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.
.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 не стирает файл из истории. Все коммиты, в которых файл уже был, остаются как есть, и любой человек, склонировавший репозиторий, достанет содержимое файла из старого коммита одной командой:
git log --oneline -- .env # найти коммиты, где файл был
git show a1f9c3d:.env # прочитать его содержимое из любого из них
Для мусора вроде venv/ это не проблема: репозиторий останется тяжёлым, но ничего страшного не случится. Для секретов — это разница между «убрал» и «кажется, что убрал», и об этом следующий раздел.
Секреты: чего нельзя коммитить никогда
Отдельный раздел, потому что цена ошибки здесь другая. Всё остальное в этой главе — про впечатление и удобство. Утёкший ключ — про деньги, доступ к чужим данным и дисциплинарные последствия.
Что нельзя коммитить ни при каких обстоятельствах:
- Токены и ключи 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и новый коммит не стирают ключ из старых коммитов — он достаётся оттуда одной командой.
Единственное правильное действие — отозвать ключ: зайти в панель того сервиса, которому этот ключ принадлежит, удалить скомпрометированный и выпустить новый. После отзыва старая строка в истории превращается в бессмысленный набор символов, и её судьба перестаёт волновать кого-либо.
Порядок действий при утечке — по важности, а не по удобству:
- Отозвать и перевыпустить ключ. Прямо сейчас, до всего остального.
- Убрать файл из отслеживания (
git rm --cached) и добавить в.gitignore, чтобы не повторилось. - Проверить, что ещё лежало рядом: часто вместе с одним ключом уезжает целый конфиг.
- Только потом, если нужно, — думать про чистку истории. GitHub описывает этот путь в статье про удаление чувствительных данных, но переписывание истории — операция тяжёлая, и она не отменяет первый пункт.
GitHub сам сканирует публичные репозитории на известные форматы ключей — это называется secret scanning. Если бот распознает в коммите, скажем, токен облачного провайдера, GitHub уведомляет и владельца репозитория, и сам сервис; крупные провайдеры на такое уведомление автоматически отзывают ключ. Механизм полезный, но полагаться на него нельзя: он знает форматы популярных сервисов, а не любой самодельный пароль в конфиге.
LICENSE: молчание — это запрет
Файл LICENSE в корне — текст лицензии, на которой ты отдаёшь свой код. Пункт, который пропускают чаще всех остальных, и при этом единственный, у которого есть юридическое значение.
Главный факт, противоречащий интуиции: отсутствие лицензии не означает «берите свободно». По умолчанию произведение защищено авторским правом автора — то есть все права остаются за тобой, и никто другой не имеет права легально использовать, изменять или распространять твой код. Публикация на GitHub этого не отменяет: она даёт другим право смотреть код и форкать его в пределах платформы, но не более того.
Из этого следует практический вывод, который многих удивляет: репозиторий без файла LICENSE — самый закрытый вариант из возможных, а не самый открытый. Если ты выкладываешь учебный проект в портфолио и хочешь, чтобы им можно было пользоваться, лицензию нужно добавить явно.
MIT против Apache-2.0 в двух словах
Две самые распространённые открытые лицензии для небольших проектов:
| MIT | Apache-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 теряется наравне с
тест2.py. Читатель не ищет, он закрывает вкладку. - Непонятно, что здесь главное. В структуре
src/иtests/роль каждого файла задана его местом. В плоском спискеhelpers.py,test_helpers.pyиhelpers_old.pyвыглядят равноправно, и приходится открывать каждый. - Растёт риск закоммитить лишнее. Когда всё свалено в одну кучу,
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 и шаблонами читается как проект, у которого есть процесс, а не только код. Это ровно тот сигнал, ради которого написана вся глава.
Типичные ошибки и чем они кончаются
Пять реальных сценариев с последствиями — не гипотетических, а тех, что случаются каждый учебный год.
Ключ 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 — не должно существовать
Как это устроено под капотом
Файл с текстом создаётся не только через 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 и первый коммит. Эти пять минут возвращаются на защите и никогда не находятся в конце, когда время уже кончилось.
Что должен уметь
- Объяснять, что видит и по каким признакам судит человек, впервые открывший репозиторий.
- Писать 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, но она ломает форки и локальные копии у всех участников — и не заменяет отзыв ключа, а только дополняет его.
Дальше по теме:
- GitHub Docs: About READMEs — где GitHub ищет README и как его показывает
- GitHub Docs: удаление чувствительных данных из репозитория — почему сначала отзыв ключа и только потом чистка истории
Сводная проверка по всей главе: 12 вопросов, 5:00 на всё, без подсказок по ходу. Вопросы показываются по одному, ответ изменить нельзя. Если время выйдет — экзамен завершится с тем, что успел ответить. Пересдавать можно сколько угодно раз.
Куда дальше: проверенные ресурсы
-
GitHub Docs: About READMEs — где GitHub ищет README, как его рендерит и что показывает на профиле.
-
gitignore — официальная документация git — точные правила синтаксиса: шаблоны, слеши, отрицания через
!. -
github/gitignore — официальная коллекция шаблонов
.gitignoreпод каждый язык и инструмент. -
git-rm — официальная документация — первоисточник про
--cached: что снимается с учёта, а что остаётся на диске. -
choosealicense.com — проект GitHub: выбор лицензии по нескольким вопросам и готовые тексты MIT, Apache-2.0 и остальных.
-
EditorConfig — формат файла, полный список свойств и таблица поддержки редакторами.
-
GitHub Docs: правила для участников проекта — что писать в CONTRIBUTING.md и где GitHub его показывает.
-
GitHub Docs: шаблоны issue — как устроена папка
.github/ISSUE_TEMPLATEи шаблон pull request. -
GitHub Docs: secret scanning — как GitHub сам находит ключи в коммитах и что происходит дальше.
-
Видео и материалы сообщества — ниже — ролики по теме и ссылки от студентов и преподавателей смотри в самом низу страницы.
Комментарии
Обсуждение живёт в GitHub Discussions и грузится с чужого домена — поэтому только по нажатию.