`git reset --hard head`与`git clean --force -d`与`git checkout - .`之间有什么区别可以放弃本地更改

时间:2017-07-19 02:06:36

标签: git

git reset --hard headgit clean --force -d vs git checkout -- .然后git pull之间有什么区别可以放弃本地更改并从Git服务器存储库中获取最新信息?

1 个答案:

答案 0 :(得分:4)

作为Ryan commentedgit clean与其他两个非常不同(非常接近,但不完全相同)。

要进行比较,请详细说明git checkout -- .git reset --hard HEAD,请参阅我对What is the difference between "git checkout -- ." and "git reset HEAD --hard"?的回答。密切关注索引的说明,因为那样告诉你下一部分。

请记住,虽然你不能直接看索引, 1 下一次提交的内容。因此,您必须了解Git使用索引提交,而不是使用工作树。通常,它足以“看到"通过将它与HEAD提交进行比较的索引:索引中的文件与HEAD提交中的同一文件完全相同,git status什么也没说;但是在文件不同的地方,git status会打印一些东西。

(注意:git status也单独将索引与工作树进行比较。如果不同,它会为未跟踪但被忽略的文件显示之外的内容。根据定义,工作树文件可以不被跟踪,因此对索引文件是否未被跟踪毫无疑问。当总结它运行的两个git diff时,git status可以在默认长格式输出中的时间,或--short输出中的所有时间。)

1 实际上,你可以看到索引:运行git ls-index --stage并且Git将溢出整个事情。 2 这实际上对调试非常有用。但是,对于包含许多文件的大型存储库,它会为每天使用打印太多git status是一个更好的工具。

2 实际上你需要添加--debug来获取整个的东西,包括--assume-unchanged--skip-worktree标志,以及即便如此,Git也会隐藏你的特殊撤消条目。

git clean仅删除(部分或全部)未跟踪的文件

在Git中,未跟踪的文件实际上非常容易定义:它是不在索引中的文件。这几乎就是它的全部内容,但是出于git clean的目的,我们还需要一个项目,即文件是否也被忽略

如果跟踪文件(在索引中),则无法忽略该文件。这些文件是Git已知的,因此git clean永远不会触及它们:那不是它的工作;它的工作是删除部分或全部未跟踪的文件。只有未跟踪的文件才能被忽略,因此未跟踪的文件要么未被跟踪,要么被忽略,或者未被跟踪,也被忽略。

默认情况下,git clean会删除或假装删除,具体取决于--dry-run vs --force等选项 - 仅限那些未被忽略的未跟踪文件。

使用-X(大写X)选项,git clean将删除(或一如既往地假装删除)仅 忽略的未跟踪文件。

使用-x(小写x)选项,git clean会绕过所有"忽略"规则,这意味着所有未跟踪的文件都会自动落入未跟踪和未被忽略的类别中。因此,git clean -f -x将删除所有未跟踪的文件,即使是那些通常被忽略的文件。

使用-dgit clean也会删除目录。根据定义,永远不会跟踪目录, 3 所以所有目录都是有效的未跟踪 - 但是它们未被跟踪的目录,而不是未跟踪的文件。 Git对一个只包含未跟踪文件(或完全为空)的子目录使用了一种特殊的快捷处理方法,但是:Git只考虑这个目录,而不是枚举该目录中的每个(未跟踪)文件。 "未跟踪的目录"。 4 git clean命令通常只留下这些:

$ mkdir tt
$ cd tt
$ git init
Initialized empty Git repository in ...
$ echo for testing git clean > README
$ git add README
$ touch untr
$ mkdir sub
$ touch sub/subfile
$ git status --short
A  README
?? sub/
?? untr

git status --short的双重问号输出表示未跟踪的文件或未跟踪的目录。由于sub是一个包含未跟踪文件的目录,因此它显示为未跟踪的目录。运行git clean -f(或git clean -n)表示Git删除(或将删除)untr,这是一个未被忽略的未跟踪文件;但是Git不会删除sub/subfile sub本身:

$ git clean -f
Removing untr

-d添加到git clean选项会使Git删除sub/subfilesub

$ git clean -df
Removing sub/

(删除整个目录意味着首先根据POSIX的要求删除所有内容。)

git clean添加路径名参数会将其清理限制为给定的路径名​​,这非常简单。

请注意,对于未被忽略但包含另一个Git存储库(无论是作为常规存储库还是作为当前存储库的子模块)的目录还有另一个特殊情况:git clean -df或{{1不会删除此子存储库,但git clean -dfxgit clean -dff

3 这实际意味着您无法将目录添加到索引中。 If you try hard enough, using the plumbing commands, you can trick Git into storing an entry with the right mode and name, but under a number of conditions, Git changes this entry's mode from "directory" to "gitlink", after which things go quite badly awry.(Gitlink条目用于存储子模块信息, 通常在Git索引中找到。)

4 Git暗中 存储git clean -dffx信息关于(至少某些)目录中的索引,作为性能黑客。这样做的要点是,如果Git发现某些目录(例如stat)只包含未跟踪文件或(递归)目录,只包含未跟踪文件,Git可以将该事物归类为"以便将来跳过工作树扫描"。这个加上Git的特殊忽略规则可以防止明确的" unignoring"忽略目录中的文件,如果自上次扫描后目录本身未被修改,则允许Git避免扫描目录以查找其他未跟踪但未被忽略的文件。 (同样的想法 - 也就是说,如果目录本身未被修改,可能没有新的文件添加到它 - 甚至适用于包含跟踪文件的目录,虽然我不记得Git使用的事实。)