这不是一个关于“--”做什么的一般性问题,如在标记的副本中。这是一个特定于git的问题,要求澄清上述命令之间的操作差异。
如果要清除当前目录而不隐藏或提交,通常使用以下命令:
git reset HEAD --hard
git clean -fd
一位同事还提到使用此命令:
git checkout -- .
对google来说,这是一个困难的命令,从git文档中我不清楚这个命令到底做了什么。这似乎是手册中后来提到的用法之一。
据猜测,它会复制
git reset HEAD --hard
,但与我已经使用的命令相比,它到底能做什么呢?它是复制其中一个或两个命令,还是相似但又有细微的不同?
最佳答案
首先,让我们只解决双连字符或双破折号,以摆脱它的方式(特别是因为这个问题不再有标记的重复)。
git在the POSIX-approved fashion (see Guideline 10)中主要使用这个来表示选项参数和非选项参数之间的分界线。由于git checkout
接受分支名称(如git checkout master
中所示)和文件(路径)名称(如git checkout README.txt
中所示),因此可以使用--
强制git将--
之后的任何内容解释为文件名,即使它本来是有效的分支名称。也就是说,如果同时有一个分支和一个名为master
的文件:
git checkout master
将检查分支,但是:
git checkout -- master
将签出文件(令人困惑的是,从当前索引)。
Branches, index, and files, oh my
接下来,我们需要解决
git checkout
的一个怪癖。从the documentation可以看出,git checkout
有很多“模式”(文档列出了synposis中的六个单独调用!)。关于Git糟糕的“用户体验”模型,有各种各样的论调(质量参差不齐:Steve Bennet's在我看来实际上是有用的,尽管我自然不同意它100%:-),包括git checkout
有太多的操作模式。特别是,您可以
git checkout
一个分支(切换分支),或git checkout
一个或多个文件。后者从特定提交或索引中提取文件。当git从提交中提取文件时,它首先将它们复制到索引中,然后从索引中将它们复制到工作树中。这个序列有一个潜在的实现原因,但它显示出来的事实是一个关键元素。我们需要对git的索引了解很多,因为
git checkout
和git reset
都使用它,有时使用的方式也不同。我认为,最好绘制一个三向图或表,说明当前或
HEAD
-commit、索引和工作树。假设:有两个普通的提交文件
README.md
和file.txt
;有一个新的,
git add
-ed但未提交的new.txt
;有一个名为
rmd.txt
的文件已被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
除了这些,还有很多可能的状态:事实上,对于每个文件名,“in/not in”头、索引和工作树有七种可能的组合(第八种组合是“not in all three”,在这种情况下,我们首先谈论的是什么文件?!)。
checkout
和reset
命令您询问的两个命令
git checkout
和git reset
都可以执行许多操作。但是,每一个的具体调用都将“完成的事情”减少到两个中的一个,我将在其中再添加几个:git checkout -- .
:仅从索引复制到工作树git checkout HEAD -- .
:从head复制到index,然后复制到work treegit 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
../
这里,我在顶层目录的子目录中,所以
.
表示Documentation
及其子目录中的所有内容。使用git
将签出(从索引中)所有.
和Documentation
文件,但不签出任何git checkout -- .
文件。但是Documentation
在没有路径名的情况下使用时,将重置所有条目,包括Documentation/RelNotes
和../builtin
的条目。
关于git - “git checkout —。”和“git reset HEAD --hard”之间有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44953037/