checkout双击和硬复位有什么区别

时间:2018-01-18 15:20:59

标签: git github

我试图从本地存储库中删除更改。我认为git reset --hard HEAD对此负责,但它不起作用。只有git checkout -- .有帮助。他们之间有什么区别?

2 个答案:

答案 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命令撤消更少的更改,因为它不会从提交历史记录更新索引。我的测试再次同意这种记录的行为。

正如我所说,如果没有更多信息,我无法推测为什么你的观察会有所不同。但这就是命令之间的区别。