Close

Resetting, checking out & reverting


The git reset, git checkout, and git revert commands are some of the most useful tools in your Git toolbox. They all let you undo some kind of change in your repository, and the first two commands can be used to manipulate either commits or individual files.

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

Три дерева Git

It helps to think about each command in terms of their effect on the three state management mechanisms of a Git repository: the working directory, the staged snapshot, and the commit history. These components are sometimes known as "The three trees" of Git. We explore the three trees in depth on the git reset page. Keep these mechanisms in mind as you read through this article.

Переключение версий (команда checkout) перемещает указатель HEAD на указанный коммит. Покажем это на следующем примере.

Перемещение указателя HEAD на указанный коммит
базы данных
Связанные материалы

Перемещение полного репозитория Git

Логотип Bitbucket
СМ. РЕШЕНИЕ

Изучите Git с помощью Bitbucket Cloud

В этом примере показана последовательность коммитов в ветке main. Сейчас и указатель HEAD, и указатель на главную ветку main указывают на коммит d. Теперь давайте выполним команду git checkout b

Sequence of commits on the main branch

Это обновление дерева «истории коммитов». Команду git checkout можно использовать на уровне коммита или файла. При переключении на уровне файла его содержимое будет отражать состояние при конкретном коммите.

Операция отмены (команда revert) принимает в качестве аргумента коммит и создает новый коммит, изменения в котором будут противоположны указанному. git revert действует только на уровне коммита и не работает на уровне файлов.

Операция сброса (команда reset) принимает в качестве аргумента коммит и сбрасывает «три дерева» до состояния репозитория при указанном коммите. Ее можно выполнить в трех разных режимах, соответствующих трем деревьям.

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

Git reset vs revert vs checkout reference


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

Команда

Область действия

Примеры использования

git reset

Область действия

На уровне коммита

Примеры использования

Discard commits in a private branch or throw away uncommitted changes

git reset

Область действия

На уровне файла

Примеры использования

Удаление файла из индекса

Git checkout

Область действия

На уровне коммита

Примеры использования

Переключение между ветками или проверка старых снимков состояния

Git checkout

Область действия

На уровне файла

Примеры использования

Отмена изменений в рабочем каталоге

git revert

Область действия

На уровне коммита

Примеры использования

Отмена коммитов в публичной ветке

git revert

Область действия

На уровне файла

Примеры использования

(Н/Д)

Commit level operations


Параметры, которые вы передаете командам git reset и git checkout, определяют область их действия. Если в качестве параметра не указан путь к файлу, они работают с коммитами целиком. Данный раздел посвящен работе на этом уровне. Обратите внимание, что git revert не имеет аналога на уровне файла.

Reset a specific commit

На уровне коммитов команда reset позволяет перенести конец ветки на другой коммит. Таким образом можно удалить коммиты из текущей ветки. Например, следующая команда перемещает ветку hotfix на два коммита назад.

git checkout hotfix git reset HEAD~2

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

Сброс ветки исправлений до HEAD-2

Команда git reset — это простой способ отменить изменения, которые еще никто не получал. Она прекрасно подойдет в случае, когда вы начали работать над функцией и вдруг подумали: «Ой, ну что я делаю? Лучше начать все сначала».

Помимо перемещения текущей ветки, с помощью команды git reset можно также изменить снимок состояния индекса и (или) рабочий каталог, передав ей один из следующих флагов:

  • --soft — снимок состояния индекса и рабочий каталог никак не изменяются.
  • --mixed — снимок состояния индекса обновляется в соответствии с указанным коммитом, а рабочий каталог остается неизменным. Это вариант по умолчанию.
  • --hard — снимок состояния индекса и рабочий каталог обновляются в соответствии с указанным коммитом.

It’s easier to think of these modes as defining the scope of a git reset operation. For further detailed information visit the git reset page.

Переключение на старые коммиты

