Урок курса
Почему ignore не помог уже сохранённому файлу
Git и GitHub с нуля: бесплатный курс с практикойВ прошлом уроке выяснилось, что шаблон в .gitignore не трогает уже отслеживаемые файлы. Если notes.local.txt уже есть в индексе, добавление его имени в .gitignore ничего не меняет — Git продолжает за ним следить. Команда git rm --cached удаляет запись из индекса, сохраняя рабочий файл на диске.
Почему .gitignore не останавливает отслеживание уже закоммиченного файла
Git разделяет файлы на два принципиально разных класса: отслеживаемые (tracked) — те, чья запись есть в текущем индексе, — и неотслеживаемые (untracked) — те, которых в индексе нет.
.gitignore влияет только на второй класс. Когда Git встречает в рабочей папке файл, которого нет в индексе, он проверяет правила игнорирования и, если путь совпадает с шаблоном, перестаёт его показывать в выводе git status как untracked. Файл просто не виден.
Но если файл уже попал в индекс — через git add и коммит — у Git есть его снимок. Правило в .gitignore на этот случай не распространяется: индексная запись не исчезает от того, что имя файла добавлено в .gitignore. Git продолжает сравнивать рабочий файл с тем, что записано в индексе, и сообщает об изменениях как обычно.
Поэтому в нашем учебном репозитории картина такая: notes.local.txt закоммичен, запись о нём есть в индексе. Добавляем в .gitignore строку notes.local.txt — и ничего не меняется. Если открыть notes.local.txt, отредактировать его и выполнить git status, Git честно сообщит modified: notes.local.txt. Правило игнорирования здесь не при чём: файл отслеживаемый, и это определяется индексом, а не историей и не .gitignore.
git rm --cached: удаление записи из индекса без удаления файла с диска
git rm --cached <путь> удаляет запись о файле из индекса Git. Рабочий файл при этом остаётся нетронутым — он никуда не исчезает.
После выполнения команды:
- Запись пути исчезает из индекса — Git больше не считает этот файл отслеживаемым.
- Файл на диске остаётся с тем содержимым, которое было до команды.
git statusпоказывает изменение как подготовленное к коммиту:deleted: notes.local.txtв разделе «Changes to be committed».
Пример выполнения:
git rm --cached notes.local.txt
Вывод:
rm 'notes.local.txt'
Git сообщает, что убрал путь из индекса — именно убрал запись, не файл. После этого git status покажет staged deletion. Если путь покрыт сохранённым правилом в .gitignore, оставшийся рабочий файл уже не показывается как untracked; для действия правила коммит не нужен. Подготовленное удаление из снимка остаётся в статусе до коммита. После него при отсутствии других правок статус будет чистым.
Что произойдёт без флага --cached
git rm notes.local.txt (без --cached) удаляет файл и из индекса, и из рабочей папки. Файл исчезнет с диска. Это деструктивная операция, и отменить её без дополнительных команд не получится. Флаг --cached обязателен именно тогда, когда нужно сохранить файл на диске и только убрать его из отслеживания.
Полная последовательность: добавить правило и убрать файл из отслеживания одним коммитом
Распакуйте выданный git_practice.zip в новую пустую папку. Откройте терминал в этой папке, куда извлечён архив, и перейдите в готовый учебный репозиторий:
cd "git_practice/prepared/tracked_local_file"
git config user.name "Учебный автор"
git config user.email "learner@example.invalid"
git status
git log --oneline
В tracked_local_file уже существует .git: повторный git init не нужен. Обе команды config задают локальную личность автора именно для нового коммита в этом репозитории; настройки другой рабочей папки сюда не переносятся. До правок убедитесь, что status чистый и log показывает два исходных коммита.
Исходное состояние в учебном репозитории git_practice/prepared/tracked_local_file: два коммита в ветке main — «Первый справочник» (README.md) и «Добавить локальные заметки» (notes.local.txt). Файл .gitignore отсутствует. git status показывает чистое состояние: notes.local.txt отслеживается, но не изменён, поэтому в выводе он не появляется.
Шаги для исправления ситуации:
1. Отредактировать notes.local.txt
Открыть файл в редакторе, добавить строку «Учебная правка» и сохранить. Теперь git status покажет:
Changes not staged for commit:
modified: notes.local.txt
Это подтверждает: файл отслеживается, и .gitignore ещё не существует.
2. Создать .gitignore
Открыть редактор, создать новый файл .gitignore в той же папке, ввести одну строку:
notes.local.txt
Сохранить. git status по-прежнему показывает modified: notes.local.txt и добавляет Untracked files: .gitignore. Правило уже прочитано Git при обработке рабочей папки, но на отслеживаемый файл оно не влияет.
3. Подготовить оба изменения к коммиту
git add .gitignore
git rm --cached notes.local.txt
Порядок этих двух команд не важен — главное, что оба изменения должны быть staged до коммита. После выполнения git status покажет:
Changes to be committed: new file: .gitignore deleted: notes.local.txt
4. Создать коммит
git commit -m "Убрать notes.local.txt из отслеживания"
5. Проверить результат
git status
Вывод: nothing to commit, working tree clean. Открыть notes.local.txt в редакторе — файл на месте, строка «Учебная правка» сохранена. Git больше не следит за этим файлом, а .gitignore скрывает его от git status как неотслеживаемый путь, совпадающий с правилом.
Для одного коммита с правилом и прекращением отслеживания нужны оба изменения: git add .gitignore и git rm --cached notes.local.txt. Только добавление .gitignore в индекс не уберёт запись notes.local.txt. После git rm --cached оставшийся рабочий файл будет показан как untracked, если для него нет действующего правила игнорирования. Но сохранённый рабочий .gitignore применяется сразу, даже когда сам он ещё untracked, не добавлен в индекс и не закоммичен. Поэтому совпадающий с его правилом notes.local.txt уже скрыт как untracked; до коммита в статусе остаётся подготовленное удаление прежнего снимка.
Добавление .gitignore в индекс и общий коммит сохраняют правило вместе с прекращением отслеживания в истории проекта, чтобы правило можно было передать вместе с этой версией. Они не включают локальное игнорирование.
Три независимых слоя: текущий индекс, рабочий файл и исторический снимок
После коммита «Убрать notes.local.txt из отслеживания» результат выглядит так — и важно не смешивать три разных наблюдения.
Текущий индекс — записи о notes.local.txt больше нет. Git не отслеживает этот путь. Именно поэтому git status показывает чистое состояние: нечего сравнивать.
Рабочий файл — notes.local.txt существует на диске с той строкой, которую мы добавили в редакторе. git rm --cached не тронул его содержимое. Дальнейшие правки этого файла останутся невидимыми для git status, потому что путь покрыт правилом в .gitignore и не отслеживается.
Исторический снимок — в коммите «Добавить локальные заметки» notes.local.txt сохранён с тем содержимым, которое было на момент того коммита. Никакая последующая операция с индексом не меняет уже созданные коммиты. Содержимое из старого снимка можно прочитать командой:
git log --oneline
Выбрать ID коммита «Добавить локальные заметки» из вывода, затем:
git show <этот-ID>:notes.local.txt
Git вернёт содержимое файла именно из того снимка — без строки «Учебная правка», потому что она была добавлена уже после того коммита. Синтаксис <ID>:<путь> означает: «содержимое пути в указанном коммите».
Эти три слоя независимы. «Файл не отслеживается сейчас» не означает «файл никогда не существовал в истории». История не переписывается: старый снимок остаётся доступным через git show столько, сколько существует репозиторий.
Задача 1
notes.local.txt находится в текущем индексе и последнем коммите. В файле добавили новую строку, но add не выполняли. Затем сохранили правило notes.local.txt в .gitignore. Как это повлияет на отслеживание именно notes.local.txt?
Задача 2
Отслеживаемый notes.local.txt нужно исключить из будущего снимка, сохранив файл на диске. Правило игнорирования уже записано. Коммит ещё не выполнен. Какая команда делает нужное изменение индекса?
Задача 3
Практика: распакуйте полный git_practice.zip в отдельную новую папку. Откройте git_practice/prepared/tracked_local_file; это уже готовый репозиторий. Через редактор измените notes.local.txt, проверьте status, создайте .gitignore с именем этого файла и снова проверьте status. Подготовьте правила, уберите notes.local.txt из индекса с сохранением файла на диске и создайте коммит. Проверьте наличие рабочего файла, status и старый коммит через show с ID из своей истории. Запишите состояние индекса и файла на диске до и после операции, ID нового коммита и свидетельство из старого коммита. Письменно объясните коллеге, почему одного правила игнорирования недостаточно и почему старые снимки сохранились.
Платформа проверяет только ответ ниже; действия в своём репозитории и письменные ответы вы проверяете самостоятельно.
В отдельном контрольном случае файл уже убрали из индекса через rm --cached, но правило игнорирования для него не добавляли. Затем записали удаление коммитом. Файл на диске не меняли и не удаляли. Как он будет показан в обычном status?
Продолжить с сохранением прогресса
Перейдите к уроку в учебном кабинете.
