我试图从本地存储库中删除更改。我认为git reset --hard HEAD
对此负责,但它不起作用。只有git checkout -- .
有帮助。他们之间有什么区别?
答案 0 :(得分:1)
git checkout -- .
告诉Git进入当前索引内容,并且对于索引中的每个文件,只要该文件位于当前目录或其下方,就将该文件的该版本复制到工作树中。 (如果您位于存储库的顶部,则这是索引中的每个文件。)
git reset --hard HEAD
告诉Git进入当前(HEAD
)提交,将该提交中的每个文件复制到索引,并且从提交到 - 索引,也将文件复制到工作树。 1 在许多情况下,甚至大多数情况下,这都会做同样的事情。在某些情况下,它不会:它取决于当前索引内容与HEAD
提交内容的匹配程度。
让我们举个例子。例如,假设您首先检查了名为branch
的某个分支的提示提交:
$ git clone -b branch ssh://git@github.com/path/to/some/repo.git
[the usual clone output happens here]
$ cd repo
然后你修改了一个文件(已经存在),和在结果上运行git add
:
$ echo all-new-contents > README.md
$ git add README.md
然后你修改了第二个文件(也已经存在),但没有在结果上运行git add
:
$ echo also all new > COPYING
此时的状态是README.md
已修改且新版本在索引中,file.txt
已修改,但索引中的更改不:
$ git status --short
M COPYING
M README.md
注意两个M
的位置。
使用git checkout -- .
,我们将从索引复制到工作树。这将撤消我们对COPYING
所做的更改,因为索引版本与HEAD
版本匹配,但它不会撤消我们对README.md
所做的更改,因为索引版本与工作树版本:
$ git checkout -- .
$ git status --short
M README.md
如果我们现在使用git reset --hard HEAD
,那么将README.md
从提交复制到索引(以便索引现在再次匹配HEAD
)并在此过程中将文件复制到正常状态,工作树中的可编辑表单(以便工作树再次匹配索引):
$ git reset --hard HEAD
HEAD is now at 36438dc19 Git 2.16-rc1
$ git status -s
$
请注意,这与您描述的效果相反:git reset --hard
使得事物与提交相匹配(正如人们所期望的那样),而git checkout -- .
没有(因为人们也应该期待,现在知道了)关于Git的索引 2 )的一切。
1 在索引重置步骤之前git reset
执行了的第一步,但由于参数为HEAD
,第一步没有效果,所以我从这个描述中省略了它。
2 好吧,至少,现在应该意识到人们不能忽略索引的存在。 :-)说真的,这里有很多东西需要知道,而且你经常可以忽略的一些,但记住索引不仅存在,而且你必须 知道才能使用Git。
答案 1 :(得分:0)
为了确切地说明两个命令为什么/如何以不同方式应用于您的更改,我们需要更多信息。 (我曾经见过的每一个问题都说“我认为这会有效,但它没有”会通过显示相关的输入和输出而大大改善。在这种情况下,git status
在每个命令之前和之后显示的是什么?)
但是,这些命令有何不同?
当你说git reset --hard HEAD
你告诉git你想要将当前签出的分支移动到当前签出的提交(什么都不做),然后你想要更新索引和工作树反映该提交(丢弃对跟踪文件的任何更新的更改)。虽然没有更改新的未跟踪文件,但应该清除任何其他更改 - 当我测试它时,就会发生这种情况。
当您说git checkout -- .
时,您要通过从索引复制.
(或.
递归的子目录)下的每个文件来更新工作树。这将撤消对所有跟踪文件的未分级更改,但仍不会触及未跟踪的文件。如果有任何内容,则会比您指定的reset
命令撤消更少的更改,因为它不会从提交历史记录更新索引。我的测试再次同意这种记录的行为。
正如我所说,如果没有更多信息,我无法推测为什么你的观察会有所不同。但这就是命令之间的区别。