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

Mic*_*nen 691 git version-control

我希望拆分提交,不知道要使用哪个重置选项.

我在看页面你能解释一下"git reset"用简单的英语做什么吗?,但我意识到我并不真正理解git索引或临时区域是什么,因此解释没有帮助.

此答案中的用例--mixed--soft看起来一样(当你想要修复和重新发送时.)有人可以将其分解吗?我意识到--mixed可能是选择,但我想知道为什么.最后,怎么样--hard

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

mka*_*sek 1392

修改存储库中的文件时,更改最初是未分级的.为了提交它,你必须暂存 - 也就是说,将它添加到索引使用git add.进行提交时,提交的更改是已添加到索引的更改.

git reset至少改变当前branch(HEAD)指向的位置.--mixed和之间的区别在于--soft您的索引是否也被修改.所以,如果我们在master这一系列提交的分支上:

- A - B - C (master)
Run Code Online (Sandbox Code Playgroud)

HEAD指向C和索引匹配C.

当我们跑git reset --soft B,master(并因此HEAD)现在指向B,但索引仍然有变化C; git status将他们展示为上演.因此,如果我们git commit在这一点上运行,我们将获得一个具有相同更改的新提交C.


好的,所以从这里开始:

- A - B - C (master)
Run Code Online (Sandbox Code Playgroud)

现在让我们做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在执行硬重置之前运行,以确保您的工作目录是干净的,或者您可以丢失未提交的更改.


最后,一个可视化: 在此输入图像描述

  • 换句话说, - 软件丢弃最后一次提交, - mix丢弃最后一次提交并添加, - hard正在丢弃最后一次提交,添加以及您对代码所做的任何更改与git checkout HEAD相同 (16认同)
  • @eventualEntropy您可以使用reflog恢复任何_committed_更改; 使用`reset --hard`删除的未提交更改将永远消失. (9认同)
  • 如果我在“reset --mixed”之前在工作树中进行了本地修改,会发生什么情况?它会覆盖我的本地更改还是会合并它们? (3认同)
  • @罗伯特两者都不是;`--mixed` 会更改您的索引,但不会更改您的工作目录,因此任何本地修改都不受影响。 (2认同)
  • 对于在终端上使用带有颜色的git的视觉人士可能会有所帮助:1.'git reset --soft A',你会看到B和C的东西是绿色的(上演)2.'重置 - 混合A'然后你会看到红色的B和C的东西(未分级)3.'重置 - 硬A'你将不再看到B和C的任何变化(就好像它们从未存在过) (2认同)
  • 谢谢!让我检查一下我的理解。假设我正在进行这一系列的提交: - A - B - C (master) 我是否可以期望在每种​​情况下 1. 执行 `git reset --mixed B` ,然后执行 `git add` ,然后执行 `git commit`让我回到原来的状态?2.执行`git reset --mixed A`,然后执行`git add`,然后执行`git commit`会让我回到原来的情况吗?3.执行`git reset --soft B`然后执行`git commit`会让我回到原来的情况吗?4.执行`git reset --soft A`然后执行`git commit`会让我回到原来的情况吗? (2认同)
  • @ user1933930 1和3将为您留下` - A - B - C'`,其中C'包含与C相同的更改(具有不同的时间戳和可能的提交消息).2和4将为您留下` - A - D`,其中D包含B和C的组合变化. (2认同)
  • 关于第一个代码块下的“HEAD 指向 C”的小建议:“HEAD”不指向 C。它指向“master”。如果它直接指向 C,那么您将处于分离头状态,并且“git reset --soft B”不会对“master”产生任何影响。 (2认同)

小智 153

用最简单的术语来说:

  • --soft:取消提交更改,更改将保持暂存状态(索引).
  • --mixed (默认值):取消提交+ unstage更改,更改将保留在工作树中.
  • --hard:uncommit + unstage +删除更改,没有任何遗漏.

  • 最佳答案,因为该答案使用技术术语来提供最简洁的完整答案 (3认同)
  • 这是唯一可读的答案。它是准确的:你无法以任何方式改进它来帮助我的日常工作。_我不关心实施琐事。_ (3认同)
  • @Nikhil 也许你的意思是原始提交仍然存在,这是真的。但是分支已更改,因此提交不再是分支的一部分。我们同意吗? (2认同)
  • 对于初学者:答案既不错误也不正确。这意味着仅对以前的提交进行重置。但是,您可以重置为树中任何位置的任何提交。您必须了解重置_移动_ HEAD 和关联的分支_指针_ 并且实际上并不修改提交树(如“取消提交”所暗示的那样)。但是,出于效率原因,git 会在一段时间(默认 90 天)后删除无法访问的提交,即不在任何分支的历史记录中。如果你想探索的话,想一想这意味着什么......(此外 git prune 和 gc 可能会删除提交) (2认同)
  • “取消承诺”是否意味着“移动头部”?这个答案听起来好像之前的提交已被删除,但我认为根本不是这种情况。另外,您可以使用 RESET 从当前 HEAD 中提取更改,这不会取消提交任何内容。 (2认同)

tim*_*c22 68

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

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


