git reset --mixed,-soft和--hard有什么区别?


740

我正在寻找一个提交,但不确定使用哪个重置选项。

我一直在用普通英语查看页面,“ git reset”有什么作用?,但是我意识到我不太了解git索引或暂存区,因此说明无济于事。

此外,用例--mixed--soft看起来是一样的我在这个问题的答案(当你想修复和重新作出)。有人可以进一步分解吗?我意识到--mixed可能是可以选择的,但是我想知道为什么。最后,那又如何--hard呢?

有人可以给我一个如何选择这三个选项的工作流程示例吗?


1
我将编辑关于其他问题的答案,以使其更加清楚。
卡斯卡贝尔

@mkarasek的回答很不错,但也有可能对这个问题感兴趣。
brandizzi 2013年

3
自我提醒:一般来说soft: stage everythingmixed: unstage everythinghard: ignore everything直至提交我从重置。
user1164937 '10 / 10/22


另一篇David Zych具有清晰解释的好文章-davidzych.com/difference-between-git-reset-soft-mixed-and-hard
src3369

Answers:


1486

当您修改存储库中的文件时,更改最初是未暂存的。为了提交它,您必须使用暂存它(即,将其添加到索引中)git add。进行提交时,提交的更改就是已添加到索引的更改。

git reset至少更改当前分支(HEAD)指向的位置。--mixed和之间的区别在于--soft您的索引是否也被修改。因此,如果我们要进行master以下一系列提交:

- A - B - C (master)

HEAD指向C和索引匹配C

当我们运行时git reset --soft Bmaster(因此HEAD)现在指向B,但索引仍具有从的变化Cgit status将显示他们上演。因此,如果我们git commit在这一点上运行,我们将获得与相同更改的新提交C


好的,所以从这里再次开始:

- A - B - C (master)

现在开始吧git reset --mixed B。(注意:--mixed是默认选项)。再一次,masterHEAD点到B,但这次的指数也被修改,以匹配B。如果我们git commit在这一点上运行,那么自从索引match以来就什么也不会发生HEAD。我们仍在工作目录中进行更改,但是由于它们不在索引中,因此将git status它们显示为未暂存。要提交它们,您将git add像往常一样提交。


最后,--hard它与--mixed(它会更改您的HEAD和索引)相同,除了它--hard还会修改您的工作目录。如果我们在C运行git reset --hard B,那么添加的更改C以及您所做的任何未提交的更改都将被删除,并且工作副本中的文件将与commit匹配B。由于您可以通过这种方式永久丢失更改,因此应该始终git status在硬重置之前运行,以确保您的工作目录是干净的,或者可以丢失未提交的更改。


最后是可视化效果: 在此处输入图片说明


43
换句话说,--soft放弃最后一次提交,--mix放弃最后一次提交和添加,--hard放弃最后一次提交,添加以及您对代码所做的与git checkout HEAD相同的任何更改
James Wang

11
@eventualEntropy您可以使用reflog 恢复所有已提交的更改。与之删除的未提交的更改将reset --hard永远消失。
mkarasek 2014年

2
@罗伯特 --mixed更改索引但不更改工作目录,因此任何本地修改均不受影响。
mkarasek

3
对于在终端上使用git并带有颜色的视觉人士可能会有所帮助:1.'git reset --soft A',您将看到B和C的内容为绿色(分阶段)2.'git reset --mixed A',您将看到B和C的内容显示为红色(未暂存)3.'git reset --hard A',您将不再在任何地方看到B和C的更改(就好像它们不存在一样)
timhc22 2014年

2
@ user1933930 1和3将使您离开- A - B - C′,其中C'包含与C相同的更改(带有不同的时间戳和可能的提交消息)。图2和4会留下- A - D,其中d含有B和C的组合的变化
mkarasek

213

用最简单的话来说:

  • --soft取消提交更改,将更改暂存(索引)。
  • --mixed (默认)取消提交+取消暂存更改,更改留在工作树中
  • --hard取消提交+取消登台+删除更改,一无所有。

8
最佳答案,因为答案使用技术术语来提供最简洁的完整答案
Trevor Boyd Smith,

1
当我提交了一个文件(未推送)并且我有一个新创建的未跟踪文件时,那么git reset --hard什么都没有?仅当我暂存未跟踪的文件时,它将文件从我的工作目录中删除。
迈克尔

1
@Nikhil您能解释这个答案在哪里错误吗?
Ned Batchelder

