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

时间:2010-08-20 04:41:20

标签: git version-control

我希望拆分提交,但不确定要使用哪个重置选项。

我正在查看页面Can you explain what "git reset" does in plain english?,但我意识到我并不真正理解git索引或临时区域是什么,因此解释没有帮助。

--mixed--soft的用例在该答案中看起来与我相同(当你想修复并重新发送时。)有人可以将其分解得更多吗?我意识到--mixed可能是可以选择的,但我想知道为什么。最后,--hard怎么办?

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

16 个答案:

答案 0 :(得分:1262)

修改存储库中的文件时,更改最初是未分阶段的。为了提交它,您必须将其暂存 - 也就是说,使用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以确保您的工作目录是干净的,或者您可以丢失未提交的更改。


最后,一个可视化: enter image description here

答案 1 :(得分:67)

请注意,这是一个简化的解释,旨在帮助您了解这一复杂功能。

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


对于使用打开颜色的终端的用户 (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程序的人来说。或者' SourceTree'

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

git reset --mixed A(或git reset A),您将在未上映的文件中看到B和C的内容'区域准备移动到上演然后提交

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

答案 2 :(得分:63)

用最简单的术语来说:

  • --soft 取消提交更改,更改将暂停( index )。
  • --mixed (默认)取消提交+非舞台更改,更改将保留在工作树中
  • --hard 取消提交+非舞台+删除更改,一无所有。

答案 3 :(得分:25)

三种遗憾

许多现有答案似乎都无法回答实际问题。它们是关于命令的功能,而不是您(用户)想要的—用例(em)。但这就是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结尾于A。

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

答案 4 :(得分:21)

以下是TortoiseGit用户的基本说明:

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

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

在TortoiseGit中,索引的概念被GUI非常隐藏。修改文件时,不必运行git add将更改添加到暂存区/索引。当简单地处理对未更改文件名的现有文件的修改时,git reset --soft--mixed是相同的!如果添加新文件或重命名文件,您只会注意到不同之处。在这种情况下,如果运行git reset --mixed,则必须从 Not Versioned Files 列表中重新添加文件。

答案 5 :(得分:10)

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

git reset --[hard/mixed/soft]

enter image description here

所以每种效果都有不同的范围

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

答案 6 :(得分:4)

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

1)历史/ HEAD

2)阶段/指数

3)工作目录

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

reset --mixed:历史记录已更改,HEAD已更改,工作目录已更改为未分期数据。

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

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

答案 7 :(得分:2)

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

1。进行一些更改。

2.git add。

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

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

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

混合“假装”,以至于您从未看到过“ git add”。

很难“假装”从未看到您进行过文件更改。

答案 8 :(得分:1)

使用3个选项的简短回答:

保留代码中的当前更改,但要重写提交历史记录:

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

要在代码中实际丢失更改

  • hard:您不必重写历史记录,但也会在重置之前丢失所有更改

答案 9 :(得分:1)

git reset命令的各种选项的基本区别如下。

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

答案 10 :(得分:1)

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

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

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

--mixed--soft之间的主要区别在于您的索引是否也被修改。详细了解here

答案 11 :(得分:1)

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

我发现这是思考git reset的最佳方法。您不仅在移动HEADeverything does that),还在移动分支引用,例如master。这类似于您运行git commit(当前分支随HEAD移动)时发生的情况,除了移动(而不是创建(移动到) new )提交之外,到先前提交。

这是reset的要点,将分支更改为新提交,而不更改HEAD在文档示例中是这样的:

  

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

          $ git branch topic/wip     (1)
          $ git reset --hard HEAD~3  (2)
          $ git checkout topic/wip   (3)
     
      
  1. 您已经进行了一些提交,但是意识到它们还不成熟,不能进入“ master”分支。您想继续在主题分支中对其进行润饰,因此在当前HEAD的旁边创建“ topic / wip”分支。
  2.   
  3. 倒回master分支以摆脱这三个提交。
  4.   
  5. 切换到“ topic / wip”分支并继续工作。
  6.   

这一系列命令的意义是什么?您想将分支移动到这里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的操作 AND ,并且还会覆盖您的工作目录。该命令类似于git checkout <ref>,除了(这是关于reset的关键点)所有形式的git reset都会移动分支ref HEAD指向

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

说命令移动HEAD是没有用的。任何更改提交历史记录中位置的命令都会移动HEAD。这就是HEAD 的内容,它是指向您身在何处的指针。 HEADis you,因此您每次操作都会移动。

答案 12 :(得分:1)

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

答案 13 :(得分:0)

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

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

答案 14 :(得分:0)

我不是git专家,只是来到了这个论坛上了解它!因此,也许我的解释并不完美,对此感到抱歉。我发现所有其他答案都很有帮助,我将尝试提出另一个观点。我会稍作修改,因为我想这可能是作者的意图:“ 我是git的新手。在使用git之前,我正在重命名我的文件:main.c,main_1.c,main_2.c,当我执行专业更改时可以在遇到麻烦时返回。因此,如果我决定返回main_1.c,那很容易,并且我还保留了main_2.c和main_3.c,因为以后也可能需要它们。我如何使用git轻松地做同样的事情?” 对于我的答案,我主要使用上面Matt的最佳答案中的“后悔数字3”,因为我还认为最初的问题是“如果在使用git时感到后悔,我该怎么办?”。一开始情况是这样的:

A-B-C-D(管理员)

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

A-B-C-D(主服务器和mynewbranch)

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

Git重置-设置commitA的数量

Git重置--hard master〜3

然后获得: A(主)– B – C – D(mynewbranch)

然后,可以继续工作并从A(主)提交,但仍然可以通过检出另一个分支 git checkout mynewbranch 来轻松访问其他版本。 现在,让我们想象一个忘记了在命令 git reset --hard 之前创建新分支的过程。提交B,C,D丢失了吗?不,但是没有存储在任何分支中。要再次找到它们,可以使用以下命令: git reflog (被视为“安全命令”)(“万一遇到麻烦,请保持冷静并使用git reflog”)。该命令将列出所有提交,甚至包括那些不属于任何分支的提交。因此,这是查找提交B,C或D的便捷方法。

答案 15 :(得分:0)

-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`.

但是,如果提交已确认到远程存储库,则不建议使用reset命令,我们必须使用revert command放弃远程提交。