git reset --mixed、--soft 和 --hard 之间有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3528245/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 08:56:06  来源:igfitidea点击:

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

gitversion-control

提问by Michael Chinen

I'm looking to split a commit up and not sure which reset option to use.

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

I was looking at the page In plain English, what does "git reset" do?, but I realized I don't really understand what the git index or staging area is and thus the explanations didn't help.

我正在查看页面用简单的英语,“git reset”有什么作用?,但我意识到我并不真正理解 git 索引或暂存区是什么,因此解释没有帮助。

Also, the use cases for --mixedand --softlook the same to me in that answer (when you want to fix and recommit). Can someone break it down even more? I realize --mixedis probably the option to go with, but I want to know why. Lastly, what about --hard?

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

Can someone give me a workflow example of how selecting the 3 options would happen?

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

回答by mkarasek

When you modify a file in your repository, the change is initially unstaged. In order to commit it, you must stage it—that is, add it to the index—using git add. When you make a commit, the changes that are committed are those that have been added to the index.

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

git resetchanges, at minimum, where the current branch (HEAD) is pointing. The difference between --mixedand --softis whether or not your index is also modified. So, if we're on branch masterwith this series of commits:

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

- A - B - C (master)

HEADpoints to Cand the index matches C.

HEAD指向C并且索引匹配C

When we run git reset --soft B, master(and thus HEAD) now points to B, but the index still has the changes from C; git statuswill show them as staged. So if we run git commitat this point, we'll get a new commit with the same changes as C.

当我们运行时git reset --soft Bmaster(因此HEAD)现在指向B,但索引仍然有从C;开始的变化。git status将它们显示为已上演。因此,如果我们此时运行git commit,我们将获得与C.



Okay, so starting from here again:

好的,所以从这里重新开始:

- A - B - C (master)

Now let's do git reset --mixed B. (Note: --mixedis the default option). Once again, masterand HEADpoint to B, but this time the index is also modified to match B. If we run git commitat this point, nothing will happen since the index matches HEAD. We still have the changes in the working directory, but since they're not in the index, git statusshows them as unstaged. To commit them, you would git addand then commit as usual.

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



And finally, --hardis the same as --mixed(it changes your HEADand index), except that --hardalso modifies your working directory. If we're at Cand run git reset --hard B, then the changes added in C, as well as any uncommitted changes you have, will be removed, and the files in your working copy will match commit B. Since you can permanently lose changes this way, you should always run git statusbefore doing a hard reset to make sure your working directory is clean or that you're okay with losing your uncommitted changes.

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



And finally, a visualization: enter image description here

最后,一个可视化: 在此处输入图片说明

回答by Mo Ali

In the simplest terms:

用最简单的话来说:

  • --soft: uncommitchanges, changes are left staged (index).
  • --mixed(default): uncommit + unstagechanges, changes are left in working tree.
  • --hard: uncommit + unstage + deletechanges, nothing left.
  • --soft取消提交更改,更改被保留(index)。
  • --mixed(默认)取消提交 + 取消暂存更改,更改保留在工作树中
  • --hard:取消提交 + 取消暂存 + 删除更改,什么都不剩。

回答by timhc22

Please be aware, this is a simplified explanation intended as a first step in seeking to understand this complex functionality.

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

May be helpful for visual learners who want to visualise what their project state looks like after each of these commands:

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



For those who use Terminal with colour turned on (git config --global color.ui auto):

对于那些在颜色打开的情况下使用终端的人(git config --global color.ui auto):

git reset --soft Aand you will see B and C's stuff in green (staged and ready to commit)

git reset --soft A你会看到 B 和 C 的东西呈绿色(已上演并准备提交)

git reset --mixed A(or git reset A) and you will see B and C's stuff in red (unstaged and ready to be staged (green) and then committed)

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

git reset --hard Aand you will no longer see B and C's changes anywhere (will be as if they never existed)

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



Or for those who use a GUI program like 'Tower' or 'SourceTree'

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

git reset --soft Aand you will see B and C's stuff in the 'staged files' area ready to commit

git reset --soft A你会在“暂存文件”区域看到 B 和 C 的东西准备提交

