Отмена изменений

Отмена коммитов и изменений

В этом разделе мы обсудим доступные стратегии и команды Git для выполнения отмены изменений. Прежде всего необходимо отметить, что в Git не существует традиционной системы отмены, как в текстовых редакторах. Лучше воздержаться от сопоставления операций Git с какой бы то ни было традиционной концепцией отмены изменений. Кроме того, Git имеет собственную систему терминов для операций отмены, и в обсуждении лучше всего использовать их. В числе таких терминов — сброс (reset), возврат (revert), переключение (checkout), очистка (clean) и другие.

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

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

Поиск утерянного: просмотр старых коммитов

git log --oneline
e2f9a78fe Replaced FlyControls with OrbitControls
d35ce0178 Editor: Shortcuts panel Safari support.
9dbe8d0cf Editor: Sidebar.Controls to Sidebar.Settings.Shortcuts. Clean up.
05c5288fc Merge pull request #12612 from TyLindberg/editor-controls-panel
0d8b6e74b Merge pull request #12805 from harto/patch-1
23b20c22e Merge pull request #12801 from gam0022/improve-raymarching-example-v2
fe78029f1 Fix typo in documentation
7ce43c448 Merge pull request #12794 from WestLangley/dev-x
17452bb93 Merge pull request #12778 from OndrejSpanel/unitTestFixes
b5c1b5c70 Merge pull request #12799 from dhritzkiv/patch-21
1b48ff4d2 Updated builds.
88adbcdf6 WebVRManager: Clean up.
2720fbb08 Merge pull request #12803 from dmarcos/parentPoseObject
9ed629301 Check parent of poseObject instead of camera
219f3eb13 Update GLTFLoader.js
15f13bb3c Update GLTFLoader.js
6d9c22a3b Update uniforms only when onWindowResize
881b25b58 Update ProjectionMatrix on change aspect
Обучающее руководство по Git: переключение на предыдущий коммит

Просмотр старых версий

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

git log --oneline

Допустим, история вашего проекта выглядит примерно так:

b7119f2 Continue doing crazy things
872fa7e Try something crazy
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import

Для просмотра коммита «Make some important changes to hello.txt» можно использовать команду git checkout в следующем виде:

git checkout a1e8fb5

Это приведет к тому, что ваш рабочий каталог будет в точности соответствовать состоянию коммита a1e8fb5. Вы можете просматривать файлы, компилировать проект, запускать тесты и даже редактировать файлы, не боясь потерять текущее состояние проекта. Никакие внесенные здесь изменения не будут сохранены в репозитории. Чтобы продолжить разработку, необходимо вернуться к текущему состоянию проекта:

git checkout main

Отмена коммита снимка

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

git log --oneline
872fa7e Try something crazy
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import

Займемся отменой коммита 872fa7e Try something crazy. Возможно, безумный эксперимент зашел слишком далеко.

Отмена коммита с помощью git checkout

Отмена публичного коммита с помощью git revert

Предположим, мы вернулись к исходному примеру истории коммитов. Истории, в которую входит коммит 872fa7e. В этот раз попробуем отмену путем обратной операции. При исполнении команды git revert HEAD Git создаст новый коммит с операцией, обратной последнему коммиту. В текущую историю ветки будет добавлен новый коммит, и она будет выглядеть следующим образом:

git log --oneline
e2f9a78 Revert "Try something crazy"
872fa7e Try something crazy
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import

На этом этапе мы снова технически «отменили» коммит 872fa7e. Хотя коммит 872fa7e по-прежнему существует в истории, новый коммит e2f9a78 отменил изменения 872fa7e. В отличие от нашей предыдущей стратегии переключения с помощью команды checkout, мы можем продолжить работать с этой же веткой, поэтому данная стратегия является удовлетворительной. Это идеальный способ отмены при работе в открытых общих репозиториях, однако если у вас есть требование вести минимальную «очищенную» историю Git, эта стратегия может не подойти.

Отмена коммита с помощью git reset

git log --oneline
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import

Вывод команды log показывает, что коммиты e2f9a78 и 872fa7e больше не существуют в истории. На этом этапе мы можем продолжить работу и создавать новые коммиты так, словно «безумных» коммитов никогда не было. Этот метод отмены изменений оставляет историю максимально чистой. Отмена с помощью команды reset отлично подходит для локальных изменений, но при работе в общем удаленном репозитории создает сложности. Если у нас есть общий удаленный репозиторий, в котором с помощью команды push опубликован коммит 872fa7e, и мы попытаемся выполнить команду git push для ветки, в которой с помощью команды reset была сброшена история, система Git обнаружит это и выдаст ошибку. Git будет считать, что публикуемая ветка не была обновлена, поскольку в ней отсутствуют коммиты. В таких случаях лучше использовать отмену с помощью команды git revert.

Отмена последнего коммита

Отмена неотправленных изменений

Рабочий каталог

Раздел проиндексированных файлов

Отмена публичных изменений

При командной работе в удаленных репозиториях необходимо подходить к отмене изменений с особой осторожностью. Команда git reset, как правило, считается методом локальной отмены. Ее следует использовать для отмены изменений в частной ветке. Она безопасно изолирует удаление коммитов от других веток, которые могут использоваться другими разработчиками. Проблемы возникают, когда команда reset выполняется в общей ветке и затем эта ветка удаленно публикуется с помощью команды git push. В этом случае Git блокирует выполнение команды push и сообщает, что публикуемая ветка устарела, поскольку в ней отсутствуют коммиты, которые есть в удаленной ветке.

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

Резюме