1
@NedBatchelder一点都不对:因为使用这些命令时,从未提交不会发生。
Nikhil

1
@Nikhil也许您的意思是原始提交仍然存在,这是事实。但是分支已更改,因此提交不再是分支的一部分。我们对此表示同意吗?
Ned Batchelder

69

请注意,这是一个简化的解释,旨在作为寻求了解此复杂功能的第一步。

对于希望通过以下每个命令来形象化其项目状态的视觉学习者可能会有所帮助:


对于那些使用启用了颜色的终端(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的更改(就好像它们从未存在过一样)


或对于使用GUI程序(例如“ Tower”或“ SourceTree”)的用户

git reset --soft A 并且您将在“暂存文件”区域中看到B和C的东西准备提交

git reset --mixed A(或git reset A),您将在“未暂存的文件”区域中看到B和C的内容准备移至暂存,然后提交

git reset --hard A 并且您将不再在任何地方看到B和C的更改(就好像它们从未存在过一样)


1
这充其量是一种误解:充其量是:您的回答似乎git reset只改变了git status输出的外观。
jub0bs 2014年

3
我明白您的意思,但不同意,因为作为视觉学习者,使用3个命令后看到我的项目“外观”最终帮助我了解了他们在做什么!
timhc22

我看到它更多是一种“傻瓜式傻瓜”的想法,可以帮助人们缓解实际情况。你能想到的如何能如此改进不被误导
timhc22

8
不,我们不需要更改此答案。它提供了一个方便的“备忘单”。考虑一下:软=绿色,混合=红色,硬=什么都没有(意味着消失)!多么容易记住!对于那些什至不了解这些颜色真正含义的新手,他们对git的了解甚少,无论如何他们都会在途中接受艰苦的课程,这不是@unegma的错!顺便说一句,我只是赞成这个答案,以抵消先前的反对。干得好,@ unegma!
RayLuo 2015年

5
这是一个很好的补充摘要,可以更好地理解我在其他地方阅读的内部工作原理。谢谢!
spex 2015年

24

所有其他的答案是伟大的,但我觉得最好将文件分解成三个类别,了解他们:unstagedstagedcommit

  • --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

22

这是TortoiseGit用户的基本说明:

git reset --soft--mixed保持文件不变。

git reset --hard实际更改文件以匹配您重置到的提交。

在TortoiseGit中,GUI完全隐藏了索引的概念。修改文件时,无需运行git add即可将更改添加到暂存区/索引。当简单地修改现有文件,这些文件不改变文件名处理,git reset --soft并且--mixed都是一样的!仅当您添加新文件或重命名文件时,您才会注意到差异。在这种情况下,如果运行git reset --mixed,则必须从“ 未版本化文件”列表中重新添加文件。


关于软和混合的区别,这个答案还不清楚。甚至不屑一顾。下面的答案对此更加清楚。stackoverflow.com/questions/2530060/…–
barlop

2
作为也具有相同行为的Github Desktop用户,此答案使我更加清楚为何对--mixed和感到困惑--soft
陈李咏

20

在这些情况下,我喜欢可以希望对此进行解释的视觉效果:

git reset --[hard/mixed/soft]

在此处输入图片说明

所以每个影响不同的范围

  1. 困难=> WorkingDir +索引+ HEAD
  2. 混合=>索引+ HEAD
  3. 软=>仅HEAD(索引和工作目录不变)。

15

三种遗憾

许多现有答案似乎都无法回答实际问题。它们与命令的作用有关,而不与您(用户)想要的用例有关。但这就是OP的要求!

最好在您下达命令时感到后悔,以这种方式进行描述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。现在,当前分支otherbranch从A终止。

(当然,您也可以使用硬重置,因为您希望B,C和D从未发生过。)


5

您不必强迫自己记住它们之间的差异。考虑一下您实际上是如何提交的。

1.进行一些更改。

2.git添加

3.gc -m“我做了什么”

软,混合和硬是您可以放弃从3到1进行的操作的方式。

软“假装”到永远不会看到您做了“ gc -m”。

混成“假装”,以至于从未见过“ git add”。

很难“假装”永远不会看到您进行了文件更改。


4

在进入这三个选项之前,必须先了解三件事。

1)历史/ HEAD

2)阶段/索引

3)工作目录

reset --soft:历史记录已更改,HEAD已更改,工作目录未更改。

