В чем разница между 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
(по умолчанию):unstaged
файлы: не менятьstaged
файлы: перейти вunstaged
commit
файлы: перейти вunstaged
--soft
:unstaged
файлы: не менятьstaged
файлы: не менятьcommit
файлы: перейти вstaged
В итоге:
--soft
опция переместит все (кромеunstaged
файлы) вstaging area
--mixed
опция переместит все вunstaged area
В этих случаях мне нравится визуал, который, я надеюсь, может объяснить это:
git reset --[hard/mixed/soft]
:
Так что у каждого эффекта разные рамки
- Hard => WorkingDir + Index + HEAD
- Смешанный => Индекс + ГОЛОВА
- 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)
- Вы сделали некоторые коммиты, но понимаете, что они были преждевременны, чтобы быть в "основной" ветке. Вы хотите продолжить полировать их в ветке темы, поэтому создайте ветку "topic/wip" вне текущего заголовка.
- Перемотайте ветку master, чтобы избавиться от этих трех коммитов.
- Переключитесь на ветку "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 (мастер)
- Первый важный момент - создать новую ветку: git branch mynewbranch. Тогда получается:
ABCD (главная и моя новая ветвь)
- Предположим теперь, что кто-то хочет вернуться к 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.