Spec-Zone.ru › Git

git-reset

Название

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

Краткое описание

git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
git reset [-q] [<tree-ish>] [--] <pathspec>…​
git reset [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]
git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>…​]

Описание

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

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

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

    git reset [<mode>] [<commit>]

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

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

    --mixed

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

    Если указан -N, удалённые пути помечаются как предназначенные для добавления (см. git-add[1]).

    --soft

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

    --hard

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

    --merge

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

    --keep

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

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

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

    git reset [-q] [<tree-ish>] [--] <pathspec>...
    git reset [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]

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

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

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

    git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>...]

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

    Это означает, что git reset -p — противоположность git add -p, то есть её можно использовать для выборочной отмены подготовки изменений. О том, как использовать параметр --patch, см. раздел «Интерактивный режим» в git-add[1].

Различия между этими тремя командами описаны в разделе «Reset, restore and revert» руководства git[1].

Параметры

-q
--quiet

Не выводить сообщения, сообщать только об ошибках.

--refresh
--no-refresh

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

--pathspec-from-file=<file>

Спецификация путей передаётся в <file>, а не в аргументах командной строки. Если <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>

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

--inter-hunk-context=<n>

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

--

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

<pathspec>...

Ограничивает пути, затрагиваемые операцией.

Подробнее см. статью 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. Кто-то просит вас выполнить pull, и изменения кажутся достойными слияния.

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

  4. Теперь можно выполнить pull и merge, оставив изменения в 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) были неудачными, и вы больше никогда не хотите их видеть. Не делайте этого, если уже передали эти коммиты кому-либо. (О последствиях см. раздел «RECOVERING FROM UPSTREAM REBASE» в git-rebase[1].)

Отмена слияния или pull
$ 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, поэтому жёсткий сброс к ней восстанавливает прежнее состояние файла индекса и рабочего дерева, а также перемещает вершину ветки на этот коммит.

Отмена слияния или pull в изменённом рабочем дереве
$ 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  ;# you were working in "feature" branch and
$ work work work      ;# got interrupted
$ git commit -a -m "snapshot WIP"                 (1)
$ git switch master
$ fix fix fix
$ git commit ;# commit with real log
$ git switch feature
$ git reset --soft HEAD^ ;# go back to WIP state  (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. Она последовательно предложит выбрать действие для каждого фрагмента различий: можно использовать простые команды вроде «да, включить это», «нет, не включать это» или даже очень мощную функцию «редактировать».

  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 target

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

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

working index HEAD target         working index HEAD
----------------------------------------------------
 A       B     C    D     --soft   A       B     D
                          --mixed  A       D     D
                          --hard   D       D     D
                          --merge (disallowed)
                          --keep  (disallowed)
working index HEAD target         working index HEAD
----------------------------------------------------
 A       B     C    C     --soft   A       B     C
                          --mixed  A       C     C
                          --hard   C       C     C
                          --merge (disallowed)
                          --keep   A       C     C
working index HEAD target         working index HEAD
----------------------------------------------------
 B       B     C    D     --soft   B       B     D
                          --mixed  B       D     D
                          --hard   D       D     D
                          --merge  D       D     D
                          --keep  (disallowed)
working index HEAD target         working index 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
working index HEAD target         working index HEAD
----------------------------------------------------
 B       C     C    D     --soft   B       C     D
                          --mixed  B       D     D
                          --hard   D       D     D
                          --merge (disallowed)
                          --keep  (disallowed)
working index HEAD target         working index 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 и целевым коммитом. В целях безопасности сброс также запрещён при наличии неслитых записей.

В следующих таблицах показано, что происходит при наличии неслитых записей:

working index HEAD target         working index HEAD
----------------------------------------------------
 X       U     A    B     --soft  (disallowed)
                          --mixed  X       B     B
                          --hard   B       B     B
                          --merge  B       B     B
                          --keep  (disallowed)
working index HEAD target         working index HEAD
----------------------------------------------------
 X       U     A    A     --soft  (disallowed)
                          --mixed  X       A     A
                          --hard   A       A     A
                          --merge  A       A     A
                          --keep  (disallowed)

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

reset

© 2005–2026 Linus Torvalds and others
Licensed under the GNU General Public License version 2.
https://git-scm.com/docs/git-reset

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API