Первый репозиторий сайта
Когда сайт состоит из Markdown, шаблонов и изображений, обычной копии папки быстро становится недостаточно. Нужно понимать, какие изменения принадлежат одной задаче, откуда взялся новый текст и к какой версии можно вернуться. В ProfessorWeb перенос материалов в исходники позволил обсуждать изменение статьи отдельно от публикации сайта. Такой же подход применим к небольшому учебному каталогу.
В этом уроке создадим отдельный репозиторий и разберём три состояния файла: содержимое на диске, подготовленное содержимое следующего коммита и сохранённую историю. Команды предназначены для самостоятельной лаборатории; здесь они ещё не выполнялись. Оглавление курса содержит последовательность уроков и архив примеров.
Папка проекта и история
Нужен установленный Git версии 2.28 или новее. Создайте новую пустую папку catalog-git-lab вне папки существующего проекта. Не выбирайте каталог ProfessorWeb: дальнейшие упражнения специально меняют файлы и историю. В архиве состояние lesson-01/start содержит три исходника. Перенесите их в новую папку с сохранением подпапок и откройте терминал именно в ней.
Начальная структура выглядит так:
catalog-git-lab/
README.md
content/courses.md
public/theme.css
В README.md записано назначение проекта, в courses.md — оглавление двух курсов, в theme.css — два цветовых акцента. Для изучения Git сборщик не нужен: сначала важна история самих файлов. Каталог .git появится после инициализации; туда Git помещает служебные данные и объекты истории. Редактировать их вручную не следует.
Выполните инициализацию и задайте автора только для этой лаборатории:
git init -b main
git config user.name "Student"
git config user.email "student@example.invalid"
git status --short
Параметр -b main задаёт название начальной ветки явно. Это полезно, поскольку настройки разных компьютеров могут выбирать другое имя. Пока коммитов нет, у ветки ещё нет сохранённой вершины истории. Локальные настройки автора не изменяют общие настройки компьютера. Учебный адрес вымышленный; для своего настоящего проекта вы выбираете подходящую вам идентификацию отдельно.
В кратком статусе ожидается обозначение ?? перед ещё не отслеживаемыми путями. Точный порядок строк и оформление сообщений зависят от окружения. Git видит новые файлы, но не включает их в историю автоматически. Наличие файла рядом с .git означает только возможность его добавить, а не согласие записать его в следующий коммит.
Что помещается в индекс
Индекс — подготовленное состояние следующего коммита. Название staging area описывает тот же механизм. Представим, что на диске находятся черновики сразу двух статей: в историю можно включить только законченную первую статью. Поэтому Git разделяет рабочую папку и индекс. Для первого коммита явно добавим все три учебных исходника:
git add README.md content/courses.md public/theme.css
git status --short
git diff --cached
Перед каждым добавленным файлом ожидается A в первой колонке краткого статуса. Она показывает отличие индекса от последнего коммита. Вторая колонка показывает отличие рабочего файла от индекса. В начале истории последнего коммита ещё нет, поэтому добавленные исходники рассматриваются как новые. Команда git diff --cached показывает подготовленный текст, который будет записан.
Обратите внимание на момент выполнения add. Git подготавливает содержимое, существовавшее именно тогда. Если после этого изменить заголовок в courses.md, новая строка останется только в рабочей папке. Уже подготовленная версия самостоятельно не обновится. Для включения последующего изменения нужно снова добавить файл. Документация git-add описывает это свойство индекса.
Так возникает полезная проверка: перед коммитом читайте подготовленное отличие, а не только открытый файл в редакторе. На экране редактора может быть более поздний текст. Если вы видите неожиданную строку в подготовленной версии, пока ещё можно изменить состав коммита. Сохранение истории начинается с осознанного выбора содержимого.
Первый сохранённый снимок
Убедитесь, что в индекс попали только три исходника и что после добавления они не менялись. Теперь запишем первый коммит:
git commit -m "Добавить исходники учебного каталога"
git status --short
git log -1 --oneline
Ожидается пустой краткий статус: рабочие файлы, индекс и сохранённый снимок согласованы. Пустой вывод не говорит, что на диске ничего нет. Он говорит об отсутствии изменений, которые Git сообщает относительно сохранённого состояния. В логе будет строка с сокращённым идентификатором и указанным сообщением.
Коммит хранит ссылку на снимок дерева файлов, данные автора и сообщение. У последующих коммитов также появляются ссылки на родителей. В этом курсе первый коммит обозначим буквой A. Это условное имя на схеме, а не строка, которую следует передавать команде Git. Реальный идентификатор зависит от содержимого и служебных данных, включая время; у разных читателей он будет различаться.
main → A
Ветка указывает на последний коммит своей линии. Сейчас main указывает на A; следующий коммит передвинет эту ссылку. История не привязана к открытому файлу редактора: если случайно испортить рабочую копию, сохранённый снимок всё ещё существует. Но изменения, которые никогда не записывались, в коммите найти невозможно.
Коммит создаётся локально. Ни GitLab, ни хостинг не получают его от команды commit. Хранение на другом компьютере и публикация сайта — отдельные действия. Для лаборатории они не нужны. Это разделение позволяет спокойно изучать историю, не меняя доступную посетителям страницу.
Когда статус требует внимания
У краткого статуса две позиции перед пробелом и именем пути. Рассмотрим три отдельные строки; начальный пробел в первой строке существенен:
M content/courses.md
M content/courses.md
MM content/courses.md
В первом варианте буква M стоит во второй колонке: файл изменён только на диске. Во втором она в первой колонке: новая версия подготовлена в индексе. Обозначение MM означает наличие обоих отличий. Они могут относиться к разным строкам одного файла, поэтому одно название пути не описывает весь состав работы.
Не пытайтесь устранять любой непустой статус повторным add всех файлов. Сначала прочитайте различия и определите, соответствует ли подготовленное содержимое вашей задаче. Для первого опыта оставьте файлы в исходном виде. Если вы внесли пробную правку, верните точный текст вручную, затем снова посмотрите статус. Эта операция понятна без изучения дополнительных команд восстановления.
Обнаружив ошибку в имени автора, исправьте локальную настройку для будущей работы. Уже созданный коммит содержит прежние метаданные; смена настройки не редактирует существующую историю. В учебном проекте это не мешает пониманию механизма, а способы изменения истории обсудим после веток и общего предка.
Теперь у каталога есть исходники и первая точка истории. Перед следующим уроком ожидается чистое рабочее дерево и единственный коммит A. Далее рассмотрим осмысленный коммит: изменим текст, выделим законченную задачу и проверим именно ту версию, которую сохраняем.