git重置-混合,-软和-硬有什么区别?

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

我正在查看页面简单地说,“git重置”是做什么的?,但我意识到我并不真正了解git索引或暂存区域是什么,因此解释没有帮助。

此外,在那个答案中,--mixed--soft的用例在我看来是一样的(当你想修复和重新启动时)。有人能再分解一下吗?我意识到--mixed可能是选项,但我想知道为什么。最后,--hard呢?

有人能给我一个工作流程示例,说明如何选择这3个选项吗?

342833 次浏览

当您修改存储库中的文件时,更改最初是未暂存的。为了提交它,您必须使用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是默认选项)。再次,masterHEAD指向B,但这次索引也被修改为匹配B。如果我们此时运行git commit,由于索引匹配HEAD,什么都不会发生。我们在工作目录中仍然有更改,但由于它们不在索引中,git status将它们显示为未分阶段。要提交它们,您需要git add,然后像往常一样提交。


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


最后是可视化:在此处输入图片描述

以下是TortoiseGit用户的基本解释:

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

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

在TortoiseGit中,该指数的概念在GUI中非常隐藏。当您修改文件时,您不必运行git add来将更改添加到暂存区域/索引中。当简单地处理对未更改文件名的现有文件的修改时,git reset --soft--mixed是相同的!只有在添加新文件或重命名文件时,您才会注意到差异。在这种情况下,如果您运行git重置-混合,您将不得不从非版本文件列表中重新添加您的文件。

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

对于想要在每个命令之后可视化其项目状态的视觉学习者可能会有所帮助:

给定:- A - B - C (master)


对于那些使用颜色打开的终端的人(git config--globalcolor.ui自动):

git reset --soft A,你会看到B和C的东西是绿色的(分阶段并准备提交)

git reset --mixed A(或git reset A),您将看到B和C的内容为红色(未暂存并准备暂存(绿色),然后提交)

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


或者对于那些使用“Tower”或“SourceTree”等GUI程序的人

git reset --soft A,您将在“分阶段文件”区域中看到B和C的内容准备提交

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

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

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

保留代码中的当前更改而是重写提交历史:

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

在代码中也实际丢失您的更改

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

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

1)历史/头部

2)阶段/指数

3)工作目录

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

重置-混合:历史记录更改,HEAD更改,工作目录更改为未暂存数据。

重置--hard:历史记录更改,HEAD更改,工作目录因数据丢失而更改。

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

用最简单的话来说:

  • #0未提交更改,更改保持阶段性(索引)。
  • #0(默认)取消提交+取消执行更改,更改留在工作树
  • #0取消提交+取消执行+删除改变,什么都没有留下。

git重置命令的各种选项之间的基本区别如下。

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

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

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

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

--mixed--soft之间的主要区别在于您的索引是否也被修改了。检查更多关于这个这里的信息。

Mkarasek的回答是伟大的,简单地说,我们可以说…

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

--soft--mixed有点相似,唯一的区别是,如果您想保留暂存区中的更改,请使用--soft,如果您不希望暂存区中的更改,请使用--mixed

在这些情况下,我喜欢一个有希望解释这一点的视觉效果:

git reset --[hard/mixed/soft]

在此处输入图片描述

所以每个都影响不同的范围:

  1. 硬=>WorkingDir+索引+HEAD
  2. 混合=>索引+头
  3. Soft=>HEAD(索引和工作目录不变)。

你不必强迫自己记住它们之间的差异。想想你实际上是如何做出承诺的。

  1. 做一些改变。

  2. git add .

  3. git commit -m "I did Something"

软、混合和硬是使你放弃从3到1的操作的方法。

  • “假装”从未见过你做过git commit
  • 混合“假装”从未见过你做过git add .
  • “假装”从未看到您进行了文件更改。

这里有许多关于git reset --soft的误解的答案。虽然有一个特定的条件,其中git reset --soft只会改变HEAD(从分离的头部状态开始),通常(并且用于预期的用途),它会移动您当前已签出的分支引用。当然,如果你没有签出分支,它就不能这样做(因此git reset --soft只会改变HEAD的特定条件)。

我发现这是考虑git reset的最佳方式。您不仅要移动HEAD所有东西都这样),还要移动分支参考,例如master。这与运行git commit时发生的情况类似(当前分支与HEAD一起移动),除了不是创建(并移动到)新的提交,而是移动到事先提交。

