Русский ▾ Topics ▾ Latest version ▾ git-reset last updated in 2.54.0

НАЗВАНИЕ

git-reset — Установка HEAD или индекса в известное состояние

ОБЗОР

git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<коммит>]
git reset [-q] [<указатель-дерева>] [--] <спецификатор-пути>…​
git reset [-q] [--pathspec-from-file=<файл> [--pathspec-file-nul]] [<указатель-дерева>]
git reset (--patch | -p) [<указатель-дерева>] [--] [<спецификатор-пути>…​]

ОПИСАНИЕ

git reset выполняет одно из следующих действий:

  1. git reset [<режим>] <коммит> изменяет коммит, на который указывает HEAD. Это позволяет отменять различные операции Git, например, коммит, слияние, перемещение и получение.

  2. Когда вы указываете файлы или каталоги или передаёте --patch, git reset обновляет проиндексированную версию указанных файлов.

    git reset [<режим>] [<коммит>]

    Установить голову текущей ветки (HEAD), чтобы она указывала на <коммит>. В зависимости от <режима>, также обновляет рабочий каталог и/или индекс в соответствии с содержимым <коммита>. <коммит> по умолчанию равен HEAD. Перед операцией ORIG_HEAD устанавливается на верхушку текущей ветки.

    <режим> должен быть одним из следующих (по умолчанию --mixed):

    --mixed

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

    Если указан -N, помечать удалённые пути как intent-to-add (см. git-add[1]).

    --soft

    Оставляет ваши файлы рабочего каталога и индекс неизменными. Например, если у вас нет проиндексированных изменений, вы можете использовать git reset --soft HEAD~5; git commit, чтобы объединить последние 5 коммитов в 1 коммит. Это работает даже при наличии изменений в рабочем каталоге, которые остаются нетронутыми, но такое использование может привести к путанице.

    --hard

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

    --merge

    Сбрасывает индекс и обновляет файлы в рабочем каталоге, которые отличаются между <коммитом> и HEAD, но сохраняет те, которые отличаются между индексом и рабочим каталогом (т.е. которые имеют не добавленные изменения). В основном существует для сброса не слитых записей индекса, таких как те, что остаются после git am -3 или git switch -m в определённых ситуациях. Если файл, который отличается между <коммитом> и индексом, имеет неиндексированные изменения, сброс прерывается.

    --keep

    Сбрасывает записи индекса и обновляет файлы в рабочем каталоге, которые отличаются между <коммитом> и HEAD. Если файл, который отличается между <коммитом> и HEAD, имеет локальные изменения, сброс прерывается.

    --recurse-submodules
    --no-recurse-submodules

    При обновлении рабочего каталога использование --recurse-submodules также рекурсивно сбросит рабочий каталог всех активных подмодулей в соответствии с коммитом, записанным в суперпроекте, также установив HEAD подмодулей в отсоединённое состояние на этом коммите.

    git reset [-q] [<указатель-дерева>] [--] <спецификатор-пути>...
    git reset [-q] [--pathspec-from-file=<файл> [--pathspec-file-nul]] [<указатель-дерева>]

    Для всех указанных файлов или каталогов устанавливает проиндексированную версию в версию из указанного коммита или дерева (которая по умолчанию равна HEAD).

    Это означает, что git reset <спецификатор-пути> является противоположностью git add <спецификатор-пути>: он убирает из индекса все изменения в указанных файлах или каталогах. Это эквивалентно git restore --staged <спецификатор-пути>....

    В этом режиме git reset обновляет только индекс (без обновления HEAD или файлов рабочего каталога). Если вы хотите обновить как файлы, так и записи индекса, используйте git-restore[1].

    git reset (--patch | -p) [<указатель-дерева>] [--] [<спецификатор-пути>...]

    Интерактивно выбирает изменения из различий между индексом и указанным коммитом или деревом (которое по умолчанию равно HEAD). Индекс изменяется с использованием выбранных изменений.

    Это означает, что git reset -p является противоположностью git add -p, т.е. вы можете использовать его для выборочного снятия изменений с индекса (unstage). См. раздел "Интерактивный режим" в git-add[1], чтобы узнать, как использовать параметр --patch.

См. "Сброс, восстановление и отмена" в git[1] для получения информации о различиях между тремя командами.

ПАРАМЕТРЫ

-q
--quiet

Тихий режим, выводить только ошибки.

--refresh
--no-refresh

Освежает индекс после смешанного сброса. Включено по умолчанию.

--pathspec-from-file=<файл>

