git reset --mixed、--soft 和 --hard 有啥区别?
Posted
技术标签:
【中文标题】git reset --mixed、--soft 和 --hard 有啥区别?【英文标题】:What's the difference between git reset --mixed, --soft, and --hard?git reset --mixed、--soft 和 --hard 有什么区别? 【发布时间】:2011-04-01 11:47:37 【问题描述】:我希望拆分提交,但不确定要使用哪个重置选项。
我正在查看页面 In plain English, what does "git reset" do?,但我意识到我并不真正了解 git 索引或暂存区域是什么,因此解释没有帮助。
此外,--mixed
和 --soft
的用例在我看来是相同的答案(当您想要修复并重新提交时)。有人可以进一步分解吗?我意识到--mixed
可能是选择,但我想知道为什么。最后,--hard
呢?
谁能给我一个工作流程示例,说明如何选择这 3 个选项?
【问题讨论】:
我会去编辑我对另一个问题的回答,试着让它更清楚一点。 @mkarasek 的回答非常好,但也有人有兴趣看看this question。 自我注意:一般而言,soft: stage everything
,mixed: unstage everything
,hard: ignore everything
直到我要重置的提交。
另见Bob Kern's additional comments about this
David Zych
的另一篇好文章,解释清楚 - davidzych.com/difference-between-git-reset-soft-mixed-and-hard
【参考方案1】:
莫阿里用最简单的话说,这里还有一个简单的解释:
--soft
: 重置 HEAD 指向上一次提交的指针
--mixed
:--soft
+ 删除 add
ed 更改
--hard
: --mixed
+ 恢复工作树文件更改(小心!)
【讨论】:
【参考方案2】:在这些情况下,我喜欢可以解释这一点的视觉效果:
git reset --[hard/mixed/soft]
:
所以每一个都会影响不同的作用域:
-
Hard => WorkingDir + Index + HEAD
混合 => 索引 + HEAD
Soft => 仅 HEAD(索引和工作目录不变)。
【讨论】:
【参考方案3】:三种遗憾
许多现有答案似乎无法回答实际问题。它们是关于命令的作用,而不是关于你(用户)想要什么——用例。但这就是OP所问的!
在您发出git reset
命令时,根据您后悔 的确切内容来描述描述可能会更有帮助。假设我们有这个:
A - B - C - D <- HEAD
以下是一些可能的遗憾以及如何处理:
1。我很遗憾 B、C 和 D 不是一个提交。
git reset --soft A
。我现在可以立即提交并预存,自 A 以来的所有更改都是一次提交。
2。我很遗憾 B、C 和 D 不是 两个 提交(或 10 个提交,或其他)。
git reset --mixed A
。提交消失了,索引又回到了 A,但工作区看起来仍然像在 D 之后一样。所以现在我可以在一个完全不同的分组中添加和提交。
3。我很遗憾 B、C 和 D 发生在这个分支上;我希望我在 A 之后分支,它们发生在另一个分支上。
创建一个新分支otherbranch
,然后git reset --hard A
。当前分支现在以 A 结束,otherbranch
源自它。
(当然您也可以使用硬重置,因为您希望 B、C 和 D 从未发生过。)
【讨论】:
也许后悔类型 2 的替代措辞可能是,“我很遗憾 B、C 和 D 不是 两个 提交,或者 十承诺。” (或者可能是“两个或多个提交”。)只是为了强调这样一个事实,即 soft 用于 1 次提交,而 mixed 用于超过 1 次。 @TTT 当然,如果这更清楚,我就把它扔进去。 在遗憾 3 中,您可以使用软重置而不是硬重置,对吗?签出新分支时,索引和工作目录都将匹配提交 D。如果我错了,请纠正我。顺便说一句,如果我们进行混合重置,那么在签出新分支后,我们必须将工作目录添加到索引中,然后索引和工作目录都会匹配提交 D。对吗? @PedroMachado 我完全不这么看,抱歉。【参考方案4】:--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`.
但是如果确认提交到远程存储库,那么不建议使用重置命令,我们必须使用revert command
来丢弃远程提交。
【讨论】:
您可以通过git reflog
恢复git reset --hard
【参考方案5】:
我不是 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(主)
-
第一个要点是新建一个分支:git branch mynewbranch。然后得到:
A-B-C-D(master 和 mynewbranch)
-
现在让我们假设一个人想要回到 A(之前 3 次提交)。 第二个要点是使用命令 git reset --hard 即使可以在网上看到它很危险。是的,这很危险,但仅适用于未提交的更改。因此,这样做的方法是:
Git reset --hard thenumberofthecommitA
或
Git reset --hard master~3
然后得到: A (master) – B – C – D (mynewbranch)
然后,可以继续工作并从 A(主)提交,但仍然可以通过签出另一个分支轻松访问其他版本:git checkout mynewbranch。 现在,让我们假设有人忘记在命令 git reset --hard 之前创建一个新分支。提交 B、C、D 是否丢失?不,但没有存储在任何分支中。要再次找到它们,可以使用被认为是“安全命令”的命令:git reflog(“如果遇到麻烦,请保持冷静并使用 git reflog”)。该命令将列出所有提交,即使是那些不属于任何分支的提交。因此,这是查找提交 B、C 或 D 的便捷方式。
【讨论】:
【参考方案6】:请注意,这是一个简化的解释,旨在作为寻求理解这一复杂功能的第一步。
对于希望在执行以下每个命令后可视化项目状态的视觉学习者可能会有所帮助:
给定:- A - B - C (master)
对于那些使用已打开颜色的终端的用户 (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
你会在“暂存文件”区域看到 B 和 C 的东西准备提交
git reset --mixed A
(或git reset A
),您将在“未暂存文件”区域中看到 B 和 C 的内容已准备好移至暂存文件,然后提交
git reset --hard A
并且您将不再在任何地方看到 B 和 C 的更改(就好像它们从未存在过一样)
【讨论】:
这是误导,充其量是:您的答案看起来好像git reset
只会改变git status
输出的外观。
我明白你的意思,但不同意,因为作为一个视觉学习者,看到我的项目在使用 3 个命令后的“外观”最终帮助我理解了他们在做什么!
我看到它更像是一种“傻瓜混蛋”的想法,可以帮助人们轻松了解实际发生的事情。你能想出如何改进它以免误导
不,我们不需要更改此答案。它提供了一个方便的“备忘单”。想一想:soft=green,mixed=red,hard=nothing(意味着消失了)!多么容易记住!对于那些甚至不明白这些颜色的真正含义的新手来说,他们对 git 的了解太少了,无论如何他们都会接受艰苦的课程,这不是@unegma 的错!顺便说一句,我只是赞成这个答案来抵消以前的反对票。干得好,@unegma!
这是一个很好的补充总结,以便在我在别处阅读它们时更好地理解内部工作原理。谢谢!【参考方案7】:
您不必强迫自己记住它们之间的差异。想想你是如何实际提交的。
进行一些更改。
git add .
git commit -m "I did Something"
软、混合和硬是让您放弃从 3 到 1 进行的操作的方式。
软“假装”从未见过你做过git commit
。
混合“假装”从未见过你做过git add .
很难“假装”从未看到您已更改文件。
【讨论】:
【参考方案8】:这里有许多对git reset --soft
有误解的答案。虽然在特定条件下git reset --soft
只会更改HEAD
(从分离的头部状态开始),但通常(并用于预期用途),它会移动您当前已签出的分支引用。 当然,如果您没有签出分支,则无法执行此操作(因此git reset --soft
的特定条件只会更改HEAD
)。
我发现这是思考git reset
的最佳方式。您不仅在移动 HEAD
(everything does that),还在移动 branch ref,例如 master
。这类似于运行 git commit
时发生的情况(当前分支与 HEAD
一起移动),除了创建(并移动到)new 提交,而是移动到 之前的提交。
这是 reset
的重点,将 branch 更改为新提交以外的内容,而不是更改 HEAD
。 您可以在文档中看到这一点示例:
撤消提交,使其成为主题分支
$ git branch topic/wip (1) $ git reset --hard HEAD~3 (2) $ git checkout topic/wip (3)
您已经进行了一些提交,但意识到将它们置于“master”分支还为时过早。您想在主题分支中继续完善它们,因此从当前 HEAD 创建“主题/wip”分支。 倒回 master 分支以摆脱这三个提交。 切换到“topic/wip”分支并继续工作。
这一系列命令的意义何在?你想移动一个分支,这里是master
,所以当你签出master
时,你运行git reset
。
这里投票最多的答案通常很好,但我想我会添加这个以纠正有误解的几个答案。
改变你的分支
git reset --soft <ref>
:将当前签出分支的分支指针重置为指定引用处的提交,<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
移动分支引用HEAD
指向。
关于“某某命令移动 HEAD”的说明:
说命令移动HEAD
是没有用的。任何更改您在提交历史中的位置的命令都会移动HEAD
。这就是HEAD
是,一个指向你所在位置的指针。 HEAD
is you,所以无论何时你都会移动。
【讨论】:
“移动分支参考”:好点。我必须更新***.com/a/5203843/6309。 也许将“移动分支引用 HEAD 指向”更改为“移动分支引用(离开?)从 HEAD 当前指向的位置”?我理解正确吗?【参考方案9】:所有其他答案都很棒,但我发现最好通过将文件分为三类来理解它们:unstaged
、staged
、commit
:
--hard
应该很容易理解,它恢复了一切
--mixed
(默认):
unstaged
文件:不要更改
staged
文件:移动到 unstaged
commit
文件:移动到 unstaged
--soft
:
unstaged
文件:不要更改
staged
文件:不要改变
commit
文件:移动到 staged
总结:
--soft
选项会将所有内容(unstaged
文件除外)移动到 staging area
--mixed
选项会将所有内容移动到 unstaged area
【讨论】:
【参考方案10】:用最简单的话来说:
--soft
:取消提交更改,更改处于暂存状态(index)。
--mixed
(默认):uncommit + unstage 更改,更改留在工作树中。
--hard
:uncommit + unstage + delete 改变了,什么都没有了。
【讨论】:
最佳答案,因为答案使用技术术语来提供完整的答案,也是最简洁的 当我提交了一个文件(未推送)并且我有一个新创建的未跟踪文件时,那么 git reset --hard 什么都不做?只有当我暂存未跟踪的文件时,它才会将其从我的工作目录中删除。 @Nikhil 也许你的意思是原始提交仍然存在,这是真的。但是分支已更改,因此提交不再是分支的一部分。我们同意吗? “取消提交”是否意味着“移动 HEAD”?这个答案听起来好像以前的提交被删除了,我根本不相信这种情况。另外,您可以使用 RESET 从当前 HEAD 中提取更改,这不会取消提交任何内容。 这是唯一可读的答案。这是准确的:你无法以任何有助于我日常工作的方式来改进它。 我不关心实现琐事。【参考方案11】:mkarasek 的答案很棒,简单来说我们可以说...
git reset --soft
:将 HEAD
设置为预期的提交,但保留您的更改从上次提交开始
git reset --mixed
:与 git reset --soft
相同,但唯一的区别是它取消了上次提交的更改
git reset --hard
:在您指定的提交上设置您的 HEAD
并重置您上次提交的所有更改,包括未提交的更改。
【讨论】:
【参考方案12】:--soft
:告诉 Git 将 HEAD 重置为另一个提交,因此索引和工作目录不会以任何方式改变。在原始 HEAD 和提交之间更改的所有文件都将被暂存。
--mixed
: 就像软一样,这会将 HEAD 重置为另一个提交。它还将重置索引以匹配它,而不会触及工作目录。所有更改都将保留在工作目录中并显示为已修改,但未暂存。
--hard
:这会重置所有内容 - 它将 HEAD 重置回另一个提交,重置索引以匹配它,并重置工作目录以匹配它。
--mixed
和--soft
的主要区别在于您的索引是否也被修改。查看更多有关此here 的信息。
【讨论】:
【参考方案13】:git reset 命令各个选项的基本区别如下。
--soft:仅将 HEAD 重置为您选择的提交。工作原理与 git checkout 基本相同,但不会创建分离的头部状态。 --mixed(默认选项):将 HEAD 重置为您在历史记录中选择的提交并撤消索引中的更改。 --hard:将 HEAD 重置为您在两个历史记录中选择的提交,撤消索引中的更改,并撤消工作目录中的更改。【讨论】:
【参考方案14】:在进入这三个选项之前,必须了解三件事。
1) 历史/HEAD
2) 阶段/索引
3) 工作目录
reset --soft : 历史改变,HEAD 改变,工作目录没有改变。
reset --mixed : 历史改变,HEAD 改变,工作目录改变了未暂存的数据。
reset --hard : 历史改变,HEAD 改变,工作目录改变,丢失数据。
使用 Git --soft 总是安全的。在复杂的需求中应该使用其他选项。
【讨论】:
【参考方案15】:在什么情况下使用这 3 个选项的简短回答:
保留代码中的当前更改,但要重写提交历史记录:
soft
:您可以一次提交所有内容并创建一个带有新描述的新提交(如果您使用 torotise git 或任何其他大多数 GUI,这是可以使用的,因为您仍然可以在提交中勾选您想要的文件并以这种方式使用不同的文件进行多次提交。在 Sourcetree 中,所有文件都将被暂存以进行提交。)
mixed
:在提交之前,您必须将各个文件再次添加到索引中(在 Sourcetree 中,所有更改的文件都将被取消暂存)
实际上丢失代码中的更改:
hard
: 你不仅会重写历史记录,还会丢失所有更改,直到重置为止
【讨论】:
在这种情况下我不会变得柔软和混合。如果您必须提交,那么还原了什么?您是提交还原还是重新提交更改(所以要恢复到原始状态?) 重新提交更改。不会有反向提交。【参考方案16】:当您修改存储库中的文件时,更改最初是未暂存的。为了提交它,您必须使用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
是默认选项)。再次,master
和 HEAD
指向 B,但这次也修改了索引以匹配 B
。如果我们此时运行git commit
,则不会发生任何事情,因为索引匹配HEAD
。我们仍然在工作目录中有更改,但由于它们不在索引中,git status
将它们显示为未暂存。要提交它们,您可以 git add
然后像往常一样提交。
最后,--hard
与--mixed
相同(它会更改您的HEAD
和索引),除了--hard
还会修改您的工作目录。如果我们在C
并运行git reset --hard B
,那么在C
中添加的更改以及您拥有的任何未提交的更改都将被删除,并且您的工作副本中的文件将与提交B
匹配。由于这种方式可能会永久丢失更改,因此您应该始终在执行硬重置之前运行git status
,以确保您的工作目录是干净的,或者您可以接受丢失未提交的更改。
最后,一个可视化:
【讨论】:
换句话说,--soft 丢弃最后一次提交,--mix 丢弃最后一次提交并添加,--hard 丢弃最后一次提交,添加以及您对代码所做的任何更改与 git checkout HEAD 相同 @eventualEntropy 您可以使用 reflog 恢复任何 committed 更改;使用reset --hard
删除的未提交更改将永远消失。
@罗伯特都没有; --mixed
会更改您的索引,但不会更改您的工作目录,因此任何本地修改都不受影响。
可能对在终端上使用 git 的视觉人士有帮助: 1.'git reset --soft A' 你会看到 B 和 C 的东西是绿色的(分阶段) 2.'git reset --mixed A' 你会看到 B 和 C 的东西是红色的(未分级) 3.'git reset --hard A' 你不会再在任何地方看到 B 和 C 的变化(就好像它们从未存在过一样)跨度>
@user1933930 1 和 3 将为您留下- A - B - C′
,其中 C' 包含与 C 相同的更改(具有不同的时间戳和可能的提交消息)。 2 和 4 将留下- A - D
,其中 D 包含 B 和 C 的组合变化。【参考方案17】:
这里是给 TortoiseGit 用户的基本解释:
git reset --soft
和 --mixed
保持您的文件不变。
git reset --hard
实际上更改您的文件以匹配您重置到的提交。
在 TortoiseGit 中,索引的概念被 GUI 隐藏得很深。修改文件时,不必运行git add
即可将更改添加到暂存区/索引。当简单地处理对不改变文件名的现有文件的修改时,git reset --soft
和--mixed
是相同的!如果您添加新文件或重命名文件,您只会注意到差异。在这种情况下,如果您运行 git reset --mixed,您将不得不从 Not Versioned Files 列表中重新添加您的文件。
【讨论】:
这个答案非常不清楚软和混合之间的区别。甚至在陈述时不屑一顾。以下答案对此更加清楚。 ***.com/questions/2530060/… 作为同样具有相同行为的 Github Desktop 的用户,这个答案让我明白了为什么我对--mixed
和 --soft
感到困惑。以上是关于git reset --mixed、--soft 和 --hard 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章