Зарегистрируйтесь, чтобы продолжить обучение

Отмена коммитов Введение в Git

Git — система, в которой не нужно бояться совершать ошибки. Можно сказать, что ошибки — это единственный способ научиться им пользоваться. В Git практически всегда есть способ восстановить или изменить любые коммиты. На крайний случай спасет повторный git clone.

Что делать, если коммит уже сделан, но он нас по каким-то причинам не устраивает? Ситуаций может быть много, и все они возникают регулярно даже у профессиональных разработчиков:

  • Забыли добавить в коммит нужные файлы
  • Изменения нужно «откатить», чтобы доработать
  • Изменения больше не актуальны, и их нужно удалить
  • Изменения были сделаны по ошибке, и их нужно отменить

По большей части Git движется «только вперед». Правильный подход при работе с ним — это создавать новое, а не изменять старое.

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

Несмотря на сказанное выше, внутри Git существуют специальные команды, позволяющие упростить отмену, либо изменение коммита. С их помощью можно сделать историю коммитов понятной, а сам процесс отката — быстрым. Эти команды мы изучим в этом уроке.

Git revert

Самая простая ситуация — отмена изменений. Фактически она сводится к созданию еще одного коммита, который выполняет изменения, противоположные тому коммиту, который отменяется:

git revert

Руками создавать подобный коммит довольно сложно, поэтому в Git добавили команду, автоматизирующую откат. Эта команда называется git revert:

# Этой команде нужен идентификатор коммита
# Это коммит, которым мы удалили файл PEOPLE.md
git revert aa600a43cb164408e4ad87d216bc679d097f1a6c
# После этой команды откроется редактор, ожидающий ввода описания коммита
# Обычно сообщение revert не меняют, поэтому достаточно просто закрыть редактор
[main 65a8ef7] Revert "remove PEOPLE.md"
 1 file changed, 1 insertion(+)
 create mode 100644 PEOPLE.md
# В проект вернулся файл PEOPLE.md

git log -p

commit 65a8ef7fd56c7356dcee35c2d05b4400f4467ca8
Author: tirion <tirion@got.com>
Date:   Sat Sep 26 15:32:46 2020 -0400

    Revert "remove PEOPLE.md"

    This reverts commit aa600a43cb164408e4ad87d216bc679d097f1a6c.

diff --git a/PEOPLE.md b/PEOPLE.md
new file mode 100644
index 0000000..4b34ba8
--- /dev/null
+++ b/PEOPLE.md
@@ -0,0 +1 @@
+Haskell Curry

Команда revert может отменять не только последний коммит, но и любой другой коммит из истории проекта. Согласитесь, это очень круто. Без системы контроля версий о таком нельзя было и мечтать.

Команда git reset

Представьте, что вам нужно удалить только что сделанный по ошибке коммит. Конечно, и в этом случае подходит git revert, но так история становится менее читаемой. Если этот коммит был сделан только сейчас и еще не отправлялся на GitHub, то лучше сделать так, как будто бы этого коммита не существовало в принципе.

Git позволяет удалять коммиты. Это опасная операция, которую нужно делать только в том случае, если речь идет про новые коммиты, которых нет ни у кого, кроме вас.

Если коммит был отправлен во внешний репозиторий, например, на GitHub, то менять историю ни в коем случае нельзя. Это сломает работу у тех, кто работает с вами над проектом.

Для удаления коммита используется команда git reset:

# Добавляем новый коммит, который мы сразу же удалим
echo 'test' >> INFO.md
git add INFO.md
git commit -m 'update INFO.md'

[main 17a77cb] update INFO.md
 1 file changed, 1 insertion(+)
 # Важно, что мы не делаем git push

git reset --hard HEAD~

HEAD is now at 65a8ef7 Revert "remove PEOPLE.md"

# Если посмотреть `git log`, то последнего коммита там больше нет

У команды git reset есть множество различных флагов и способов работы. С ее помощью можно удалять коммиты, отменять их без удаления, восстанавливать файлы из истории и так далее. Работа с ней относится к продвинутому использованию Git, но здесь мы затрагиваем только самую базу.

Флаг --hard означает полное удаление. Без него git reset отменит коммит, но не удалит его, а поместит все изменения этого коммита в рабочую директорию, так что с ними можно будет продолжить работать.

Флаг HEAD~ означает «один коммит от последнего коммита». Обратите внимание, что здесь используется знак ~ — тильда. Его легко перепутать с дефисом -. Если бы мы хотели удалить два последних коммита, то могли бы написать HEAD~2:

git reset

HEAD (переводится как «голова») — так обозначается последний сделанный коммит. Подробнее эту терминологию мы разберем в уроке, посвященном внутреннему устройству Git.

Без --hard команда git reset по умолчанию работает в режиме --mixed, при котором изменения остаются в рабочей директории, но исключаются из индекса (unstage). Затем их можно исправить или отменить и выполнить новый коммит:

echo 'no code no pain' > README.md
git add README.md
git commit -m 'update README.md'

[main f85e3a6] update README.md
 1 file changed, 1 insertion(+)

# Теперь откатываем последний коммит
git reset HEAD~

Unstaged changes after reset:
M   README.md

git status

On branch main
Your branch is up to date with 'origin/main'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   README.md

Опция --soft позволяет сохранить изменения в индексе:

git reset --soft HEAD~1

git status

On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   README.md

Команда git reset --soft отменяет коммит, но оставляет изменения в индексе (staging area). Следующий коммит включит в себя те же изменения, если их не модифицировать.

Последнего коммита больше не существует. При этом сделанные в нем изменения не пропали. Они находятся в рабочей директории для дальнейшей доработки.

git reset modes

Выводы

  • Git позволяет отменять, даже если допущена ошибка, всегда есть возможность её исправить. Это можно сделать несколькими способами
  • git revert — безопасный способ отмены коммитов. Он создаёт новый коммит, который отменяет изменения предыдущего. Это полезно при работе в команде, так как не меняет историю коммитов.
  • git reset — мощный, но потенциально опасный инструмент. Он позволяет отменять коммиты, но при этом может изменить или удалить изменения:

    • git reset --soft оставляет изменения в индексе.
    • git reset --mixed (по умолчанию) снимает индексацию, но оставляет изменения в рабочей директории.
    • git reset --hard полностью удаляет изменения, и их нельзя восстановить без специальных команд.
  • Изменять историю коммитов нужно с осторожностью. Если коммиты уже отправлены в удалённый репозиторий, лучше использовать git revert, так как git reset может привести к проблемам при синхронизации с другими разработчиками.

  • Правильный подход в Git — двигаться вперёд. Если в коммите ошибка, проще сделать новый исправляющий коммит, чем менять историю.

  • Перед использованием git reset --hard важно убедиться, что важные изменения не будут потеряны.

Таким образом, Git предоставляет инструменты для гибкого управления изменениями, но их использование требует понимания возможных последствий.


Самостоятельная работа

  1. Выполните все шаги из урока
  2. Измените добавленный текст на No code No pain
  3. Закоммитьте изменения с сообщением update README.md
  4. Залейте изменения на GitHub

Дополнительные материалы

  1. Документация Git — git reset

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
Верстка на HTML5 и CSS3, Программирование на JavaScript в браузере, разработка клиентских приложений используя React
10 месяцев
с нуля
Старт 24 апреля
профессия
Программирование на Python, Разработка веб-приложений и сервисов используя Django, проектирование и реализация REST API
10 месяцев
с нуля
Старт 24 апреля
профессия
Тестирование веб-приложений, чек-листы и тест-кейсы, этапы тестирования, DevTools, Postman, SQL, Git, HTTP/HTTPS, API
4 месяца
с нуля
Старт 24 апреля
профессия
Программирование на Java, Разработка веб-приложений и микросервисов используя Spring Boot, проектирование REST API
10 месяцев
с нуля
Старт 24 апреля
профессия
новый
Google таблицы, SQL, Python, Superset, Tableau, Pandas, визуализация данных, Anaconda, Jupyter Notebook, A/B-тесты, ROI
9 месяцев
с нуля
Старт 24 апреля
профессия
Программирование на PHP, Разработка веб-приложений и сервисов используя Laravel, проектирование и реализация REST API
10 месяцев
с нуля
Старт 24 апреля
профессия
Программирование на JavaScript в браузере и на сервере (Node.js), разработка бекендов на Fastify и фронтенда на React
16 месяцев
с нуля
Старт 24 апреля
профессия
Программирование на JavaScript, разработка веб-приложений, bff и сервисов используя Fastify, проектирование REST API
10 месяцев
с нуля
Старт 24 апреля
профессия
новый
Git, JavaScript, Playwright, бэкенд-тесты, юнит-тесты, API-тесты, UI-тесты, Github Actions, HTTP/HTTPS, API, Docker, SQL
8 месяцев
c опытом
Старт 24 апреля
профессия
новый
Разработка фронтенд- и бэкенд-компонентов для веб-приложений на Spring Boot и React
16 месяцев
с нуля
Старт 24 апреля
профессия
новый
Программирование на JavaScript и PHP, разработка веб-приложений и сервисов используя Laravel, проектирование REST API и работа с базами
16 месяцев
с нуля
Старт 24 апреля
профессия
новый
Автоматизированное тестирование веб-приложений на Python
8 месяцев
с нуля
Старт 24 апреля
профессия
новый
Программирование на JavaScript и Python, разработка веб-приложений и сервисов используя Django, проектирование REST API и работа с базами данных
16 месяцев
с нуля
Старт 24 апреля

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»