Спецификатор пути передаётся в <файле>, а не в аргументах командной строки. Если <файл> точно равен -, то используется стандартный ввод. Элементы спецификатора пути разделяются символами LF или CR/LF. Элементы спецификатора пути могут заключаться в кавычки, как объяснено для переменной конфигурации core.quotePath (см. git-config[1]). См. также --pathspec-file-nul и глобальный --literal-pathspecs.

--pathspec-file-nul

Имеет значение только при указании --pathspec-from-file. Элементы спецификатора пути отделяются друг от друга с помощью NUL-символа, а все остальные символы интерпретируются буквально (включая кавычки и переводы строк).

-U<n>
--unified=<n>

Создавать сравнения с <число> строками контекста. Количество строк контекста по умолчанию равно diff.context или 3, если переменная конфигурации не установлена. (-U без <числа> молча принимается как синоним -p из-за исторической случайности).

--inter-hunk-context=<n>

Выводить в качестве контекста между блоками изменений до <n> строк, тем самым объединяя близкие блоки изменений. По умолчанию равно значению переменной конфигурации diff.interHunkContext или 0, если она не установлена.

--

Не рассматривать остальные аргументы командной строки в качестве параметров.

<спецификатор-пути>…

Ограничивает пути, на которые влияет операция.

Более подробно описание см. в параграфе спецификатор пути (pathspec) в gitglossary[7].

ПРИМЕРЫ

Отменить добавление
$ edit                                     (1)
$ git add frotz.c filfre.c
$ mailx                                    (2)
$ git reset                                (3)
$ git pull git://info.example.com/ nitfol  (4)
  1. Вы счастливо работаете над чем-то и обнаруживаете, что изменения в этих файлах в хорошем порядке. Вы не хотите видеть их при выполнении git diff, поскольку планируете работать над другими файлами, а изменения в этих файлах отвлекают.

  2. Кто-то просит вас выполнить получение, и изменения выглядят достойными слияния.

  3. Однако вы уже изменили индекс (т.е. ваш индекс не соответствует коммиту HEAD). Но вы знаете, что получение, которое вы собираетесь выполнить, не затрагивает frotz.c или filfre.c, поэтому вы отменяете изменения индекса для этих двух файлов. Ваши изменения в рабочем каталоге остаются там.

  4. Затем вы можете выполнить получение и слияние, оставив изменения в frotz.c и filfre.c всё ещё в рабочем каталоге.

Отменить коммит и переделать
$ git commit ...
$ git reset --soft HEAD^      (1)
$ edit                        (2)
$ git commit -a -c ORIG_HEAD  (3)
  1. Это чаще всего делается, когда вы вспомнили, что только что закоммиченное неполно, или вы сделали опечатку в сообщении коммита, или и то, и другое. Оставляет рабочий каталог таким, каким он был до "reset".

  2. Внесите исправления в файлы рабочего каталога.

  3. "reset" копирует старую голову в .git/ORIG_HEAD; переделайте коммит, начиная с его сообщения журнала. Если вам не нужно дополнительно редактировать сообщение, вы можете вместо этого указать параметр -C.

    См. также параметр --amend в git-commit[1].

Отменить коммит, превратив его в тематическую ветку
$ git branch topic/wip          (1)
$ git reset --hard HEAD~3       (2)
$ git switch topic/wip          (3)
  1. Вы сделали несколько коммитов, но понимаете, что они были преждевременными для ветки master. Вы хотите продолжить их доработку в тематической ветке, поэтому создайте ветку topic/wip от текущего HEAD.

  2. Перемотайте ветку master назад, чтобы избавиться от этих трёх коммитов.

  3. Переключитесь на ветку topic/wip и продолжайте работу.

Отменить коммиты навсегда
$ git commit ...
$ git reset --hard HEAD~3   (1)
  1. Последние три коммита (HEAD, HEAD^ и HEAD~2) были плохими, и вы больше никогда не хотите их видеть. Не делайте этого, если вы уже передали эти коммиты кому-то ещё. (О последствиях такого действия см. раздел "ВОССТАНОВЛЕНИЕ ПОСЛЕ ПЕРЕМЕЩЕНИЯ ВЫШЕСТОЯЩЕЙ ВЕТКИ" в git-rebase[1].)

