M_M*_*M_M 3 git git-checkout git-reset git-clean
这不是关于' - '的一般问题,如标记的副本.这是一个特定于git的问题,要求明确所提到的命令之间的操作差异.
如果我想清除当前目录而不进行存储或提交,我通常会使用以下命令:
git reset HEAD --hard
git clean -fd
Run Code Online (Sandbox Code Playgroud)
一位同事还提到使用这个命令:
git checkout -- .
Run Code Online (Sandbox Code Playgroud)
对谷歌来说这是一个困难的命令,而且从git文档中我不清楚这个命令实际上做了什么.它似乎是手册中后面提到的用法之一.
猜测它会复制git reset HEAD --hard
,但与我已经使用的命令相比,它究竟做了什么呢?
它是复制一个还是两个命令,还是相似但略有不同?
首先,让我们解决双连字符或双短划线,以使其不受影响(特别是因为这个问题不再有明显的重复).
Git主要以POSIX批准的方式使用它(参见指南10),以指示选项参数和非选项参数之间的分界线.既然git checkout
接受分支名称,例如git checkout master
文件(路径)名称,git checkout README.txt
也可以使用--
强制Git来解释--
作为文件名后面的内容,即使它本来是有效的分支名称.也就是说,如果您同时拥有一个分支和一个名为的文件master
:
git checkout master
Run Code Online (Sandbox Code Playgroud)
将检查分支,但:
git checkout -- master
Run Code Online (Sandbox Code Playgroud)
将检出文件(令人困惑的是,从当前索引).
接下来,我们需要解决一个奇怪的问题git checkout
.从文档中可以看出,有许多"模式" git checkout
(文档列出了在synposis中的六个单独的调用!).有各种各样的咆哮(不同的质量:史蒂夫班纳特的实际上很有用,在我看来,虽然我自然不同意它100%:-))关于Git糟糕的"用户体验"模型,包括git checkout
有太多模式的事实的操作.
特别是,你可以git checkout
一个分支(切换分支),或git checkout
一个或多个文件.后者从特定提交或索引中提取文件.当Git从提交中提取文件时,它首先将它们复制到索引,然后将它们从索引复制到工作树.
这个序列有一个潜在的实现原因,但它显示的事实是一个关键元素.我们需要知道很多关于Git的指数,因为两者git checkout
并git reset
以不同的方式使用它,有时.
我认为,绘制一个三维图表或表格来说明当前 - 或 - HEAD
委托,索引和工作树是一个好主意.假设:
README.md
和file.txt
;git add
但未提交的new.txt
;rmd.txt
has git rm
-ed但未提交的文件;untr.txt
.每个实体 - HEAD
提交,索引和工作树 - 现在都拥有三个文件,但每个实体都拥有一组不同的文件.整个州的表格如下所示:
HEAD index work-tree
-------------------------------
README.md README.md README.md
file.txt file.txt file.txt
new.txt new.txt
rmd.txt
untr.txt
Run Code Online (Sandbox Code Playgroud)
除了这些之外还有更多可能的状态:实际上,对于每个文件名,有七种可能的组合"in/not-in"HEAD,index和work-tree(第八种组合"不是全部三种" ",在这种情况下,我们甚至在第一时间谈论什么文件?!).
checkout
和reset
命令这两个命令你问,git checkout
和git reset
,都能够做很多事情.然而,每个特定的调用将"完成的事情"减少到两个中的一个,我将添加几个:
git checkout -- .
:仅从索引到工作树的副本git checkout HEAD -- .
:从 HEAD 复制到索引,然后复制到工作树git reset --mixed
:从HEAD重置索引(然后单独留下工作树)git reset --hard
:从HEAD重置索引,然后从索引重置工作树这些重叠很多,但有几个关键不同的部分.
我们new.txt
特别考虑上面提到的文件.它现在在索引中,所以如果我们从索引复制到工作树,我们用索引副本替换工作树副本.git checkout -- new.txt
例如,这是做什么的.
相反,如果我们从开始复制HEAD
到索引中,没有任何反应new.txt
在指数:new.txt
不存在的HEAD
.因此,显式git checkout HEAD -- new.txt
只是失败,而git checkout HEAD -- .
复制存在的文件HEAD
并使两个现有new.txt
版本不受干扰.
该文件rmd.txt
是走了从索引,所以如果我们git checkout -- .
,Git不会看到它,做它没有.但是,如果我们git checkout HEAD -- .
,Git rmd.txt
从HEAD
索引(现在它回来)复制,然后从索引复制到工作树(现在它也回到那里).
git reset
与没有路径名参数一起使用时,该命令有一个关键区别.在这里,它实际上重新设置索引以匹配提交.这意味着,因为new.txt
它注意到文件不在HEAD
,所以它删除了索引条目.如果与之一起使用--hard
,它也会删除工作树条目.同时rmd.txt
是在HEAD
,所以它会复制回索引,以及--hard
,对工作树为好.
如果有不分级的,即工作树只,更改其他两个文件README.md
和file.txt
,两种形式git checkout
与--hard
形式git reset
消灭这些变化.
如果对这些文件进行了分阶段更改 - 已复制到工作树中的更改 - 则git reset
取消对它们进行分阶段.git checkout
您给它命名的变体也是如此HEAD
.但是,将git checkout
索引文件复制回工作树的变体可以保持这些分阶段的更改!
最后,值得注意的是.
,意味着当前目录,可能在任何时候都与"顶级Git存储库"不同:
$ git rev-parse --show-toplevel
/home/torek/src/kernel.org/git
$ pwd
/home/torek/src/kernel.org/git/Documentation
$ git rev-parse --show-cdup
../
Run Code Online (Sandbox Code Playgroud)
在这里,我位于Documentation
顶级目录的子目录中git
,因此.
意味着所有内容Documentation
及其子目录.例如,使用git checkout -- .
将检出(从索引)所有Documentation
和Documentation/RelNotes
文件,但不检出任何../builtin
文件.但是git reset
,在没有路径名的情况下使用时,将重置所有条目,包括for ..
和../builtin
.