`git reset --hard head` 与 `git clean --force -d ` 与 `git checkout -- .` 之间的区别是什么,丢弃本地更改

Leo*_*Leo 2 git

git reset --hard headvsgit clean --force -dgit checkout -- .然后git pull丢弃本地更改并从 Git 服务器存储库获取最新版本之间有什么区别?

tor*_*rek 5

正如瑞安评论的那样git clean与其他两个非常不同(非常接近,但不完全相同)。

为了比较,在血淋淋的细节,git checkout -- .并且git reset --hard HEAD,看到我的答案是什么区别“混帐结帐- ”。和“git reset HEAD --hard”? 请密切注意索引的描述,因为它会告诉您有关下一部分的信息。

请记住,虽然你不能看到指数直接,1这是什么进入下一个承诺。因此,了解 Git使用索引而不是工作树进行提交至关重要。通常,通过将索引与HEAD提交进行比较来“查看”索引就足够了:只要索引中的文件与HEAD提交中的同一个文件完全相同,git status什么都不说;但只要文件不同,就会git status打印一些东西。

(注意:git status另外,单独将索引与工作树进行比较。如果它们不同,它会说明一些事情 -除了未跟踪但被忽略的文件。根据定义,只有工作树文件可以不被跟踪,所以毫无疑问关于索引文件是否未跟踪。总结git diff它运行的两个s 时,git status可以一次执行一个,在默认的长格式输出中,或者在输出中一次执行--short。)


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

2实际上,您需要添加--debug以获取整个内容,包括--assume-unchanged--skip-worktree标志,即使如此,Git 也会对您隐藏特殊的撤消条目。


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

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

如果文件被跟踪(在索引中),则不能忽略该文件。Git 知道这些文件,所以git clean永远不会碰它们:那不是它的工作;它的工作是删除部分或全部未跟踪的文件。只能忽略未跟踪的文件,因此未跟踪的文件要么未跟踪但未忽略,要么未跟踪且也忽略。

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

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

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

随着-dgit clean也将删除目录。根据定义,永远不会跟踪目录,3因此所有目录实际上都未被跟踪——但它们是未跟踪的目录,而不是未跟踪的文件。Git使用一种特殊的短切治疗,其中包含只是未跟踪文件的子目录(或者说完全是空的),但是:不是每一个枚举(未经跟踪)文件该目录中,git就会认为这是“未经跟踪目录”。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
Run Code Online (Sandbox Code Playgroud)

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

$ git clean -f
Removing untr
Run Code Online (Sandbox Code Playgroud)

添加-dgit clean选项使 Git 删除sub/subfilesub

$ git clean -df
Removing sub/
Run Code Online (Sandbox Code Playgroud)

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

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

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


3这真正意味着您不能向索引添加目录。 如果你足够努力,使用管道命令,你可以欺骗 Git 以正确的模式和名称存储一个条目,但在许多情况下,Git 将这个条目的模式从“目录”更改为“gitlink”,之后事情大错特错。 (Gitlink条目存在存储子模块的信息,并且在GIT中索引通常找到)。

4 GIT中偷偷确实存储stat信息有关的指数(至少一些)的目录,作为性能劈。这样做的要点是,如果 Git 发现了某个目录,例如sub只包含未跟踪的文件或(递归地)只包含未跟踪文件的目录,Git 可以将其归类为“在未来的工作树扫描中跳过”。这一点,再加上 Git 的特殊忽略规则,可以防止在被忽略的目录中显式“取消忽略”文件,如果自上次扫描以来目录本身没有被修改,则允许 Git 避免扫描目录以查找其他未跟踪但未忽略的文件。(同样的想法——也就是说,如果目录本身没有被修改,就不可能向其中添加任何新文件——甚至适用于包含跟踪文件的目录,尽管我不记得 Git 是否使用了这个事实。)