Отменить слияние или получение
$ git pull                         (1)
Auto-merging nitfol
CONFLICT (content): Merge conflict in nitfol
Automatic merge failed; fix conflicts and then commit the result.
$ git reset --hard                 (2)
$ git pull . topic/branch          (3)
Updating from 41223... to 13134...
Fast-forward
$ git reset --hard ORIG_HEAD       (4)
  1. Попытка обновления из вышестоящей ветки привела к множеству конфликтов; вы не были готовы тратить много времени на слияние сейчас, поэтому решаете сделать это позже.

  2. "pull" не создал коммит слияния, поэтому git reset --hard, который является синонимом git reset --hard HEAD, очищает беспорядок в файле индекса и рабочем каталоге.

  3. Слияние тематической ветки с текущей веткой, которое привело к перемотке вперёд.

  4. Но вы решили, что тематическая ветка ещё не готова для публичного использования. "pull" или "merge" всегда оставляют исходную верхушку текущей ветки в ORIG_HEAD, поэтому жёсткий сброс на неё возвращает ваш файл индекса и рабочий каталог в то состояние и сбрасывает верхушку ветки на этот коммит.

Отменить слияние или получение в изменённом рабочем каталоге
$ git pull                         (1)
Auto-merging nitfol
Merge made by recursive.
 nitfol                |   20 +++++----
 ...
$ git reset --merge ORIG_HEAD      (2)
  1. Даже если у вас могут быть локальные изменения в вашем рабочем каталоге, вы можете безопасно выполнить git pull, когда знаете, что изменения в другой ветке не пересекаются с ними.

  2. После изучения результата слияния вы можете обнаружить, что изменения в другой ветке неудовлетворительны. Выполнение git reset --hard ORIG_HEAD вернёт вас туда, где вы были, но отбросит ваши локальные изменения, чего вы не хотите. git reset --merge сохраняет ваши локальные изменения.

Прерванный рабочий процесс

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

$ git switch feature  ;# вы работали в ветке "feature" и
$ work work work      ;# были прерваны
$ git commit -a -m "snapshot WIP"                 (1)
$ git switch master
$ fix fix fix
$ git commit ;# коммит с реальным журналом
$ git switch feature
$ git reset --soft HEAD^ ;# вернуться в состояние WIP  (2)
$ git reset                                       (3)
  1. Этот коммит будет удалён, поэтому подойдёт временное сообщение журнала.

  2. Это удаляет коммит WIP из истории коммитов и устанавливает ваш рабочий каталог в состояние непосредственно перед тем, как вы сделали этот снимок.

  3. На этом этапе файл индекса всё ещё содержит все изменения WIP, которые вы закоммитили как snapshot WIP. Это обновляет индекс, чтобы показать ваши файлы WIP как незакоммиченные.

    См. также git-stash[1].

Сбросить один файл в индексе

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

$ git reset -- frotz.c                      (1)
$ git commit -m "Commit files in index"     (2)
$ git add frotz.c                           (3)
  1. Это удаляет файл из индекса, оставляя его в рабочем каталоге.

  2. Это фиксирует все остальные изменения в индексе.

  3. Снова добавляет файл в индекс.

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

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

$ git tag start
$ git switch -c branch1
$ edit
$ git commit ...                            (1)
$ edit
$ git switch -c branch2                     (2)
$ git reset --keep start                    (3)
  1. Это фиксирует ваши первые правки в branch1.

  2. В идеальном мире вы могли бы понять, что более ранний коммит не относится к новой теме, когда создавали и переключались на branch2 (т.е. git switch -c branch2 start), но никто не совершенен.

  3. Но вы можете использовать reset --keep, чтобы удалить нежелательный коммит после того, как переключились на branch2.

Разделить коммит на последовательность коммитов

Предположим, вы создали много логически отдельных изменений и закоммитили их вместе. Затем позже вы решаете, что было бы лучше связать каждый логический блок с собственным коммитом. Вы можете использовать git reset, чтобы перемотать историю назад без изменения содержимого ваших локальных файлов, а затем последовательно использовать git add -p для интерактивного выбора того, какие части включать в каждый коммит, используя git commit -c для предварительного заполнения сообщения коммита.