对于那些使用打开颜色的终端的人(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的变化(就好像它们从未存在过一样)


或者对于那些使用像'Tower'或'SourceTree'这样的GUI程序的人

git reset --soft A 你会在'staged files'区域看到B和C的东西准备提交

git reset --mixed A(或git reset A)你将看到'未分级文件'区域中的B和C的东西准备移动到暂存然后提交

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

  • 不,我们不需要改变这个答案.它提供了一个方便的"备忘单".想一想:soft = green,mixed = red,hard = nothing(意味着消失)!多么容易记住!对于那些甚至不了解这些颜色真正含义的新手,他们对git知之甚少,无论如何他们都会接受艰苦的教训,这不是@unegma的错!顺便说一句,我只是赞成这个答案,以抵消之前的downvote.干得好,@unegma! (8认同)
  • 这是一个很好的补充总结,以便在我在别处阅读时更好地理解内部运作.谢谢! (5认同)
  • 我看到了你的观点,但不同意,因为作为一个视觉学习者,看到我的项目在使用3个命令后"看起来"的方式最终帮助我理解了他们在做什么! (3认同)
  • 我认为它更像是一种“傻瓜式的 git”想法,可以帮助人们轻松了解实际发生的事情。你能想到如何改进它才不会产生误导吗 (2认同)

mat*_*att 34

Three types of regret

A lot of the existing answers don't seem to answer the actual question. They are about what the commands do, not about what you (the user) want — the use case. But that is what the OP asked about!

It might be more helpful to couch the description in terms of what it is precisely that you regret at the time you give a git reset command. Let's say we have this:

A - B - C - D <- HEAD
Run Code Online (Sandbox Code Playgroud)

Here are some possible regrets and what to do about them:

1. I regret that B, C, and D are not one commit.

git reset --soft A. I can now immediately commit and presto, all the changes since A are one commit.

2. I regret that B, C, and D are not two commits (or ten commits, or whatever).

git reset --mixed A. The commits are gone and the index is back at A, but the work area still looks as it did after D. So now I can add-and-commit in a whole different grouping.

3. I regret that B, C, and D happened on this branch; I wish I had branched after A and they had happened on that other branch.

Make a new branch otherbranch, and then git reset --hard A. The current branch now ends at A, with otherbranch stemming from it.

(当然,您也可以使用硬重置,因为您希望 B、C 和 D 根本没有发生过。)

  • @elbowlobstercowstand 这实际上是我的职业生涯。 (7认同)
  • 老实说,你应该考虑从事技术教学工作。这是一种很好的方式来构建/教导大多数人在寻找这个答案时都会遇到的“我搞砸了,现在该怎么办”的场景。道具朋友。 (6认同)

Jam*_*ruk 22

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

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

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

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

  • 作为Github Desktop的用户也有相同的行为,这个答案让我清楚地知道为什么我对`--mixed`和`--soft`感到困惑. (2认同)

Tom*_*vid 18

在这些情况下,我喜欢一个可以解释这个问题的视觉效果:

git reset --[hard/mixed/soft] :

在此输入图像描述

所以每个影响范围都不同

  1. Hard => WorkingDir + Index + HEAD
  2. 混合=>索引+ HEAD
  3. Soft => HEAD only(索引和工作目录不变).


qin*_*127 17

您不必强迫自己记住它们之间的差异。想想你实际上是如何进行提交的。

  1. 做一些改变。

  2. git add .

  3. git commit -m "I did Something"

Soft、Mixed 和 Hard 是使您能够放弃从 3 到 1 所做的操作的方式。

  • “假装”从来没有看到你做过git commit
  • “假装”没见过你做过git add .
  • 很难“假装”永远不会看到您对文件进行了更改。


Viv*_*aru 16

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

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

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


Han*_*n W 14

所有其他的答案是伟大的,但我觉得最好将文件分解成三个类别,了解他们: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


小智 10

--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.
Run Code Online (Sandbox Code Playgroud)

注意:如果提交已确认到本地存储库并放弃这些提交,我们可以使用:

 `git reset command`.
Run Code Online (Sandbox Code Playgroud)

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


Sur*_*rma 8

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

1) 历史/头部

2) 阶段/索引

3) 工作目录

reset --soft :历史改变,HEAD改变,工作目录没有改变。

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

reset --hard :历史改变,HEAD改变,工作目录因丢失数据而改变。

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


De *_*ica 7

这里有许多答案对git reset --soft. 虽然有一个特定的条件git reset --soft只会改变HEAD(从分离的头部状态开始),通常(和预期用途),它会移动您当前已检出的分支引用。当然,如果您没有检出分支,则无法执行此操作(因此特定条件 wheregit 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)
Run Code Online (Sandbox Code Playgroud)
  1. 您已经进行了一些提交,但意识到它们进入“主”分支还为时过早。您想继续在主题分支中完善它们,因此从当前 HEAD 创建“主题/擦除”分支。
  2. 回滚主分支以摆脱这三个提交。
  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 is,指向您所在位置的指针。HEAD是你,所以你会移动。

  • “移动分支参考”:好点。我不得不更新 /sf/answers/364269041/。 (2认同)