reset --mixed:历史记录已更改,HEAD已更改,工作目录已更改,但未暂存数据。

reset --hard:历史记录已更改,HEAD已更改,工作目录已更改,丢失了数据。

使用Git --soft总是很安全的。一个人应该在复杂的需求中使用其他选项。


3

这里有许多关于的误解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. 您已经进行了一些提交,但是意识到它们还不成熟,不能进入“ master”分支。您要继续在主题分支中对其进行润饰,因此请在当前HEAD之外创建“ topic / wip”分支。
  2. 倒退master分支以摆脱这三个提交。
  3. 切换到“ topic / wip”分支并继续工作。

这一系列命令的意义是什么?您想在此处移动分支master因此,在master签出后,您可以运行git reset

在这里,票数最高的答案通常是好的,但我想我会添加它以纠正一些带有误解的答案。

更改您的分支

git reset --soft <ref>:将当前签出的分支的分支指针重置为指定参考处的提交<ref>。您的工作目录和索引中的文件不会更改。从此阶段提交将使您回到git reset命令之前的状态。

也更改您的索引

git reset --mixed <ref>

或同等

git reset <ref>

做什么--softAND也是该指数将匹配提交在规定的基准复位。虽然git reset --soft HEAD什么都不做(因为它说将已签出的分支移到已签出的分支),但是git reset --mixed HEAD,或者等效地git reset HEAD,这是一个常用且有用的命令,因为它会将索引重置为上一次提交的状态。

也更改您的工作目录

git reset --hard <ref>:做什么--mixedAND也覆盖你的工作目录。该命令与相似git checkout <ref>,除了(这是关键点reset分支ref 指向的所有形式的git reset移动HEAD

关于“这样的命令移动HEAD”的注释:

说一条命令移动并没有用HEAD。任何更改提交历史记录中位置的命令都会移动HEAD。这就是HEAD ,它是指向您无论身在何处的指针。HEAD是你,所以无论何时你都会移动。


2
“移动分支引用”:好点。我必须更新stackoverflow.com/a/5203843/6309
VonC

1

在什么情况下使用3个选项的简短答案:

在代码中保留当前更改,但要重写提交历史记录,请执行以下操作:

  • soft:您可以一次提交所有内容,并使用新的描述创建一个新的提交(如果使用torotise git或其他大多数GUI,则可以使用它,因为您仍然可以在提交中勾选想要的文件并进行多个用不同的文件提交这种方式。在Sourcetree中,所有文件都会被暂存以进行提交。)
  • mixed:提交提交之前,您将不得不再次将单个文件添加到索引中(在Sourcetree中,所有更改的文件都将被取消登台)

要实际上也丢失代码中的更改

  • hard:您不仅会重写历史记录,而且还会丢失所有更改,直到重置为止

在这种情况下,我不会变得柔和而混杂。如果您必须提交,那么恢复了什么?您要提交还原还是重新提交更改(以便返回到原始状态?)
John Little

重新提交更改。不会有反向提交。
Nickpick

1

git reset命令的各个选项之间的基本区别如下。

  • --soft:仅将HEAD重置为您选择的提交。基本上与git checkout相同,但不会创建分离的头部状态。
  • --mixed(默认选项):将HEAD重置为您在历史记录中选择的提交,并撤消索引中的更改。
  • --hard:将HEAD重置为您在两个历史记录中选择的提交,撤消索引中的更改,并撤消工作目录中的更改。

1

--soft:告诉Git将HEAD重置为另一个提交,因此索引和工作目录不会以任何方式改变。在原始HEAD和提交之间更改的所有文件将被暂存。

--mixed:就像软件一样,这会将HEAD重置为另一个提交。它还将重置索引以使其匹配,而不会触摸工作目录。所有更改都将保留在工作目录中,并显示为已修改但未上演。

--hard:这将重置所有内容-将HEAD重置为另一个提交,重置索引以使其匹配,并重置工作目录以使其也匹配。

--mixed和之间的主要区别--soft是您的索引是否也被修改。在这里查看更多有关此内容。


0

mkarasek的答案很棒,简单来说,我们可以说...

  • git reset --soft:将设置HEAD为预期的提交,但使更改从上一次提交开始进行
  • git reset --mixed:与相同,git reset --soft但唯一的区别是从上次提交取消更改的阶段
  • git reset --hardHEAD在您指定的提交上进行设置,并重置上一次提交中的所有更改,包括未提交的更改。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.