Правила исключения файлов
У учебного каталога уже есть два коммита с исходниками. Но по мере разработки рядом появляются результаты сборки, настройки редактора и переменные окружения. Если записывать всю папку без разбора, история быстро перестаёт объяснять изменения сайта. Иногда в неё попадает содержимое, которое вообще не должно передаваться другим разработчикам.
В этом уроке определим границу исходников с помощью .gitignore. Разберём её на нашем Markdown-каталоге и отдельно рассмотрим важный случай: файл уже находится в истории. Оглавление курса и архив содержат исходное состояние lesson-03/start. Команды пока не запускались; результаты ниже описывают ожидаемое поведение.
Исходник и воспроизводимый результат
Для лаборатории исходниками считаются README.md, content/courses.md и public/theme.css. Именно их человек меняет, обсуждает и передаёт следующему разработчику. Предположим, отдельная сборка позже создаёт dist/index.html. Такой файл представляет результат преобразования исходников. В нашей лаборатории сборщик не запускается: пример результата можно создать вручную как обычный текст.
На настоящем проекте решение хранить результат сборки зависит от процесса публикации. Для нашего каталога договоримся, что dist в исходную историю не входит. Этот выбор не означает запрета хранить любые HTML-файлы. Если HTML является авторским исходником, он имеет другую роль. Правило должно описывать происхождение файла, а не только его расширение.
Локальная настройка .env.local также не относится к общей истории. Для опыта создайте в ней только вымышленное значение CATALOG_MODE=local-demo. Никаких настоящих паролей или токенов здесь не нужно. Посмотрев краткий статус до настройки исключений, вы увидите новые неотслеживаемые пути. У уже сохранённых исходников статус останется пустым, если вы их не меняли.
Правила в корне проекта
Создайте файл .gitignore в корне лаборатории с таким полным содержимым:
/dist/
/.env.local
/.env
/.venv/
/node_modules/
*.log
.DS_Store
Начальный слеш привязывает соответствующее правило к папке, в которой лежит этот .gitignore. Поэтому /dist/ относится к корневому результату сборки. Завершающий слеш означает каталог. Если позже внутри исходников появится content/dist/, корневое правило /dist/ само по себе не делает его исключённым.
Шаблон *.log не содержит слеша и может совпадать с именем файла в разных подпапках. Здесь это осознанный выбор: временные логи не нужны в истории. Если журнал является частью учебного материала, потребуется более точное правило. Исключение широкого типа удобно, пока оно не скрывает авторские исходники.
Каталоги зависимостей и виртуального окружения перечислены на будущее. Их наличие в правилах не требует устанавливать Node.js или Python для выполнения урока. Сам .gitignore не игнорируется: его записывают вместе с исходниками, чтобы остальные разработчики получили одинаковые правила проекта.
Теперь прочитайте статус и причину исключения отдельных путей:
git status --short
git check-ignore -v dist/index.html .env.local
git add .gitignore
git diff --cached
git commit -m "Исключить результаты сборки и локальные настройки"
При заданных условиях статус показывает новый .gitignore, а созданные вручную dist/index.html и .env.local исчезают из обычного списка неотслеживаемых файлов. Команда check-ignore -v показывает правило, которое объясняет исключение. Чтение этой причины полезнее догадки: в проекте могут действовать также другие источники правил.
Что исключения сохраняют на диске
После добавления правила локальная переменная остаётся в файле, а вручную созданный HTML остаётся в dist. Git не удаляет эти данные. Он лишь не предлагает обычным способом включать намеренно неотслеживаемые пути в историю. Вы можете открыть файл в редакторе, скопировать его или потерять при удалении папки независимо от .gitignore.
Отсюда следует различие между исключением и резервной копией. Если важная рабочая заметка игнорируется, коммиты её не сохраняют. Это может быть подходящим решением для личной временной записи, но не для единственного экземпляра значимого документа. Разделяйте данные по назначению до записи правил, чтобы удобство не оборачивалось потерей нужного материала.
Для общего описания переменных обычно создают отдельный файл, например .env.example, с вымышленными значениями. В нашем списке он не совпадает с /.env и /.env.local, поэтому может храниться в истории. Читатель получает названия настроек, но не действительные значения конкретного окружения. Такой образец не является автоматически работающей конфигурацией сервера.
Исключение можно отменить последующим правилом с !, но это требует понимать порядок и границы папок. Например, повторное включение файла внутри полностью игнорируемого каталога нельзя считать очевидным исключением одной строкой: Git должен иметь возможность обходить нужные родительские папки. Для нашего урока проще оставить dist целиком результатом и не создавать вложенных исключений.
Если файл уже записан
Самая существенная граница .gitignore: правила относятся к неотслеживаемым файлам. Добавление /.env.local не прекращает отслеживание файла, который вы уже включили в предыдущий коммит. Это прямо указано в документации gitignore. Если такой файл продолжает показываться как изменённый, правило не обязательно написано неправильно.
Для безопасного лабораторного разбора представим, что ранее был записан только вымышленный образец. Удаление файла из индекса с сохранением рабочего экземпляра выглядит так:
git rm --cached .env.local
git diff --cached
Не выполняйте этот фрагмент в основном сценарии: там .env.local никогда не добавлялся, поэтому удалять его из индекса нечего. В отдельном опыте подготовленный diff покажет удаление из следующего снимка. На диске файл останется, поскольку используется --cached. После записи такого удаления будущее состояние перестанет содержать путь, но старые коммиты всё ещё смогут хранить прежнее содержимое.
Если в историю попал настоящий секрет, исключение и последующее удаление не отменяют факт раскрытия. Значение требуется заменить в системе, где оно действительно предоставляет доступ. Переписывание общей истории — самостоятельная задача с другими последствиями; этот урок её не выполняет. Лаборатория поэтому использует только вымышленные строки.
Правило проекта стоит обсуждать по тому же принципу, что и изменение статьи. Если новый разработчик не получит какой-то файл из истории, сможет ли он понять, откуда этот файл берётся? Для dist ответом будет будущая описанная сборка, для .env.local — образец переменных и самостоятельная настройка окружения. Если происхождение неизвестно, слишком широкое исключение может скрыть необходимую часть проекта. Сам .gitignore должен помогать передаче работы, а не просто делать статус визуально пустым.
Ожидаемый результат основного сценария — третий коммит с .gitignore, чистый статус отслеживаемых исходников и два локальных исключённых примера. Далее создадим ветку разработки, чтобы новое описание каталога можно было подготовить независимо от основной линии.