Урок курса
Почему add не сохраняет все будущие правки
Git и GitHub с нуля: бесплатный курс с практикойВ прошлом уроке появились три области Git: рабочая папка, индекс и репозиторий. git add переводил файл в индекс, git commit — сохранял снимок. Индекс хранит версию файла на момент git add: более поздняя правка остаётся в рабочей папке и не попадает в следующий коммит автоматически.
Индекс как снимок момента git add
git add не ставит за файлом «слежку» в смысле постоянного отслеживания. Он делает ровно одно: в момент вызова читает содержимое файла и копирует его в индекс. С этого момента индекс хранит самостоятельную копию — не ссылку на файл в рабочей папке, а именно снимок его содержимого.
Если после git add README.md открыть файл и дописать ещё одну строку, в рабочей папке станет одно содержимое, а в индексе — другое. Индекс не знает о новых изменениях. Он остаётся замороженным на том состоянии, которое было в момент вызова команды.
Именно поэтому между git add и git commit лучше проверять git status: он покажет, совпадает ли рабочая папка с тем, что лежит в индексе, или нет.
Три версии одного файла: коммит, индекс, рабочая папка
Рассмотрим конкретный сценарий. Репозиторий уже содержит один коммит с README.md.
Откройте README.md обычным текстовым редактором. Не удаляя прежний текст, добавьте в конце отдельную строку Правка 1 и сохраните файл. В терминале выполните:
git add README.md
Снова откройте README.md и добавьте после первой правки строку Правка 2. Сохраните файл, но повторный git add не выполняйте. В рабочем файле теперь есть обе строки, а в индексе — только первая. Проверьте состояние:
git status
Вывод git status будет выглядеть примерно так:
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: README.md
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
modified: README.md
README.md фигурирует в обоих разделах одновременно. Это не ошибка — это точное отражение ситуации: файл существует в трёх различных версиях прямо сейчас.
— Последний коммит хранит README.md без обеих правок — то, что было сохранено ранее.
— Индекс хранит версию с «Правкой 1» — снимок, сделанный при git add.
— Рабочая папка содержит файл с обеими правками — то, что видно при открытии файла.
Строка в разделе «Changes to be committed» говорит: индекс отличается от последнего коммита. Строка в разделе «Changes not staged for commit» говорит: рабочая папка отличается от индекса. Git различает эти два расхождения и сообщает о каждом отдельно.
Коммит фиксирует индекс: незакоммиченная правка остаётся в рабочей папке
Когда выполняется git commit, Git берёт содержимое индекса — и только его — и создаёт из него снимок. Рабочая папка в этот момент не читается. Всё, что там есть сверх индекса, просто остаётся нетронутым.
Продолжим предыдущий сценарий:
git commit -m "Добавлена правка 1"
git status
После коммита git status покажет:
On branch main
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
modified: README.md
«Правка 1» теперь в истории. «Правка 2» по-прежнему только в рабочей папке — не в индексе, не в репозитории. git log --oneline при этом покажет два коммита, а не три и не один.
Здесь возникает типичное заблуждение: «я уже сделал git add README.md, значит, все мои дальнейшие правки этого файла тоже войдут в коммит». Это неверно. git add не подписывает контракт на будущее. Он копирует файл в индекс ровно один раз — в момент вызова. Правка, сделанная после, для Git выглядит так, как будто git add ещё не выполнялся: она в рабочей папке и нигде больше.
Чтобы «Правка 2» попала в следующий коммит, нужно снова выполнить git add README.md — тогда индекс обновится до текущего состояния файла.
Задача 1
В исходном коммите README содержит только заголовок. В рабочий файл дописали строку «Контакт», выполнили git add README.md, затем дописали «Установка» без повторного add и выполнили обычный git commit -m "Add contact".
Обозначения содержимого:
А — только заголовок;
Б — заголовок и «Контакт»;
В — заголовок, «Контакт» и «Установка».
Как распределены версии сразу после успешного коммита, до любых следующих действий?
Задача 2
Практика на своём компьютере: начните с учебного репозитория после урока3, в котором один коммит с README. Добавьте первую строку и сохраните файл, подготовьте README в индексе, затем добавьте вторую строку и сохраните. До фиксации письменно предскажите содержимое будущего коммита. Запишите коммит без повторной подготовки, проверьте status и компактную историю. Запишите, совпал ли результат с прогнозом. Если пример этого урока уже выполнен, подготовьте отдельную новую папку по урокам2–3, сохранив прежний репозиторий.
Для самопроверки: ожидаются два коммита, а README остаётся в Changes not staged for commit. Платформа проверяет только ответ ниже; ваш репозиторий и письменный прогноз вы проверяете самостоятельно.
В контрольном опыте ученик вместо этого получил два коммита и чистый статус; рабочий README всё ещё содержит обе строки. Из списка ниже он совершил ровно одно дополнительное действие между второй правкой и коммитом. Какое действие объясняет результат?
Продолжить с сохранением прогресса
Перейдите к уроку в учебном кабинете.
