В этой статье мы рассмотрим команду git reset
, которая позволит отменить неправильные/неудачные изменения, сделанные локально, а также «откатить» неудачный merge
(слияние).
Содержание:
Постановка задачи
Основные сведения
Примеры использования
«Странная» нотация (~ и ^)
Заключение
Допустим, вы работаете над проектом, и сделали изменения, которые теперь хотите отменить. Можно выполнить git status
и увидеть все сделанные изменения, после чего вручную отменить ненужные. Но что если изменений очень много (такое случается после неудачных «ручных» мерджей)? В таком случае вам поможет команда git reset
. Эта команда подобна скальпелю — она очень острая/эффективная, и именно поэтому ее следует использовать с осторожностью.
Далее рассмотрим основные сценарии ее использования.
Вообще говоря, назначение git reset
— взять текущую ветку и «сбросить» (переназначить, англ. reset
) ее так, чтобы она указывала на какой-либо другой коммит; в частности, засинхронизировать индекс и рабочее дерево репозитория. Более конкретно, если ваша ветка master
(в настоящее время в статусе checkout
) выглядит так:
- A - B - C (HEAD, master)
где A, B, C — последовательные коммиты ветки master
. И вы хотите, чтобы master заканчивалась коммитом B, а не С, то вы используете git reset <B>
(в данном случае <B> — это хэш коммита B), чтобы переместить ее туда:
- A - B (HEAD, master) # - коммит C все еще здесь, но никакая ветка больше не указывает на этот коммит
Важный момент: это поведение существенно отличается от команды git checkout <B>
, которая привела бы к такому результату:
- A - B (HEAD) - C (master)
В результате вы получите состояние с отсоединенным (detached) указателем HEAD. Итак, HEAD, ваше рабочее дерево, индекс — все соответствуют коммиту B, но ветка master была оставлена на коммите C. Если в данном состоянии репозитория вы сделаете новый коммит D, вы получите такую конфигурацию, которая, скорее всего, отличается от того, чего вы хотели достичь:
Запомните главное: reset
не делает коммитов, он всего лишь меняет ветку (которая указывает на коммит), чтобы она указывала на другой коммит. Другими словами, что бы ни значило само слово reset
, логически оно определяет, что происходит с вашим индексом и рабочим деревом.
Рассмотрим некоторые основные варианты использования git reset
.
Команду можно использовать для самых разных целей; общая идея состоит в том, что все они включают сброс ветки, индекса и/или рабочего дерева с тем, чтобы они указывали/соответствовали заданному коммиту.
Если сократить документацию git reset до одного абзаца, наиболее частый путь использования команды — git reset [<коммит>] [пути...]
, что сбросит данные пути до их состояния из данного коммита. Если пути не указаны, все дерево будет сброшено («ресетнуто»), а если коммит не указан, подразумевается коммит HEAD
(текущий коммит).
Это стандартный паттерн команд git (включая checkout, diff, log, хотя семантика может несколько отличаться), так что сюрпризов здесь не предвидится.
Например, git reset <другая-ветка> <путь/к/директории>
сбрасывает все в пути <путь/к/директории> к его состоянию в ветке <другая-ветка>; git reset — сбрасывает текущую директорию к ее состоянию в HEAD, а простой git reset сбрасывает все дерево к его состоянию в HEAD.
Всего есть четыре опции для управления тем, что происходит с вашим рабочим деревом и индексом во время исполнения команды reset.
Напомним, «индекс» — это «сцена» git’а, условное место, где происходят изменения, когда вы, например, выполняете команду git add
, подготавливая свой коммит.
git reset --hard
означает git reset --hard HEAD
, то есть, не изменяя ветку, избавиться от всех локальных изменений. Другой случай применения — перенести ветку из одного места в другое и держать при этом индекс/рабочее дерево в синхронизированном состоянии. Напоминаем, эта опция действительно может привести к потере вашей работы, поскольку она модифицирует ваше рабочее дерево. Будьте на 100% уверены, что действительно хотите отказаться от локальных изменений, перед тем как выполнять reset --hard
.
git reset --mixed
. Эта команда сбрасывает индекс, но не рабочее дерево. Это означает, что все ваши файлы остаются неизменными, но любые изменения между текущим коммитом и коммитом, к которому вы сбрасываете, будут показаны как локальные изменения (или неотслеживаемые/untracked файлы) во время выполнения команды git status
. Используйте эту опцию, когда вы вдруг поняли, что сделали неправильные коммиты, но все же хотите оставить некоторые изменения, которые сделали, чтобы их исправить и закоммитить снова. Чтобы закоммитить, вам придется добавить файлы в индекс снова командой git add
.--soft
не изменяет индекс или рабочее дерево. Все ваши файлы остаются нетронутыми, как если бы вы использовали --mixed
, но все изменения показываются как готовые к коммиту во время выполнения git status
(то есть, зачекиненные и готовые к коммиту). Используйте эту опцию, если осознали, что сделали несколько плохих коммитов, но сейчас состояние проекта правильное, и все что вам нужно — перекоммитить его еще раз. Индекс не тронут, поэтому вы можете закоммитить немедленно — результирующий коммит будет иметь то же содержание, которое было до выполнения reset.
git reset --merge
сбрасывает индекс (подобно опции --mixed
— все изменения показываются как локальные изменения) и сбрасывает все файлы, затронутые слиянием, но не трогает остальные файлы. Это может позволить восстановить все до состояния, которое было до «плохого» слияния. Скорее всего, вы будете использовать это как git reset --merge
(что означает git reset --merge HEAD
), потому что хотите сбросить только изменения, вызванные попыткой слияния, а не переместить ветку (указатель HEAD не изменился, поскольку слияние было неудачным).
Если говорить более конкретно, представим, что мы поменяли файлы A и B и пытаемся «смерджиться» в ветку с измененными файлами C и D. Слияние «фейлится» по какой-либо причине, и мы решаем прервать его. Используем git reset --merge
. Это приводит C и D обратно к состоянию, которое у них было в HEAD, но не затрагивает изменения в A и B, поскольку они не участвовали в попытке слияния.
При использовании команды git reset
«странная нотация» бывает особенно полезной, поскольку позволяет указывать коммиты, близкие к HEAD, без необходимости написания их хэшей:
В этой статье мы рассмотрели команду git, которая позволяет отменить/исправить локальные изменения — git reset
. Изучили различные условия, в которых приходится вносить исправления: отмена всего, частичная отмена, отмена в случае слияния. Освежили полезную «странную» нотацию для указания коммита без хэша — «~ и ^» нотацию.
Более подробно про нашу тему в этом видео: как различить soft, mixed и hard Git Reset:
Прокси (proxy), или прокси-сервер — это программа-посредник, которая обеспечивает соединение между пользователем и интернет-ресурсом. Принцип…
Согласитесь, было бы неплохо соединить в одно сайт и приложение для смартфона. Если вы еще…
Повсеместное распространение смартфонов привело к огромному спросу на мобильные игры и приложения. Миллиарды пользователей гаджетов…
В перечне популярных чат-ботов с искусственным интеллектом Google Bard (Gemini) еще не пользуется такой популярностью…
Скрипт (англ. — сценарий), — это небольшая программа, как правило, для веб-интерфейса, выполняющая определенную задачу.…
Дедлайн (от англ. deadline — «крайний срок») — это конечная дата стачи проекта или задачи…