git reset --mixed A(or git reset A) and you will see B and C's stuff in the 'unstaged files' area ready to be moved to staged and then committed

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

git reset --hard Aand you will no longer see B and C's changes anywhere (will be as if they never existed)

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

回答by Hansen W

All the other answers are great, but I find it best to understand them by breaking down files into three categories: unstaged, staged, commit:

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

  • --hardshould be easy to understand, it restores everything
  • --mixed(default):
    1. unstagedfiles: don't change
    2. stagedfiles: move to unstaged
    3. commitfiles: move to unstaged
  • --soft:
    1. unstagedfiles: don't change
    2. stagedfiles: dont' change
    3. commitfiles: move to staged
  • --hard应该很容易理解,它恢复了一切
  • --mixed(默认)
    1. unstaged文件:不要改变
    2. staged文件:移至 unstaged
    3. commit文件:移至 unstaged
  • --soft
    1. unstaged文件:不要改变
    2. staged文件:不要改变
    3. commit文件:移至 staged

In summary:

总之:

  • --softoption will move everything (except unstagedfiles) into staging area
  • --mixedoption will move everything into unstaged area
  • --soft选项会将所有内容(unstaged文件除外)移动到staging area
  • --mixed选项会将所有内容移动到 unstaged area

回答by James Lawruk

Here is a basic explanation for TortoiseGit users:

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

git reset --softand --mixedleave your files untouched.

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

git reset --hardactually change your filesto match the commit you reset to.

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

In TortoiseGit, The concept of the indexis very hidden by the GUI. When you modify a file, you don't have to run git addto add the change to the staging area/index. When simply dealing with modifications to existing files that are not changing file names, git reset --softand --mixedare the same! You will only notice a difference if you added new files or renamed files. In this case, if you run git reset --mixed, you will have to re-add your file(s) from the Not Versioned Fileslist.

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

回答by Tomer Ben David

In these cases I like a visual that can hopefully explain this:

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

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

git reset --[hard/mixed/soft]

enter image description here

在此处输入图片说明

So each effect different scopes

所以每个效果不同的范围

  1. Hard => WorkingDir + Index + HEAD
  2. Mixed => Index + HEAD
  3. Soft => HEAD only (index and working dir unchanged).
  1. 硬 => WorkingDir + 索引 + HEAD
  2. 混合 => 索引 + HEAD
  3. Soft => HEAD only(索引和工作目录不变)。

回答by matt

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!

许多现有答案似乎并没有回答实际问题。它们是关于命令的作用,而不是关于你(用户)想要什么——用例。但这就是OP所问的!

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

根据您在下达命令时后悔的事情来进行描述可能会更有帮助git reset。假设我们有这个:

A - B - C - D <- HEAD

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

以下是一些可能的遗憾以及如何处理它们:

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

1. 我很遗憾 B、C 和 D 不是一个提交。

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

git reset --soft A. 我现在可以立即提交并快速提交,自 A 以来的所有更改都是一次提交。

2. I regret that B, C, and D are not tencommits.

2. 我很遗憾 B、C 和 D 不是十次提交。

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.

git reset --mixed A. 提交消失了,索引又回到了 A,但工作区看起来仍然和 D 之后一样。所以现在我可以在一个完全不同的分组中添加和提交。

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.

3. 我很遗憾 B、C、D 发生在这个分支上;我希望我在 A 之后分支并且它们发生在另一个分支上。

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

创建一个新分支otherbranch,然后git reset --hard A. 当前分支现在以 A 结束,并otherbranch源于它。

(Of course you could also use a hard reset because you wish B, C, and D had never happened at all.)

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

回答by qinmu2127

You don't have to force yourself to remember differences between them. Think of how you actually made a commit.

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

1.Make some changes.

1.做一些改变。

2.git add .

2.git 添加。

3.gc -m "I did Something"

3.gc -m "我做了某事"

Soft, Mixed and Hard is the way enabling you to give up the operations you did from 3 to 1.

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

Soft "pretended" to never see you have did "gc -m".

软“假装”从来没有看到你做过“gc -m”。

Mixed "pretended" to never see you have did "git add ."

混合“假装”从来没有看到你做过“git add”。

Hard "pretended" to never see you have made file changes.

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

