В чем разница между git reset --mixed, --soft и --hard?

Я ищу разделить коммит и не уверен, какой вариант сброса использовать.

Я смотрел на страницу. Можете ли вы объяснить, что делает "git reset" на простом английском?, но я понял, что не совсем понимаю, что такое индекс git или область подготовки, и поэтому объяснения не помогли.

Также варианты использования для --mixed а также --soft Посмотрите на меня в том же ответе (когда вы хотите исправить и подтвердить.) Может кто-нибудь сломать его еще больше? я понимаю --mixed Вероятно, это вариант, но я хочу знать, почему. Наконец, как насчет --hard?

Может ли кто-нибудь дать мне пример рабочего процесса, как будет происходить выбор 3-х вариантов?

18 ответов

Решение

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

git reset меняет, как минимум, текущую ветку (HEAD) указывает. Разница между --mixed а также --soft является ли ваш индекс также изменен. Итак, если мы находимся на ветке master с этой серией коммитов:

- A - B - C (master)

HEADуказывает на C и индекс совпадает C,

Когда мы бежим git reset --soft B, master (и поэтому HEAD) теперь указывает на B, но индекс по-прежнему имеет изменения от C; git status покажет их как постановочные. Так что, если мы бежим git commit в этот момент мы получим новый коммит с теми же изменениями, что и C,


Итак, начиная с этого снова:

- A - B - C (master)

Теперь давайте git reset --mixed B, (Заметка: --mixed опция по умолчанию). Снова, master а также HEAD указывают на B, но на этот раз индекс также изменяется, чтобы соответствовать B, Если мы бежим git commit на данный момент ничего не произойдет, так как индекс соответствует HEAD, У нас все еще есть изменения в рабочем каталоге, но так как они не в индексе, git status показывает их как неподготовленные. Чтобы совершить их, вы бы git add а затем совершить как обычно.


И наконец, --hard такой же как --mixed (это меняет ваш HEAD и индекс), кроме этого --hard также изменяет ваш рабочий каталог. Если мы в C и беги git reset --hard Bзатем изменения добавляются в C, а также любые незафиксированные изменения, которые у вас есть, будут удалены, и файлы в вашей рабочей копии будут соответствовать фиксации B, Так как вы можете навсегда потерять изменения таким образом, вы всегда должны запускать git status перед выполнением полной перезагрузки, чтобы убедиться, что ваш рабочий каталог чист, или что вы в порядке с потерей незафиксированных изменений.


И, наконец, визуализация:

Проще говоря:

  • --soft: незафиксированные изменения, изменения оставляются поэтапными (индекс).
  • --mixed (по умолчанию): uncommit + unstage изменения, изменения остаются в рабочем дереве.
  • --hard: uncommit + unstage + удалить изменения, ничего не осталось.

Три типа сожаления

Многие из существующих ответов, похоже, не отвечают на настоящий вопрос. Они касаются того, что делают команды, а не того, что вы (пользователь) хотите, - варианта использования. Но это то, о чем спрашивает ОП!

Было бы более полезно изложить описание в терминах того, о чем вы сожалеете в то время, когдаgit resetкоманда. Допустим, у нас есть это:

A - B - C - D <- HEAD

Вот некоторые возможные сожаления и что с ними делать:

1. Я сожалею, что B, C и D не являются одним коммитом.

git reset --soft A. Теперь я могу немедленно выполнить фиксацию и готово, все изменения с момента A являются одной фиксацией.

2. Я сожалею, что B, C и D - это не десять коммитов.

git reset --mixed A. Коммиты исчезли, и индекс вернулся в A, но рабочая область по-прежнему выглядит так же, как и после D. Итак, теперь я могу добавлять и фиксировать в совершенно другой группе.

3. Я сожалею, что на этой ветке произошли B, C и D; Мне жаль, что я не разветвился после A, и они произошли в той другой ветви.

Сделайте новую ветку otherbranch, а потом git reset --hard A. Текущая ветвь теперь заканчивается на A сotherbranch вытекающие из этого.

(Конечно, вы также можете использовать полный сброс, потому что хотите, чтобы B, C и D никогда не происходили.)

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

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


Для тех, кто использует Терминал с включенным цветом (git config --global color.ui auto):

git reset --soft A и вы увидите вещи B и C в зеленом цвете (поставленные и готовые к фиксации)

git reset --mixed A (или же git reset A) и вы увидите вещи B и C в красном (не подготовленные и готовые к постановке (зеленые), а затем зафиксированные)

git reset --hard A и вы больше нигде не увидите изменений B и C (как если бы они никогда не существовали)


Или для тех, кто использует программу с графическим интерфейсом, как "Башня" или "SourceTree"

git reset --soft A и вы увидите вещи B и C в области 'готовые файлы', готовые к фиксации

git reset --mixed A (или же git reset A), и вы увидите вещи B и C в области "неподготовленные файлы", готовые для перемещения в промежуточную и затем зафиксированные

git reset --hard A и вы больше нигде не увидите изменений B и C (как если бы они никогда не существовали)

Все остальные ответы хороши, но я считаю, что лучше всего их понять, разбив файлы на три категории: unstaged, staged, commit:

  • --hard должно быть легко понять, он все восстанавливает
  • --mixed (по умолчанию):
    1. unstagedфайлы: не менять
    2. staged файлы: перейти в unstaged
    3. commit файлы: перейти в unstaged
  • --soft:
    1. unstagedфайлы: не менять
    2. stagedфайлы: не менять
    3. commit файлы: перейти в staged

В итоге:

  • --soft опция переместит все (кроме unstaged файлы) в staging area
  • --mixed опция переместит все в unstaged area

В этих случаях мне нравится визуал, который, я надеюсь, может объяснить это:

git reset --[hard/mixed/soft]:

Так что у каждого эффекта разные рамки

  1. Hard => WorkingDir + Index + HEAD
  2. Смешанный => Индекс + ГОЛОВА
  3. Soft => HEAD only (индекс и рабочий каталог без изменений).

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

1. Внесите некоторые изменения.

2.git добавить.

3.gc -m "Я сделал что-то"

Soft, Mixed и Hard - это способ, позволяющий отказаться от операций, которые вы делали от 3 до 1.

Софт "притворился", что никогда не видел, что ты сделал "gc -m".

Смешанный "сделал вид", чтобы никогда не видеть, что вы сделали "git add".

Жестко "притворялся", чтобы никогда не видеть, что вы сделали изменения в файле

Вот основное объяснение для пользователей TortoiseGit:

git reset --soft а также --mixed оставьте ваши файлы нетронутыми.

git reset --hard на самом деле измените ваши файлы в соответствии с коммитом, к которому вы сбросили

В TortoiseGit концепция индекса очень скрыта в графическом интерфейсе. Когда вы изменяете файл, вам не нужно запускать git add добавить изменение в промежуточную область / индекс. Когда просто имеешь дело с изменениями существующих файлов, которые не меняют имен файлов, git reset --soft а также --mixed подобные! Вы заметите разницу только в том случае, если добавите новые или переименованные файлы. В этом случае, если вы запустите git reset --mixed, вам нужно будет повторно добавить ваши файлы из списка " Не версионные файлы".

Ответ mkarasek велик, простыми словами, мы можем сказать...

  • git reset --soft: установить HEAD к предполагаемому коммиту, но сохраняйте свои изменения с момента последнего коммита
  • git reset --mixed: это так же, как git reset --soft но единственное отличие состоит в том, что он ставит ваши изменения с последних коммитов
  • git reset --hard: установите свой HEAD на коммите вы указываете и сбрасываете все ваши изменения с последних коммитов, включая не зафиксированные изменения.

Прежде чем перейти к этим трем вариантам, нужно понять 3 вещи.

1) История / ГОЛОВА

2) Стадия / индекс

3) Рабочий каталог

reset --soft: История изменена, HEAD изменен, Рабочий каталог не изменен.

reset --mixed: история изменена, HEAD изменена, рабочая директория изменена с неподготовленными данными.

reset --hard: История изменена, HEAD изменен, Рабочий каталог изменен с потерянными данными.

С Git --soft всегда безопасно. Нужно использовать другой вариант в сложном требовании.

Здесь есть несколько ответов с неправильным представлением о git reset --soft, Пока есть конкретное условие, при котором git reset --soft будет только меняться HEAD (начиная с отсоединенного состояния головы), как правило (и для предполагаемого использования), он перемещает ссылку ветвления, которую вы в настоящее время извлекли. Конечно, это не может быть сделано, если у вас нет проверенной ветки (отсюда определенное условие, где git reset --soft будет только меняться HEAD).

Я считаю, что это лучший способ думать о git reset, Вы не просто двигаетесь HEAD ( все это делает), вы также перемещаете ветку ref, например, master, Это похоже на то, что происходит при запуске git commit (текущая ветвь движется вместе с HEAD), за исключением того, что вместо создания (и перехода к) новой фиксации вы переходите к предыдущей фиксации.

Это точка reset , изменяя ветку на что-то отличное от нового коммита, не меняя HEAD , Вы можете увидеть это в примере документации:

Отменить коммит, сделав его веткой тем

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

Какой смысл в этой серии команд? Вы хотите переместить ветку, здесь master так что пока у вас есть master проверил, ты бежишь git reset,

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

Измени свою ветку

git reset --soft <ref>: сбрасывает указатель ветки для текущей извлеченной ветки в фиксацию по указанной ссылке,. Файлы в вашем рабочем каталоге и индексе не изменены. Принятие обязательств с этого этапа вернет вас туда, где вы были до git reset команда.

Измените свой индекс тоже

git reset --mixed <ref>

или эквивалентно

git reset <ref>:

Делает то, что --soft делает AND также сбрасывает индекс в соответствии с фиксацией по указанной ссылке. В то время как git reset --soft HEAD ничего не делает (потому что говорит переместить извлеченную ветку в извлеченную ветку), git reset --mixed HEAD или эквивалентно git reset HEAD, это обычная и полезная команда, потому что она сбрасывает индекс до состояния вашего последнего коммита.

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

git reset --hard <ref>: делает то, что --mixed делает И также перезаписывает ваш рабочий каталог. Эта команда похожа на git checkout <ref>, кроме этого (и это ключевой момент reset) все формы git reset переместить ветку ref HEAD указывает на.

Примечание о "такая-то команда перемещает ГОЛОВУ":

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

--mixed vs --soft vs --hard:

--mixed:

   Delete changes from the local repository and staging area.

   It won't touch the working directory.

   Possible to revert back changes by using the following commands.

     - git add

     - git commit

   Working tree won't be clean.

--soft:

    Deleted changes only from the local repository.

    It won't touch the staging area and working directory.

    Possible to revert back changes by using the following command.

     - git commit.

    Working tree won't be clean

--hard:

    Deleted changes from everywhere.

    Not possible to revert changes.

    The working tree will be clean.

ПРИМЕЧАНИЕ. Если коммиты подтверждены в локальном репозитории, и для отмены этих коммитов мы можем использовать:

 `git reset command`.

Но если коммиты подтверждены в удаленном репозитории, тогда не рекомендуется использовать команду сброса, и мы должны использовать revert command чтобы отменить удаленные коммиты.

--soft: Говорит Git сбросить HEAD для другого коммита, так что индекс и рабочий каталог не будут изменены каким-либо образом. Все файлы, измененные между оригинальным HEAD и коммитом, будут размещены.

--mixed: Как и софт, это сбросит HEAD к другому коммиту. Он также сбросит индекс, чтобы он соответствовал ему, в то время как рабочий каталог не будет затронут. Все изменения останутся в рабочем каталоге и появятся как измененные, но не подготовленные.

--hard: Это сбрасывает все - он сбрасывает HEAD обратно в другой коммит, сбрасывает индекс, чтобы соответствовать ему, и сбрасывает рабочий каталог, чтобы соответствовать ему.

Основное различие между --mixed а также --soft является ли ваш индекс также изменен. Проверьте больше об этом здесь.

Основное различие между различными опциями команды git reset приведено ниже.

  • --soft: Сбрасывает только HEAD в выбранный вами коммит. Работает в основном так же, как git checkout, но не создает отдельное состояние головы.
  • --mixed (опция по умолчанию): сбрасывает заголовок в коммит, выбранный вами в истории, и отменяет изменения в индексе.
  • --hard: сбрасывает заголовок в коммит, выбранный вами в истории, отменяет изменения в индексе и отменяет изменения в вашем рабочем каталоге.
  • Все виды сброса меняют HEAD в репо. Кроме того...
  • git reset --soft <B>перемещает изменения из коммитов, удаленных из репо, в индекс, сливая все, что там уже было.
  • git reset --hard <b>теряет изменения в рабочем дереве и индексе.
    Это единственный, кто меняет рабочее дерево.

Краткий ответ, в каком контексте используются 3 варианта:

Чтобы сохранить текущие изменения в коде, но переписать историю коммитов:

  • soft: Вы можете зафиксировать все сразу и создать новый коммит с новым описанием (если вы используете torotise git или любой другой графический интерфейс, это тот, который нужно использовать, так как вы можете пометить, какие файлы вы хотите в коммите и сделать несколько коммитит таким образом с разными файлами. В Sourcetree все файлы будут помещаться для коммита.)
  • mixed: Вам придется снова добавить отдельные файлы в индекс, прежде чем вы совершите фиксацию (в Sourcetree все измененные файлы будут без изменений)

Чтобы фактически потерять ваши изменения в коде:

  • hard: вы не просто переписываете историю, но и теряете все изменения до момента сброса

Мо Али выразился проще, и вот еще одно простое объяснение:

: сбросить указатель HEAD на предыдущую фиксацию

: --soft+ удалить addред изменения

--hard: --mixed+ восстановить изменения в файле рабочего дерева (ОСТОРОЖНО!)

Я не эксперт по git и просто пришел на этот форум, чтобы понять это! Таким образом, возможно, мое объяснение не идеально, извините за это. Я нашел все остальные ответы полезными, и я просто попытаюсь дать другую точку зрения. Я немного изменю вопрос, так как я предполагаю, что это, возможно, было намерением автора: " Я новичок в git. Перед использованием git я переименовал свои файлы следующим образом: main.c, main_1.c, main_2.c, когда я вносил основные изменения, чтобы иметь возможность вернуться в случае проблем. Таким образом, если я решил вернуться к main_1.c, это было легко, и я также оставил main_2.c и main_3.c, поскольку они мне могли понадобиться позже. Как я могу легко сделать то же самое с помощью git?"В своем ответе я в основном использую" сожаление номер три "из замечательного ответа Мэтта выше, потому что я также думаю, что первоначальный вопрос заключается в том," что мне делать, если я сожалею об использовании git? ". Вначале ситуация такая:

ABCD (мастер)

  1. Первый важный момент - создать новую ветку: git branch mynewbranch. Тогда получается:

ABCD (главная и моя новая ветвь)

  1. Предположим теперь, что кто-то хочет вернуться к A (3 коммита до этого). Второй важный момент - использовать команду git reset --hard, даже если в сети можно прочитать, что это опасно. Да, это опасно, но только для незафиксированных изменений. Таким образом, способ сделать это:

Git reset - жесткий номер сообщения

или же

Git reset --hard master ~ 3

Тогда получаем: A (master) -B-C-D (mynewbranch).

Затем можно продолжить работу и выполнить фиксацию из A (master), но все же можно получить легкий доступ к другим версиям, проверяя в другой ветке: git checkout mynewbranch. Теперь представим, что кто-то забыл создать новую ветку перед командой git reset --hard. Утрачены ли коммиты B, C, D? Нет, но не хранятся ни в каких ветках. Чтобы найти их снова, можно использовать команду: git reflog, которая рассматривается как "команда безопасности" ("в случае проблемы сохраняйте спокойствие и используйте git reflog"). Эта команда перечислит все коммиты, даже те, которые не принадлежат ни одной ветке. Таким образом, это удобный способ найти фиксацию B, C или D.

Другие вопросы по тегам