作为Ryan commented,git 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 diffs 时,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 与 --force 等选项 - 仅那些未被忽略的未跟踪文件。
使用-X(大写X)选项,git clean 将仅删除(或一如既往地假装删除)那些被忽略的未跟踪文件。
使用-x(小写x)选项,git clean 会绕过所有“忽略”规则,这意味着所有未跟踪的文件都会自动归入未跟踪且未忽略的类别。因此,git clean -f -x 将删除所有未跟踪的文件,即使是那些通常被忽略的文件。
使用-d,git clean 也将删除目录。根据定义,目录永远不会被跟踪,3 所以所有目录实际上都是未被跟踪的——但它们是未被跟踪的目录,而不是未被跟踪的文件。但是,Git 对只包含未跟踪文件(或完全为空)的子目录使用特殊的快捷方式处理:Git 不会枚举该目录中的每个(未跟踪的)文件 in,而是仅考虑这一点一个“未跟踪的目录”。4git 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/subfile 和sub:
$ git clean -df
Removing sub/
(根据 POSIX 的要求,删除整个目录意味着首先删除其所有内容。)
将路径名参数添加到git clean 会将其清理限制为给定的路径名,这非常简单。
请注意,对于未被忽略但包含另一个 Git 存储库(无论是作为常规存储库,还是作为当前存储库的子模块)的目录,还有另一个特殊的极端情况:git clean -df 或 git clean -dfx 不会删除此子存储库,但 git clean -dff 或 git clean -dffx 将。
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 索引中找到。)
4Git 秘密地确实将stat 信息关于(至少一些)目录存储在索引中,作为性能黑客。其要点是,如果 Git 发现某个目录(例如 sub)只包含未跟踪的文件或(递归地)只包含未跟踪文件的目录,Git 可以将其归类为“在未来的工作树扫描中跳过” .这一点,再加上 Git 的特殊忽略规则(防止显式“取消忽略”被忽略目录中的文件),如果自上次扫描后目录本身未修改,则允许 Git 避免扫描目录以查找其他未跟踪但未忽略的文件。 (同样的想法——也就是说,如果目录本身没有被修改,就不可能有新的文件被添加到其中——甚至适用于包含被跟踪文件的目录,尽管我不记得 Git 是否使用了这个事实。)