回答by Suresh Sharma

Before going into these three option one must understand 3 things.

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

1) History/HEAD

1) 历史/头部

2) Stage/index

2) 阶段/索引

3) Working directory

3) 工作目录

reset --soft : History changed, HEAD changed, Working directory is not changed.

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

reset --mixed : History changed, HEAD changed, Working directory changed with unstaged data.

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

reset --hard : History changed, HEAD changed, Working directory is changed with lost data.

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

It is always safe to go with Git --soft. One should use other option in complex requirement.

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

回答by De Novo

There are a number of answers here with a misconception about git reset --soft. While there is a specific condition in which git reset --softwill only change HEAD(starting from a detached head state), typically (and for the intended use), it moves the branch reference you currently have checked out.Of course it can't do this if you don't have a branch checked out (hence the specific condition where git reset --softwill only change HEAD).

这里有许多答案对git reset --soft. 虽然有一个特定的条件git reset --soft只会改变HEAD(从分离的头部状态开始),通常(和预期用途),它会移动您当前已检出的分支引用。当然,如果您没有检出分支,则无法执行此操作(因此特定条件 wheregit reset --soft只会更改HEAD)。

I've found this to be the best way to think about git reset. You're not just moving HEAD(everything does that), you're also moving the branch ref, e.g., master. This is similar to what happens when you run git commit(the current branch moves along with HEAD), except instead of creating (and moving to) a newcommit, you move to a priorcommit.

我发现这是思考git reset. 你不只是在移动HEAD一切都这样做),你也在移动分支 ref,例如,master。这与运行时发生的情况类似git commit(当前分支与 一起移动HEAD),除了不是创建(并移动到)提交,而是移动到先前的提交。

This is the point of reset, changing a branchto something other than a new commit, not changing HEAD.You can see this in the documentation example:

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

Undo a commit, making it a topic branch

          $ git branch topic/wip     (1)
          $ git reset --hard HEAD~3  (2)
          $ git checkout topic/wip   (3)
  1. 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.
  2. Rewind the master branch to get rid of those three commits.
  3. Switch to "topic/wip" branch and keep working.

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

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

What's the point of this series of commands? You want to move a branch, here master, so while you have masterchecked out, you run git reset.

这一系列命令的意义何在?您想在此处移动一个分支master因此在您master签出时,您运行git reset.

The top voted answer here is generally good, but I thought I'd add this to correct the several answers with misconceptions.

这里投票最高的答案通常很好,但我想我会添加这个来纠正几个有误解的答案。

Change your branch

改变你的分支

git reset --soft <ref>: resets the branch pointer for the currently checked out branch to the commit at the specified reference, <ref>. Files in your working directory and index are not changed. Committing from this stage will take you right back to where you were before the git resetcommand.

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

Change your index too

也改变你的索引

git reset --mixed <ref>

git reset --mixed <ref>

or equivalently

或等效地

git reset <ref>:

git reset <ref>

Does what --softdoes ANDalso resets the index to the match the commit at the specified reference. While git reset --soft HEADdoes nothing (because it says move the checked out branch to the checked out branch), git reset --mixed HEAD, or equivalently git reset HEAD, is a common and useful command because it resets the index to the state of your last commit.

做什么--softAND也是该指数将匹配提交在规定的基准复位。虽然git reset --soft HEAD什么都不做(因为它说将检出分支移动到检出分支)git reset --mixed HEAD,或等效地git reset HEAD,是一个常见且有用的命令,因为它将索引重置为您上次提交的状态。

Change your working directory too

也更改您的工作目录

git reset --hard <ref>: does what --mixeddoes ANDalso overwrites your working directory. This command is similar to git checkout <ref>, except that (and this is the crucial point about reset) all forms of git resetmove the branch ref HEADis pointing to.

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

A note about "such and such command moves the HEAD":

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

It is not useful to say a command moves the HEAD. Any command that changes where you are in your commit history moves the HEAD. That's what the HEADis, a pointer to wherever you are. HEADis you, and so will move whenever you do.

说命令移动HEAD. 任何更改您在提交历史记录中的位置的命令都会移动HEAD. 这就是HEADis,指向您所在位置的指针。HEAD是你,所以你会移动。