<style>.lazy{display:none}</style>Команды Git: reset, checkout и revert

Команды Git: reset, checkout и revert

Команды git reset, git checkout и git revert – одни из самых полезных в Git. Все они позволяют отменять изменения в вашем репозитории, а первые две могут применяться как к коммитам, так и к отдельными файлам.

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

Содержание

Обзор команд

Составляющие Git-репозитория: рабочая директория, снимок состояния / индекс, история коммитов.

Лучше всего рассматривать каждую команду с точки зрения их влияния на три механизма управления состоянием репозитория Git: рабочая директория, снимок состояния/индекс и историю коммитов. Эти компоненты также иногда называют “тремя деревьями” Git.

БЕСПЛАТНО СКАЧАТЬ КНИГИ в телеграм канале "Библиотека тестировщика"

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

Цепочка коммитов a-b-c-d. Указатели Head и Main нацелены на последний коммит - d.

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

После выполнения команды git checkout Head указывает на коммит b, а Main - по-прежнему на d.

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

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

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

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

Сравнение git reset, git revert и git checkout

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

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

Команды на уровне коммита

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

Сброс (reset) коммита

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

git checkout hotfix git reset HEAD~2

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

Откат ветки hotfix к HEAD-2. Состояние до отката: в ветке hotfix HEAD указывает на последний из трех коммитов.
Откат ветки hotfix к HEAD-2. Состояние до отката: в ветке hotfix HEAD указывает на первый из трех коммитов. Два оставшихся коммита становятся открепленными.

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

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

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

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

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

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

git checkout hotfix

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

Перемещение HEAD из ветки  master в ветку hotfix. Состояние до переключения.
Перемещение HEAD из ветки  master в ветку hotfix. Состояние после переключения.

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

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

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

Отмена коммитов, внесенных в общий доступ, с помощью revert

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

git checkout hotfix git revert HEAD~2

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

Отмена изменений от второго с конца коммита. Состояние до применения revert.
Отмена изменений от второго с конца коммита. Состояние после применения revert.

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

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

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

Команды на уровне файлов

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

Отмена изменений в файле с помощью git reset

При вызове с указанием пути к файлу команда 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

Команда checkout для файла аналогична использованию 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, но действует только на указанный файл.

Смотрите также: “Настройка Git репозитория”.

Заключение

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

Перевод статьи «Resetting, checking out & reverting».

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *