这不是关于什么' - '与标记的副本一样。这是一个特定于git的问题,要求澄清所提到的命令之间的操作差异。
如果我想在没有存储或提交的情况下清理当前目录,我通常会使用这些命令:
git reset HEAD --hard
git clean -fd
一位同事也提到使用这个命令:
git checkout -- .
这对谷歌来说是一个困难的命令,而且从git文档中我并不清楚这个命令实际上做了什么。它似乎是手册中后面提到的用法之一。
猜测它会复制git reset HEAD --hard
,但与我已经使用过的命令相比,它究竟做了什么呢?
它是复制一个还是两个命令,还是相似而又略有不同?
答案 0 :(得分:7)
首先,让我们只解决双连字符或双连字符,以使其不受影响(特别是因为此问题不再有明显重复)。
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
将检出文件(令人困惑的是,来自当前的索引)。
接下来,我们需要解决git checkout
的怪癖。从the documentation可以看出,有很多"模式" git checkout
的文档(文档列出了在synposis中的六个单独的调用!)。有各种各样的咆哮(不同的质量:Steve Bennet's实际上是有用的,在我看来,虽然我自然不同意它100%:-))关于Git的糟糕"用户体验&# 34;模型,包括git checkout
有太多操作模式的事实。
特别是,您可以git checkout
分支(切换分支)或git checkout
一个或多个文件。后者从特定提交或索引中提取文件。当Git从提交中提取文件时,它首先将它们复制到索引,然后将从索引复制到工作树
这个序列有一个潜在的实现原因,但它显示的事实是一个关键元素。我们需要了解很多关于Git的索引,因为git checkout
和git reset
都使用它,有时候会以不同的方式使用它。
我认为,绘制一个说明当前或HEAD
- 提交,索引和工作树的三向图表或表格是一个好主意。假设:
README.md
和file.txt
; git add
- 但未提交new.txt
; rmd.txt
的文件已被git rm
- 但尚未提交; 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" HEAD,索引和工作树(第八个组合是"不是所有三个",在这种情况下,我们甚至首先讨论的文件是什么?!)。
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
复制到索引(现在它已经回来),然后从索引复制到工作树(现在它就是&#39} ; s也回到那里。)
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存储库的顶部不同而且#34;:
$ 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
的{{1}}子目录中,因此git
表示 .
及其子目录中的所有内容。例如,使用Documentation
将(从索引中)检出所有git checkout -- .
和Documentation
文件,但不检出任何Documentation/RelNotes
文件。但../builtin
在没有路径名的情况下使用时,会重置所有条目,包括git reset
和..
的条目。