这是#0的重点,将分支更改为新提交以外的内容,而不是更改#1。你可以在留档示例中看到:

撤消提交,使其成为主题分支

          $ git branch topic/wip     (1)$ git reset --hard HEAD~3  (2)$ git checkout topic/wip   (3)
  1. 你已经做了一些提交,但意识到它们在“master”分支中还为时过早。你想在主题分支中继续完善它们,所以从当前HEAD创建“主题/wip”分支。
  2. 倒带master分支以摆脱这三个提交。
  3. 切换到“主题/wip”分支并继续工作。

这一系列命令的目的是什么?您想移动一个分支,这里是master,所以当您签出master时,您运行git reset

这里投票最多的答案通常是好的,但我想我会添加这个来纠正几个错误的答案。

改变你的分支

git reset --soft <ref>:将当前签出分支的分支指针重置到指定引用<ref>处的提交。您的工作目录和索引中的文件没有更改。从这个阶段提交将带您回到git reset命令之前的位置。

也改变你的索引

git reset --mixed <ref>

或等同

git reset <ref>

--soft做的事情也重置索引以匹配指定引用处的提交。虽然git reset --soft HEAD什么也不做(因为它说将签出分支移动到签出分支),但git reset --mixed HEAD或等效的git reset HEAD是一个常见且有用的命令,因为它将索引重置为上次提交的状态。

也更改您的工作目录

git reset --hard <ref>:做--mixed做的也覆盖你的工作目录。这个命令类似于git checkout <ref>,除了(这是关于reset的关键点)所有形式的#4移动分支ref#5指向。

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

说命令移动HEAD是没有用的。任何更改您在提交历史记录中的位置的命令都会移动HEAD。这就是HEAD,指向您所在位置的指针。#0是你,因此无论何时都会移动。

所有其他答案都很棒,但我发现最好通过将文件分为三类来理解它们: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

三种类型的后悔

很多现有的答案似乎并没有回答实际的问题。它们是关于命令做什么,而不是关于你(用户)想要什么——用例。但这正是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。当前分支现在以A结束,otherbranch源于它,包含B、C和D。

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

我不是git专家,只是来到这个论坛来理解它!因此,也许我的解释并不完美,对不起。我发现所有其他的答案都很有帮助,我会尝试给出另一个观点。我会稍微修改一下这个问题,因为我猜这可能是作者的意图:"我是git新手。在使用git之前,我像这样重命名我的文件:main. c,main_1. c,main_2. c当我执行主要更改时,以便能够在遇到麻烦时返回。因此,如果我决定回到main_1. c,这很容易,我还保留main_2. c和main_3. c,因为我以后也可能需要它们。我怎么能使用git轻松地做同样的事情呢?"对于我的回答,我主要使用上面Matt的伟大回答中的“遗憾之三”,因为我也认为最初的问题是关于“如果我在使用git时有遗憾怎么办?”。一开始,情况是这样的:

A-B-C-D(硕士)

  1. 第一个要点是创建一个新分支创建分支。然后得到:

A-B-C-D(master和mynew分支)

  1. 现在让我们假设一个人想要返回A(之前提交了3次)。第二个要点是使用命令git重置--hard即使可以在网上读到它是危险的。是的,它很危险,但只适用于未提交的更改。因此,方法是:

Git复位--hard thenberoftheecommitA

git重置--硬主控~3

然后得到:A(master)-B-C-D(mynew分支)

然后,可以从A(master)继续工作和提交,但仍然可以通过在另一个分支上签出来轻松访问其他版本:git检查mynew分支。现在,让我们假设一个人忘记在命令git重置之前创建一个新的分支。提交B,C,D是否丢失了?不,但是没有存储在任何分支中。要再次找到它们,可以使用命令:gitreflg,被认为是“安全命令”(“如果遇到麻烦,保持冷静并使用git reflg”)。该命令将列出所有提交,即使是不属于任何分支的提交。因此,找到提交B,C或D是一种方便的方法。

--混合vs--软vs--硬:

--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:重置HEAD指向上一次提交的指针

--mixed--soft+删除added更改

--hard--mixed+恢复工作树文件更改(小心!)

  • 所有重置类型更改存储库中的HEAD。另外…
  • git reset --soft <B>将从repo中删除的提交的更改移动到索引中,合并到已经存在的任何内容中。
  • git reset --hard <b>丢失工作树中的更改索引。
    它是唯一可以更改工作树的。

支持文本解释的图表