Команду git checkout используют, чтобы обновлять состояние репозитория до определенной точки в истории проектов. Когда ей передают имя ветки, она позволяет переключиться на нее.

git checkout hotfix

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

Moving HEAD from main to hotfix

Кроме того, можно переключиться на конкретный коммит, передав в качестве аргумента ссылку на коммит, а не ветку. При этом происходит то же самое, что и при переключении на ветку: команда перемещает ссылку HEAD на указанный коммит. Например, следующая команда переключит версию на два уровня до текущего коммита:

git checkout HEAD~2
Перемещение указателя HEAD на конкретный коммит

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

Undo public commits with revert

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

git checkout hotfix git revert HEAD~2

Выглядит это следующим образом:

Отмена второго коммита с конца

Сравните это с командой git reset, которая меняет существующую историю коммитов. Поэтому команду git revert лучше использовать для отмены изменений в публичной ветке, а git reset следует оставить для сброса изменений в частной.

Или можно рассматривать git revert как инструмент для отмены изменений, попавших в коммиты, в то время как команда git reset HEAD предназначена для отмены изменений, не попавших в коммиты.

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

File-level operations


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

Git reset a specific file

При вызове с указанием пути к файлу команда git reset обновляет снимок состояния индекса, чтобы он соответствовал версии из указанного коммита. Например, следующая команда получит версию foo.py во втором с конца коммите и занесет ее в индекс для следующего коммита:

git reset HEAD~2 foo.py

Как и в случае с версией git reset на уровне коммита, этот вариант чаще используется с указателем HEAD, а не с конкретным коммитом. Выполнение команды git reset HEAD foo.py удалит файл foo.py из индекса. Содержащиеся в нем изменения по-прежнему будут присутствовать в рабочем каталоге.

Перемещение файла из истории коммитов в снимок состояния индекса

Флаги --soft, --mixed и --hard не влияют на работу команды git reset на уровне файла, поскольку снимок состояния индекса обновляется всегда, а рабочий каталог — никогда.

Git checkout file

Переключение на уровне файла аналогично использованию команды git reset с указанием пути к файлу, за исключением того, что оно обновляет рабочий каталог, а не индекс. В отличие от версии на уровне коммитов эта команда не перемещает ссылку HEAD, а значит, не переключает ветку.

Перемещение файла из истории коммитов в рабочий каталог

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

git checkout HEAD~2 foo.py

Как и вызов git checkout на уровне коммита, эту команду можно использовать для проверки старых версий проекта, только область действия будет ограничена указанным файлом.

Если вы выполните индексирование и коммит для файла, на который переключились, это приведет к восстановлению старой версии файла. Обратите внимание, что при этом удаляются все последующие изменения в файле, тогда как команда git revert отменяет только изменения, внесенные указанным коммитом.

Как и git reset, эту команду обычно используют с указателем HEAD в качестве ссылки на коммит. Например, команда git checkout HEAD foo.py отменит неиндексированные изменения в файле foo.py. Это поведение аналогично команде git reset HEAD --hard, но действует только на указанный файл.

Резюме


You should now have all the tools you could ever need to undo changes in a Git repository. The git reset, git checkout, and git revert commands can be confusing, but when you think about their effects on the working directory, staged snapshot, and commit history, it should be easier to discern which command fits the development task at hand.


Поделитесь этой статьей
Следующая тема

Рекомендуемые статьи

Добавьте эти ресурсы в закладки, чтобы изучить типы команд DevOps или получать регулярные обновления по DevOps в Atlassian.

Люди сотрудничают друг с другом, используя стену со множеством инструментов

Блог Bitbucket

Рисунок: DevOps

Образовательные программы DevOps

Демонстрация функций в демо-зале с участием экспертов Atlassian

Как инструмент Bitbucket Cloud работает с Atlassian Open DevOps

Подпишитесь на информационную рассылку по DevOps

Thank you for signing up