简体   繁体   English

“git checkout — .” 和有什么区别? 和“git reset HEAD --hard”?

[英]What is the difference between “git checkout — .” and “git reset HEAD --hard”?

This is not a general question about what '--' does, as in the marked duplicate.这不是关于“--”做什么的一般问题,如标记的重复项。 This is a git-specific question asking for clarity on what the operational differences are between the mentioned commands.这是一个特定于 git 的问题,要求明确上述命令之间的操作差异。

If I want to clean out my current directory without stashing or committing, I usually use these commands:如果我想在不存储或提交的情况下清理当前目录,我通常使用以下命令:

git reset HEAD --hard
git clean -fd

A co-worker also mentioned using this command:一位同事也提到使用此命令:

git checkout -- .

It's a difficult command to google, and it's not clear to me from the git documentation what this command actually does.对谷歌来说这是一个困难的命令,我从 git 文档中不清楚这个命令实际上做了什么。 It seems to be one of the later-mentioned usages in the manual.这似乎是手册中后面提到的用法之一。

At a guess it replicates git reset HEAD --hard , but what exactly does it do as compared to the commands I'm already using?猜测它复制了git reset HEAD --hard ,但与我已经使用的命令相比,它究竟做了什么?
Does it replicate one or both of the commands, or is it similar yet subtly different?它是否复制了一个或两个命令,或者它是否相似但略有不同?

First, let's just address the double hyphen or double dash, to get it out of the way (especially since this question no longer has a marked duplicate).首先,让我们解决双连字符或双破折号,以摆脱它(特别是因为这个问题不再有标记重复)。

