关于版本控制:git reset –mixed,-soft和–hard有什么区别?

What's the difference between git reset --mixed, --soft, and --hard?

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

我当时在看页面,您能否用普通英语解释" git reset"的作用?但是我意识到我并不真正理解git索引或登台区域,因此这些解释无济于事。

另外,--mixed--soft的用例在该答案中对我来说看起来是相同的(当您要修复并重新提交时。)有人可以进一步分解它吗? 我意识到--mixed可能是可以选择的选项,但是我想知道为什么。 最后,--hard呢?

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


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

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

1
- A - B - C (master)

HEAD指向C,并且索引匹配C

当我们运行git reset --soft B时,master(因此是HEAD)现在指向B,但是索引仍然具有与C相同的更改; git status将按阶段显示它们。因此,如果此时运行git commit,我们将获得一个新提交,其更改与C相同。

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

1
- A - B - C (master)

现在开始git reset --mixed B。 (注意:--mixed是默认选项)。 masterHEAD再次指向B,但是这次也修改了索引以匹配B。如果此时运行git commit,则由于索引匹配HEAD,因此不会发生任何事情。我们仍在工作目录中进行更改,但是由于它们不在索引中,因此git status将它们显示为未暂存。要提交它们,您可以先git add然后照常提交。

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

最后是可视化效果:
enter image description here


用最简单的话来说:

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


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

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

对于那些使用启用了颜色的终端的用户
(git config --global color.ui自动):

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的更改(就好像它们不存在一样)


这是TortoiseGit用户的基本说明:

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

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

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


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

git reset --[hard/mixed/soft]

enter image description here

所以每个影响不同的范围

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

  • 所有其他答案都很不错,但我发现最好将文件分为三类来理解它们:unstagedstagedcommit

    • --hard应该易于理解,它可以还原所有内容
    • --mixed(默认):

    • unstaged文件:请勿更改
    • staged文件:移至unstaged
    • commit文件:移至unstaged
    • --soft

    • unstaged文件:请勿更改
    • staged文件:请勿更改
    • commit文件:移至staged

    综上所述:

    • --soft选项会将所有内容(unstaged文件除外)移到staging area
    • --mixed选项会将所有内容移至unstaged area


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

    1)历史/ HEAD

    2)阶段/索引

    3)工作目录

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

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

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

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


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

    1.进行一些更改。

    2.git添加

    3.gc -m"我做了什么"

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

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

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

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


    这里有许多关于git reset --soft的误解。在特定情况下,git reset --soft仅会更改HEAD(从分离的磁头状态开始),通常(并用于预期用途),它会移动您当前已签出的分支引用。当然,如果您没有签出分支,则无法执行此操作(因此,git reset --soft仅会更改HEAD的特定条件)。

    我发现这是思考git reset的最佳方法。您不仅在移动HEAD(所有操作都在做),还在移动分支引用,例如master。这与运行git commit(当前分支与HEAD一起移动)时发生的情况类似,除了移动(而不是创建(移至)新的提交,而是移至上一个提交)。

    这是reset的要点,将分支更改为新提交以外的其他内容,而不更改HEAD。您可以在文档示例中看到以下内容:

    Undo a commit, making it a topic branch

    1
    2
    3
              $ git branch topic/wip     (1)
              $ git reset --hard HEAD~3  (2)
              $ git checkout topic/wip   (3)
  • You have made some commits, but realize they were premature to be in the"master" branch. You want to continue polishing them in a topic branch, so create"topic/wip" branch off of the current HEAD.
  • Rewind the master branch to get rid of those three commits.
  • Switch to"topic/wip" branch and keep working.
  • 这一系列命令的意义是什么?您想移动一个分支,这里是master,因此当您签出master时,您将运行git reset

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

    更改您的分支

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

    也更改您的索引

    git reset --mixed

    或同等

    git reset

    --soft所做的与,并且还将索引重置为与指定参考上的提交匹配的索引。尽管git reset --soft HEAD不执行任何操作(因为它说将已检出的分支移至已检出的分支),但git reset --mixed HEAD或等效的git reset HEAD是常见且有用的命令,因为它将索引重置为上一次提交的状态。

    也更改您的工作目录

    git reset --hard :执行--mixed的操作,并且还覆盖您的工作目录。该命令类似于git checkout ,除了(这是关于reset的关键点)所有形式的git reset移动分支引用HEAD所指向。

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

    说命令移动HEAD是没有用的。任何更改提交历史记录中位置的命令都会移动HEAD。这就是HEAD的含义,它是指向您所在位置的指针。 HEAD是您,因此您每次行动都会移动。


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

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

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

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


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

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


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

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

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

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

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


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

    • git reset --soft:将HEAD设置为预期的提交,但保持更改从上一次提交开始
    • git reset --mixed:与git reset --soft相同,但唯一的不同是它取消了上一次提交的更改
    • git reset --hard:在您指定的提交上设置您的HEAD,并从上次提交中重置所有更改,包括未提交的更改。