重置 --soft 和 --mixed 的区别

4

我对GIT很新,正在努力理解git reset --softgit reset --mixed之间的区别。我知道后者会重置索引,而前者则不会,但我正在尝试理解实际差异:何时应该使用其中之一?

我阅读了这篇Stack Overflow文章,它似乎表明mixed适合在重新提交之前进行一些更改,而soft则适合立即重新提交。我正在使用SourceTree,并关闭了暂存面板,很难看出为什么会这样;我无论如何都看不到任何实际的真正区别。

我唯一看到的区别是,在软重置中重置的新添加文件会显示为已添加,但混合重置不会。但在任何一种情况下,我都可以成功地更改新添加的文件并重新提交。当然,我对现有文件所做的任何新更改都会无缝地添加到我的当前未提交更改中,准备好提交。

我必须在Source Tree中使用暂存面板才能看到任何实际差异吗,还是我只是忽略了什么?明确地说,以我现在配置的方式,我看到了未提交的更改,并在一步中进行提交。


这个有帮助吗?https://dev59.com/-3A75IYBdhLWcg3wAD7x - Ant P
我不能将这个作为答案发布,因为我不太了解SourceTree,但对于GUI用户来说可能没有区别;Git GUI工具往往不仅提供界面,而且实际上抽象出了正在发生的事情,并对您想要做什么进行了假设(GitHub客户端特别有这个问题),这是我避免使用它们的主要原因。 - Ant P
@AntP - 非常感谢。非常感谢您的评论。我怀疑这很可能是真的,但我想在这里发布以确保。为了对SourceTree公平,它确实给你使用暂存区选项,但我最终关闭了它,因为我认为在将更改添加到索引和提交它们之间多加一步没有意义。关闭暂存区后,我会看到未提交的更改,然后在一步中提交它们。 - Adam Rackis
暂存区的好处在于你可以将文件暂存到一个稳定点进行提交,继续对其进行工作,然后再实际提交之前检查一下,“****,我搞砸了”,重新检出并保留已暂存的更改——它为你提供了灵活性,可以挑选和选择要提交的内容,而不必强制反映当前工作副本中的内容,也不必在以后更改主意时只提交然后撤销(留下可能损坏或不完整的修订)。 - Ant P
显示剩余2条评论
2个回答

7

首先,阅读@Ant P上方建议的链接。

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

让我补充一下正在进行的模型的一点内容。

'git reset'使用三个不同的东西。

  1. HEAD引用。这表示参考点。这有几个用途,但也许最相关的是这将是您下一个提交的父级(假设您不再次更改它)。
  2. 您的工作树。
  3. 索引。(SourceTree中的“暂存”窗格)。这是git用来构建下一个提交的方式。它实际上不是直接从您的工作树创建提交的。这就是为什么您需要执行'git add'的原因。

因此,如果您使用两个文件foo.txt和bar.txt创建了git repo。

在第一个修订版中,将'v1'放入每个文件中。 在第二个修订版中,将'v2'放入每个文件中。 现在,在每个文件中放入'v3',并执行'git add foo.txt'。

此时,您改变主意,决定重置到第一个版本。您想要结束在什么状态下?

  • 'git reset --hard HEAD^':重置所有内容。您的树回到了第一个版本,没有任何更改排队到索引中。
  • 'git reset --soft HEAD^':只重置HEAD指针。索引仍然具有重置之前的状态。这意味着第二次提交中的所有更改以及您已经添加的任何内容。因此,它具有您放入foo.txt中的“v3”以及您在第二次提交的第一次尝试中提交的“v2”。
  • 'git reset --mixed HEAD^':这只是重置索引,用当前修订版填充它。实际上,它正在撤消您可能进行的任何“git add”(或“git rm”)操作。

那么为什么要执行git reset --soft呢?

假设您创建了一个提交,并且决定在推送之前对其进行修正。(重要!一旦推送,您希望将提交视为永久性,否则您会为其他人造成麻烦)

你可以进行更改,然后执行'git commit --amend'。但这只适用于最后一次提交。或者你可以执行'git rebase --interactive',对特定的提交进行更改,合并提交等操作。
或者你可以执行'git reset --soft',添加、更改、删除或重置任何文件,直到达到你想要的状态,然后将其作为新提交进行提交。
'git reset --mixed'(或不带--mixed;它是默认值)仅适用于撤消'git add'或'git rm'。
总之,在我看来,你在交互式使用中可能不想使用--soft。使用它没有问题,但'git commit --amend'或'git rebase --interactive'可能更直观地实现你想要的结果。
你会经常使用'git reset --mixed'。

+1,因为这非常全面,但我不确定对于主要关注GUI环境内涵义的用户是否过于有用(并不是说理解底层模型不重要,但某些事情在一定抽象层次以上没有直接相关性)。 - Ant P
“git reset --mixed”(或者不带--mixed;这是默认设置)仅适用于撤销“git add”或“git rm”。从听起来的意思来看,像SourceTree这样的GUI工具似乎抽象出了使差异的东西,比如这个(我可以在SourceTree中进行软重置后轻松撤消添加)。 - Adam Rackis
@AdamRackis 我刚刚在我的回答中添加的关键区别是,当您在SourceTree中运行重置时,您不会任何暂存内容,因为您让SourceTree在提交时只暂存您选择的所有内容 - 如果索引中没有任何内容,则这两个标志是相同的。 - Ant P
我引用了命令行选项,因为这是最好记录的,并且对更广泛的受众有用的信息。以下是Atlassian的答案,专门针对SourceTree。https://answers.atlassian.com/questions/112557/git-amend-a-commit-do-more-than-change-the-message. - Bob Kerns

3
如果您使用的是未提交到版本库或在提交之间更改的.gitignore,则无法通过混合重置添加被忽略的文件,除非手动添加,也不会显示在git diffgit status中。
使用软重置,您重置的所有内容都将保证包含在提交中(如果您进行了提交)。
实际上,这两种方法都可能是您需要的方式,这就是为什么GIT中存在这两种方法(以及对索引本身的显式访问)。

1
我认为你的回答如果包含一个例子会更有益;现在的话,我觉得不是很清楚。 - jub0bs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接