Git mostly uses this in the POSIX-approved fashion (see Guideline 10) , to indicate a dividing line between option arguments and non-option arguments. Git 主要以POSIX 认可的方式使用它(参见指南 10) ,以指示选项参数和非选项参数之间的分界线。 Since git checkout accepts branch names, as in git checkout master , and also file (path) names, as in git checkout README.txt , you can use the -- to force Git to interpret whatever comes after the -- as a file name, even if it would otherwise be a valid branch name.由于git checkout接受分支名称(如git checkout master )和文件(路径)名称(如git checkout README.txt ,您可以使用--强制 Git 将--后面的任何内容解释为文件名,即使它是一个有效的分支名称。 That is, if you have both a branch and a file named master :也就是说,如果你有一个分支和一个名为master文件

git checkout master

will check out the branch , but:将检查分支,但是:

git checkout -- master

will check out the file (confusingly, from the current index ).将检出文件(令人困惑的是,从当前索引)。

Branches, index, and files, oh my 分支、索引和文件,天哪

Next, we need to address a quirk of git checkout .接下来,我们需要解决git checkout一个怪癖。 As one can see from the documentation , there are many "modes" of git checkout (the documentation lists six separate invocations in the synposis!).文档中可以看出, git checkout有许多“模式”(文档在概要中列出了六个单独的调用!)。 There are various rants (of varying quality: Steve Bennet's is actually useful, in my opinion, though naturally I do not agree with it 100% :-) ) about Git's poor "user experience" model, including the fact that git checkout has too many modes of operation.关于 Git 糟糕的“用户体验”模型,有各种各样的咆哮(质量各不相同: Steve Bennet 的实际上很有用,在我看来,虽然我自然 100% 不同意它:-)),包括git checkout也有多种操作模式。

In particular, you can git checkout a branch (to switch branches), or git checkout one or more files .特别是,您可以git checkout一个分支(切换分支),或git checkout一个或多个文件 The latter extracts the files from a particular commit, or from the index.后者从特定提交或索引中提取文件。 When Git extracts files from a commit, it first copies them to the index, and then copies them from the index, to the work-tree.当 Git 从提交中提取文件时,它首先将它们复制索引,然后将它们索引复制工作树。

There is an underlying implementation reason for this sequence, but the fact that it shows through at all is a key element.这个序列有一个潜在的实现原因,但它完全显示出来的事实是一个关键因素。 We need to know a lot about Git's index, because both git checkout and git reset use it, and sometimes in different ways.我们需要了解很多关于 Git 的索引,因为git checkoutgit reset使用它,而且有时使用的方式不同。

It's a good idea, I think, to draw a three-way diagram or table illustrating the current—or HEAD —commit, the index, and the work-tree.我认为,绘制一个三向图或表格来说明当前(或HEAD提交、索引和工作树是个好主意。 Suppose that:假设:

  • there are two ordinary, committed files README.md and file.txt ;有两个普通的提交文件README.mdfile.txt
  • there is a new, git add -ed but uncommitted new.txt ;有一个新的, git add -ed 但未提交的new.txt
  • there is a file named rmd.txt that has been git rm -ed but not committed;有一个名为rmd.txt的文件已被git rm -ed 但未提交;
  • and there is an untracked file named untr.txt .并且有一个名为untr.txt的未跟踪文件。

Each entity—the HEAD commit, the index, and the work-tree—holds three files right now, but each holds a different set of files.每个实体HEAD提交、索引和工作树——现在都持有三个文件,但每个都持有不同的文件 The table of the entire state then looks like this:整个状态的表看起来像这样:

  HEAD       index    work-tree
-------------------------------
README.md  README.md  README.md
file.txt   file.txt   file.txt
           new.txt    new.txt
rmd.txt
                      untr.txt

There are many more possible states than just these: in fact, for each file-name, there are seven possible combinations of "in/not-in" HEAD, index, and work-tree (the eighth combination is "not in all three", in which case, what file are we even talking about in the first place?!).可能的状态远不止这些:事实上,对于每个文件名,“在/不在”HEAD、索引和工作树有七种可能的组合(第八种组合是“不在所有三个中” “,在这种情况下,我们甚至首先谈论的是什么文件?!)。

The checkout and reset commands checkoutreset命令

The two commands you're asking about, git checkout and git reset , are both able to do many things.您询问的两个命令git checkoutgit reset都可以做很多事情。 The specific invocations of each, however, reduce the "things done" to one of two, to which I will add several more:然而,每个的具体调用将“完成的事情”减少到两个之一,我将添加更多:

  • git checkout -- . : copies from index, to work-tree, only :索引复制工作树,仅
  • git checkout HEAD -- . : copies from HEAD, to index, and then to work-tree :HEAD 复制索引,然后复制工作树
  • git reset --mixed : resets index from HEAD (and then leaves work-tree alone) git reset --mixed :从 HEAD 重置索引(然后单独留下工作树)
  • git reset --hard : resets index from HEAD, then resets work-tree from index git reset --hard :从 HEAD 重置索引,然后从索引重置工作树

These overlap a lot, but there are several crucially-different parts.这些重叠很多,但有几个关键不同的部分。

Let's consider the file named new.txt above in particular.让我们特别考虑上面名为new.txt的文件。 It's in the index right now, so if we copy from the index, to the work-tree, we replace the work-tree copy with the index copy.它现在在索引中,所以如果我们索引复制工作树,我们用索引副本替换工作树副本。 This is what git checkout -- new.txt does, for instance.例如,这就是git checkout -- new.txt所做的。

If, instead, we start by copying from HEAD to the index, nothing happens to new.txt in the index: new.txt doesn't exist in HEAD .相反,如果我们通过复制开始HEAD到索引中,没有任何反应new.txt索引: new.txt存在HEAD Hence an explicit git checkout HEAD -- new.txt just fails, while a git checkout HEAD -- .因此,显式git checkout HEAD -- new.txt失败,而git checkout HEAD -- . copies the files that are in HEAD and leaves the two existing new.txt versions undisturbed.复制HEAD的文件,并使两个现有的new.txt版本不受干扰。

The file rmd.txt is gone from the index, so if we git checkout -- .文件rmd.txt从索引中消失了,所以如果我们git checkout -- . , Git does not see it and does nothing about it. ,Git 看不到它,也不做任何处理。 But if we git checkout HEAD -- .但是如果我们git checkout HEAD -- . , Git copies rmd.txt from HEAD into the index (now it's back) and then from the index to the work-tree (and now it's back there, too). , Git 将rmd.txtHEAD复制到索引中(现在它回来了),然后从索引复制到工作树(现在它也回到了那里)。

The git reset command has a key difference when used with no path name arguments. git reset命令在没有路径名参数的情况下使用时有一个关键的区别。 Here, it literally re-sets the index to match the commit.在这里,它从字面上重新设置索引以匹配提交。 That means that for new.txt , it notices that the file is not in HEAD , so it removes the index entry.这意味着对于new.txt ,它注意到该文件不在HEAD ,因此它删除了索引条目。 If used with --hard , it therefore also removes the work-tree entry.如果与--hard ,它也会因此删除工作树条目。 Meanwhile rmd.txt is in HEAD , so it copies that back to the index, and with --hard , to the work-tree as well.同时rmd.txtHEAD ,所以它会复制回索引,并与--hard ,对工作树为好。

If there are unstaged, ie, work-tree only, changes to the other two files README.md and file.txt , both forms of git checkout and the --hard form of git reset wipe out those changes.如果有未暂存的,即只有工作树,对其他两个文件README.mdfile.txt更改,两种形式的git checkout--hard形式的git reset清除这些更改。

If there are staged changes to those files—changes that have been copied into the index—then git reset un-stages them.如果对这些文件进行了暂存更改(已复制到索引中的更改),则git reset取消git reset它们。 So does the variant of git checkout where you give it the name HEAD . git checkout的变体也是如此,您将其命名为HEAD However, the variant of git checkout where you copy the index files back to the work-tree keeps those staged changes staged!但是,将索引文件复制回工作树的git checkout变体使这些暂存更改保持暂存状态!

Top level vs current directory顶级与当前目录

Last, it's worth noting that .最后,值得注意的是. , meaning the current directory , may at any time be different from "top of Git repository": ,表示当前目录,可能随时与“顶部 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
../

Here, I am in the Documentation sub-directory of the top level directory git , so .在这里,我在顶级目录gitDocumentation子目录中,所以. means everything in Documentation and its subdirectories .表示Documentation及其子目录中的所有内容 Using git checkout -- .使用git checkout -- . will check out (from the index) all the Documentation and Documentation/RelNotes files, but not any of the ../builtin files, for instance.例如,将检出(从索引中)所有DocumentationDocumentation/RelNotes文件,但不会../builtin任何../builtin文件。 But git reset , when used without path names, will reset all entries, including those for .. and ../builtin .但是git reset ,当在没有路径名的情况下使用时,将重置所有条目,包括..../builtin

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 git checkout和有什么不一样? vs git reset --hard HEAD - What is the difference between git checkout . vs git reset --hard HEAD “git checkout -f”和“git reset --hard HEAD”有什么区别? - What is difference between “git checkout -f” and “git reset --hard HEAD”? git checkout HEAD -- 之间有区别吗? 和 git reset --hard HEAD? - Is there a difference between git checkout HEAD -- . and git reset --hard HEAD? git reset - hard HEAD和git checkout之间有区别吗? - Is there a difference between git reset --hard HEAD and git checkout .? git reset --hard HEAD~1 和 git reset HEAD~1 --hard 之间的区别? - Difference between git reset --hard HEAD~1 and git reset HEAD~1 --hard? “git reset --hard”和“git checkout”有什么区别? - What is the difference between “git reset --hard” and “git checkout .”? git reset - hard和git checkout之间的区别 - Difference between git reset --hard and git checkout git reset –hard head`和`git clean –force -d`vs`git checkout —之间有什么区别,以放弃本地更改。 - What is the difference between `git reset --hard head` vs `git clean --force -d ` vs `git checkout — .` to discard local changes 'git reset --hard HEAD~1' 和 'git reset --soft HEAD~1' 有什么区别? - What is difference between 'git reset --hard HEAD~1' and 'git reset --soft HEAD~1'? git reset --hard HEAD〜1和git revert HEAD有何异同? - What's the similarity & difference between git reset --hard HEAD~1 and git revert HEAD?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM