Урок курса

Отменить изменение новым коммитом

Git и GitHub с нуля: бесплатный курс с практикой

В прошлом уроке git commit --amend исправлял последний коммит — но ценой его замены: старый хеш исчезал из истории. Это работало, пока коммит не ушёл в общий репозиторий. Что делать, если коммит уже опубликован или вообще не последний? Для этого у Git есть другой инструмент — git revert.

Механизм git revert: новый обратный коммит поверх истории

Когда Git выполняет git revert, он смотрит на изменения выбранного коммита и создаёт поверх истории новый коммит с точно противоположным патчем: строки, которые были добавлены, теперь удаляются, и наоборот. Сам отменяемый коммит при этом не трогается — его хеш остаётся в истории на своём месте, его содержимое не меняется.

Это инвариант git revert: операция всегда только добавляет коммит в цепочку, никогда не удаляет существующие объекты. После выполнения команды git log покажет оба коммита — и оригинальный, который вы отменили, и новый, который аннулировал его изменения.

Практически это значит, что история становится длиннее, но остаётся честной: любой участник проекта, заглянув в лог, увидит, что именно было сделано и что потом было отменено. Ни одна строчка прошлого не стирается.

Revert против amend: какой из них переписывает историю

git commit --amend не добавляет коммит — он заменяет последний коммит новым объектом с новым хешем. Старый хеш исчезает из обычного git log. Если этот коммит уже был отправлен в общий репозиторий, у других участников в истории останется старая версия, а у вас — новая. Это расхождение приходится разруливать принудительно, и именно поэтому amend принято использовать только до публикации.

git revert не трогает ни один существующий коммит. Он добавляет новый поверх любой точки истории — неважно, последний это коммит или сделанный три недели назад, опубликован он или нет. Все уже существующие хеши остаются нетронутыми, поэтому коллеги, которые уже получили эту историю, не обнаружат расхождений.

Критерий выбора прямой:

  • Нужно поправить последний коммит, который ещё не уходил никуда → amend.
  • Нужно отменить любой коммит в опубликованной или общей истории → только revert.

Предусловия и синтаксис git revert --no-edit

Распакуйте git_practice.zip в новую отдельную папку и откройте терминал именно в git_practice/prepared/revert_history. Здесь уже есть .git; повторный git init не нужен. Для нового обратного коммита задайте обе локальные настройки автора по одной:

git config user.name "Учебный автор"
git config user.email "learner@example.invalid"

Main содержит три обычных коммита: контакт в README.md обновлён, а последующий независимый коммит добавил navigation.md. Перед учебным git revert рабочая папка и индекс должны быть чистыми. Проверьте это командой:

git status

Вывод должен содержать строку nothing to commit, working tree clean. При другом состоянии остановитесь: осознанно сохраните правки известным commit либо откажитесь от них изученными действиями, затем снова проверьте status. Это условие данного опыта, а не обещание отказа при любых рабочих изменениях. Не затрагиваемые операцией рабочие правки могут сохраниться; при необходимости их перезаписи Git защитно откажет.

Далее нужно узнать хеш коммита, который вы хотите отменить:

git log --oneline

Ниже сокращённый пример с условными ID; используйте значения фактического log своей копии:

a1b2c3d Добавить навигацию
7f4e921 Обновить контакт
3c09d12 Первый справочник

Найдите ID «Обновить контакт», который не является последним. Сначала выполните git show <найденный-ID> и прочитайте изменение контакта. Подставляйте свой ID вместо угловых скобок. Затем выполните:

git revert --no-edit <найденный-ID>

Флаг --no-edit говорит Git не открывать текстовый редактор для правки сообщения. Вместо этого Git сам формирует сообщение нового коммита по шаблону:

Revert "Обновить контакт"

Если флаг опустить, Git откроет редактор и предложит отредактировать это сообщение вручную — в учебных сценариях это лишнее, поэтому --no-edit удобен.

Команда работает только с обычными коммитами (не merge-коммитами). Для merge-коммитов синтаксис отличается и в этом уроке не рассматривается.

Как убедиться, что revert сработал: git log, git show и файлы

После выполнения git revert --no-edit <ID> выполните git log --oneline. История должна стать длиннее на один коммит. Продолжение условного примера ID:

e3d1fa2 Revert "Обновить контакт"
a1b2c3d Добавить навигацию
7f4e921 Обновить контакт
3c09d12 Первый справочник

Оба коммита присутствуют: и 7f4e921 Обновить контакт (исходный), и e3d1fa2 Revert "Обновить контакт" (новый, стоит выше). Если исходного коммита в логе нет — что-то пошло не так.

Далее проверьте содержимое нового коммита:

git show HEAD

Diff должен быть зеркальным по отношению к исходному. Если коммит 7f4e921 добавил строку Контакт: коллеги, то git show HEAD покажет её удаление:

-Контакт: коллеги
+Контакт: команда

Если хотите перекрёстно убедиться, выполните git show <найденный-ID> — его diff будет в точности противоположным: там будет +Контакт: коллеги и -Контакт: команда.

Наконец, откройте README.md напрямую — контакт должен вернуться к значению, которое было до отменяемого коммита. При этом navigation.md, добавленный коммитом «Добавить навигацию», остаётся нетронутым: revert затронул только те файлы, которые изменил коммит 7f4e921. Независимые коммиты, сделанные после него, revert не трогает.

Задача 1

В общей линейной истории есть обычный коммит К с ошибочной правкой. Рабочая папка и индекс чистые; обратная правка применяется без конфликта. Выполнили git revert --no-edit с ID К. Какая история получится?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 2

Практика: распакуйте git_practice.zip в отдельную новую папку и войдите в git_practice/prepared/revert_history. Репозиторий уже подготовлен, состояние чистое. Найдите в своей истории коммит «Обновить контакт», проверьте его изменение README через show и отмените известной формой revert без редактора сообщения. Проверьте новый обратный коммит и сохранность исходного. Запишите найденный ID, исходный и обратный diff, новую историю и содержимое README после отмены. Письменно объясните коллеге различие amend и revert для ошибочного уже опубликованного обычного коммита.

Платформа проверяет только ответ ниже; действия в своём репозитории и письменные ответы вы проверяете самостоятельно.

В контрольной истории К менял контакт в README, а следующий отдельный коммит Н создал navigation.md. Отмена К применена без конфликта. Что должно остаться после нового обратного коммита?

Выберите один вариант
Без регистрации · результат не сохраняется

Продолжить с сохранением прогресса

Перейдите к уроку в учебном кабинете.

Перейти к интерактивному уроку