$ git reset -N HEAD^                        (1)
$ git add -p                                (2)
$ git diff --cached                         (3)
$ git commit -c HEAD@{1}                    (4)
...                                         (5)
$ git add ...                               (6)
$ git diff --cached                         (7)
$ git commit ...                            (8)
  1. Сначала сбросьте историю на один коммит назад, чтобы удалить исходный коммит, но оставить рабочий каталог со всеми изменениями. -N гарантирует, что любые новые файлы, добавленные с HEAD, по-прежнему отмечены, чтобы git add -p мог их найти.

  2. Затем мы интерактивно выбираем части сравнения для добавления с помощью возможности git add -p. Он будет спрашивать вас о каждой части сравнения по порядку, и вы можете использовать простые команды, такие как "yes, include this", "No don’t include this" или даже очень мощную возможность "edit".

  3. Когда вы удовлетворены частями, которые хотите включить, вы должны проверить, что было подготовлено для первого коммита, с помощью git diff --cached. Это показывает все изменения, которые были перемещены в индекс и вот-вот будут закоммичены.

  4. Затем зафиксируйте изменения, хранящиеся в индексе. Параметр -c указывает предварительно заполнить сообщение коммита из исходного сообщения, с которого вы начали в первом коммите. Это полезно, чтобы избежать повторного ввода. HEAD@{1} — это специальное обозначение коммита, на котором HEAD находился до исходного сброса (1 изменение назад). Дополнительные сведения см. в git-reflog[1]. Вы также можете использовать любую другую допустимую ссылку на коммит.

  5. Вы можете повторять шаги 2-4 несколько раз, чтобы разбить исходный код на любое количество коммитов.

  6. Теперь вы выделили многие изменения в отдельные коммиты и можете больше не использовать режим патча git add, чтобы выбрать все оставшиеся незакоммиченные изменения.

  7. Ещё раз проверьте, чтобы убедиться, что вы включили то, что хотели. Вы также можете проверить, что git diff не показывает никаких оставшихся изменений для последующей фиксации.

  8. И наконец, создайте финальный коммит.

ОБСУЖДЕНИЕ

Таблицы ниже показывают, что происходит при выполнении:

git reset --option целевой_объект

для сброса HEAD на другой коммит (целевой_объект) с различными параметрами сброса в зависимости от состояния файлов.

В этих таблицах A, B, C и D — это некоторые различные состояния файла. Например, первая строка первой таблицы означает, что если файл находится в состоянии A в рабочем каталоге, в состоянии B в индексе, в состоянии C в HEAD и в состоянии D в целевом объекте, то git reset --soft целевой_объект оставит файл в рабочем каталоге в состоянии A, а в индексе — в состоянии B. Он сбрасывает (т.е. перемещает) HEAD (т.е. верхушку текущей ветки, если вы на ней находитесь) на целевой_объект (который имеет файл в состоянии D).

рабочий индекс HEAD целевой         рабочий индекс HEAD
----------------------------------------------------
 A       B     C    D     --soft   A       B     D
			  --mixed  A       D     D
			  --hard   D       D     D
			  --merge (запрещено)
			  --keep  (запрещено)
рабочий индекс HEAD целевой         рабочий индекс HEAD
----------------------------------------------------
 A       B     C    C     --soft   A       B     C
			  --mixed  A       C     C
			  --hard   C       C     C
			  --merge (запрещено)
			  --keep   A       C     C
рабочий индекс HEAD целевой         рабочий индекс HEAD
----------------------------------------------------
 B       B     C    D     --soft   B       B     D
			  --mixed  B       D     D
			  --hard   D       D     D
			  --merge  D       D     D
			  --keep  (запрещено)
рабочий индекс HEAD целевой         рабочий индекс HEAD
----------------------------------------------------
 B       B     C    C     --soft   B       B     C
			  --mixed  B       C     C
			  --hard   C       C     C
			  --merge  C       C     C
			  --keep   B       C     C
рабочий индекс HEAD целевой         рабочий индекс HEAD
----------------------------------------------------
 B       C     C    D     --soft   B       C     D
			  --mixed  B       D     D
			  --hard   D       D     D
			  --merge (запрещено)
			  --keep  (запрещено)
рабочий индекс HEAD целевой         рабочий индекс HEAD
----------------------------------------------------
 B       C     C    C     --soft   B       C     C
			  --mixed  B       C     C
			  --hard   C       C     C
			  --merge  B       C     C
			  --keep   B       C     C

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

git reset --keep предназначен для использования при удалении некоторых последних коммитов в текущей ветке с сохранением изменений в рабочем каталоге. Если могут быть конфликты между изменениями в коммите, который мы хотим удалить, и изменениями в рабочем каталоге, которые мы хотим сохранить, сброс запрещён. Вот почему он запрещён, если есть изменения как между рабочим каталогом и HEAD, так и между HEAD и целевым объектом. Для безопасности он также запрещён, когда есть не слитые записи.

Следующие таблицы показывают, что происходит, когда есть не слитые записи:

рабочий индекс HEAD целевой         рабочий индекс HEAD
----------------------------------------------------
 X       U     A    B     --soft  (запрещено)
			  --mixed  X       B     B
			  --hard   B       B     B
			  --merge  B       B     B
			  --keep  (запрещено)
рабочий индекс HEAD целевой         рабочий индекс HEAD
----------------------------------------------------
 X       U     A    A     --soft  (запрещено)
			  --mixed  X       A     A
			  --hard   A       A     A
			  --merge  A       A     A
			  --keep  (запрещено)

X означает любое состояние, а U означает не слитый индекс.

GIT

Является частью пакета git[1]