Перейти к содержанию

Восстановление рабочего файла

В предыдущем уроке мы возвращали ошибочное изменение новым коммитом. Теперь рассмотрим другую ситуацию: при редактировании каталога вы случайно удалили часть текста, но ещё не записали работу в историю. Здесь сначала требуется выбрать нужное содержимое файла, а затем решить, нужно ли вообще создавать новый коммит.

Продолжим учебный каталог с сохранёнными адресами JavaScript и HTML/CSS. Сценарий lesson-09 в архиве продолжения задаёт отдельную лабораторию. Это подготовленные действия; команды не выполнялись. Репозиторий ProfessorWeb не служит местом для упражнения.

Три места, в которых лежит версия

Для content/courses.md полезно назвать три состояния. Рабочий файл видит редактор. Индекс содержит выбранную для следующей записи версию. Коммит HEAD содержит последнюю записанную версию текущей линии. Они могут совпадать, но название файла само по себе ещё не говорит, какое из этих состояний вы хотите получить.

В лабораторном начале все три содержат два курса и правильный адрес /courses/javascript/. Теперь удалите из рабочего Markdown строку ссылки HTML/CSS, сохранив остальные строки. Не добавляйте изменение в индекс. Прочитайте различие и убедитесь, что потерян именно один пункт:

git status --short
git diff -- content/courses.md
git diff --cached -- content/courses.md

Ожидается изменение только рабочего файла; последнее сравнение пустое. Поэтому возвращать файл можно из индекса, который ещё хранит нужный список. В нашей модели вы осознанно отказываетесь от этой конкретной незаписанной правки. Если рядом были полезные новые абзацы, сначала сохраните их отдельно или перенесите вручную: операция заменяет содержимое выбранного файла целиком.

git restore -- content/courses.md

После этого ожидается возвращение обеих ссылок и отсутствие различий. Это не новый коммит и не отмена старой истории. Вы просто заменили незаписанное содержимое известной версией. В документации restore отдельно определены источник и место восстановления: без дополнительных параметров источником служит индекс, а назначением — рабочее дерево.

Индекс как самостоятельный источник

Изменим условие. Добавьте в конец файла абзац «Выберите удобный темп обучения.» и выполните git add content/courses.md. Затем в рабочем файле снова удалите ссылку HTML/CSS. Теперь полезный абзац уже выбран для записи, а случайное удаление появилось позднее. Команда восстановления из предыдущего раздела должна вернуть файл к индексу, сохранив новый абзац.

Удобно выразить состояние словами: история содержит исходный каталог, индекс — каталог с рекомендацией, рабочий файл — рекомендацию и неполный список. После восстановления рабочий файл должен совпасть с индексом. Изменение абзаца относительно истории остаётся. Именно поэтому выражение «вернуть всё назад» недостаточно точное: оно скрывает выбор исходной точки.

git restore -- content/courses.md
git diff -- content/courses.md
git diff --cached -- content/courses.md

Ожидается пустое первое сравнение и добавленный абзац во втором. Прочитайте оба вывода до записи. В упражнении рекомендацию сохраняем отдельным коммитом; эта запись становится новой текущей точкой. Другие файлы остаются прежними, и URL обоих курсов не меняются.

Если же вы хотите только убрать выбор из индекса, используется git restore --staged -- content/courses.md. Рабочий текст при этом сохраняется. Например, вы передумали включать рекомендацию в ближайший коммит, но продолжаете над ней работать. Это отличается от удаления самой рекомендации. После команды она остаётся видимой в редакторе и появляется как незаписанное различие рабочего файла.

Выбор старой записанной версии

Иногда источник находится глубже в истории. Допустим, новый абзац уже записан, но для сравнения редакционных вариантов нужен предыдущий каталог. Сначала прочитайте старый файл, ничего не заменяя:

git show HEAD~1:content/courses.md

В данном сценарии предыдущая запись — исходный снимок, поэтому в нём нет рекомендации. Синтаксис с двоеточием обозначает файл внутри выбранного снимка. Руководство show описывает чтение объектов; такой просмотр помогает проверить выбор до изменения рабочих данных.

Вернуть прежний текст в рабочую папку можно явным источником:

git restore --source=HEAD~1 --worktree -- content/courses.md

Индекс остаётся на текущем коммите. Поэтому после замены появится рабочее различие: удаление рекомендации. История и указатель ветки не перемещаются. Для нашего урока это только временное сравнение; после чтения восстановите рабочий файл из текущего индекса обычным restore. Ожидаемое конечное состояние снова содержит рекомендацию и чистое дерево.

В реальном проекте HEAD~1 имеет смысл только после чтения истории. В ветке со слияниями эта запись выбирает первого родителя, а не любую интересующую старую версию. Надёжнее записать конкретный идентификатор нужного коммита и посмотреть файл. В лаборатории линейная история намеренно делает выбор однозначным.

При согласовании старой версии полезно сравнить и ссылку, и её подпись. Если вы вернули только адрес, а название теперь обещает другой курс, формально прежний URL восстановлен, но документ может вводить читателя в заблуждение. В нашем сценарии подпись JavaScript одинаковая во всех версиях, поэтому замена целого файла сохраняет эту согласованность. Для другого документа сначала сформулируйте, какие пары значений должны остаться вместе. Исторический снимок служит источником содержания, но решение о пригодности этого содержания относится к текущей задаче. Такой разбор помогает не превращать восстановление в механическое копирование любой старой страницы. Выбирайте версию по нужному результату, а затем читайте полученный документ как посетитель каталога.

Восстановление по смыслу

Представьте, что вы одновременно удалили ссылку и исправили опечатку в соседнем абзаце. Восстановление всего файла уберёт обе правки, хотя отказаться требуется только от удаления ссылки. Сначала прочитайте git diff, затем выберите ручное исправление или интерактивное восстановление отдельных фрагментов. Интерактивный режим требует внимательно читать каждый предлагаемый участок: границы фрагмента определяет сравнение строк, а не редакционная задача.

Не восстанавливайте содержимое широкой командой по всей папке лишь потому, что ошибку заметили на одной странице. Для большого каталога, подобного ProfessorWeb, рядом могут находиться десятки независимых незаписанных материалов. Точный путь делает действие обозримым; понимание источника объясняет, почему нужный текст сохранится.

Если выбранный снимок вообще не содержит отслеживаемого файла, восстановление может означать его удаление. Поэтому проверка show важна и для переименованных страниц. В нашем примере путь одинаков во всех снимках, и такой дополнительной развилки нет. Новые неотслеживаемые файлы тоже не следует считать автоматически сохранёнными в индексе или истории.

Наблюдаемый результат урока — правильные две ссылки, новая рекомендация в записанном снимке и отсутствие незаписанного изменения. Мы различили отказ от рабочего текста, снятие выбора из индекса и чтение старого файла. В следующем уроке используем историю, чтобы понять, откуда взялось конкретное изменение ссылки.