【问题标题】:What is the difference between "git checkout -- ." and "git reset HEAD --hard"?"git checkout -- ." 和有什么区别?和“git reset HEAD --hard”?
【发布时间】:2017-12-10 16:54:57
【问题描述】:

这不是关于 '--' 做什么的一般问题,就像在标记的副本中那样。这是一个特定于 git 的问题,要求明确上述命令之间的操作差异。

如果我想在不存储或提交的情况下清理当前目录,我通常使用以下命令:

git reset HEAD --hard
git clean -fd

一位同事也提到使用此命令:

git checkout -- .

对于谷歌来说这是一个困难的命令,从 git 文档中我不清楚这个命令实际上做了什么。貌似是手册后面提到的一种用法。

猜测它复制了git reset HEAD --hard,但与我已经使用的命令相比,它究竟做了什么?
它是复制一个或两个命令,还是相似但略有不同?

【问题讨论】:

  • 在 Stack Overflow 和其他 SE 网站上有很多关于此的问题:google.ca/…
  • git checkout -- 文件名将撤消特定文件的任何未暂存更改。混帐结帐 - 。将对当前文件夹中的所有文件执行相同的操作。
  • @meagar 谢谢,这与其说是双破折号的作用,不如说它是如何与 git 一起工作的。我认为这是一个常用工具的常见用法,可以保证特定于 git 的答案。
  • Git 通常以 POSIX 认可的方式将-- 视为选项结束标记,因此git whatever -a -- -b -c 仅将-a 视为选项-b-c 作为非选项参数git checkout -- 中的 -- 仅表示 -- 后面的任何内容都被视为 路径名,即使它类似于选项(-f 表示文件 -f,而不是 @ 987654335@) 或分支名称(master 表示文件 master,而不是分支 master)。至于git checkout .(有或没有--),这是文件提取形式,它git reset --HARD略有(微妙)不同。
  • 具体来说,git reset --hard 将从索引中删除提交中没有相应文件的所有条目,同时替换现有条目来自提交,而 git checkout -- .replace 现有条目与来自提交的条目,但不会 remove 任何条目。 . 也表示 current 目录,它可能是也可能不是 top level 目录,具体取决于您在存储库树中的位置。

标签: git git-checkout git-reset git-clean


【解决方案1】:

首先,让我们解决双连字符或双破折号,以使其不碍事(特别是因为这个问题不再有标记的重复项)。

Git 主要在the POSIX-approved fashion (see Guideline 10) 中使用它来表示选项参数和非选项参数之间的分界线。由于git checkout 接受分支名称,如git checkout master,以及文件(路径)名称,如git checkout README.txt,您可以使用-- 强制Git 将-- 之后的任何内容解释为文件名称,即使它是一个有效的分支名称。也就是说,如果你有一个 branch 和一个名为 masterfile

git checkout master

将检查 分支,但是:

git checkout -- master

将检查 文件(令人困惑的是,从当前 索引)。

Branches, index, and files, oh my

接下来,我们需要解决git checkout 的怪癖。从the documentation 可以看出,git checkout 有许多“模式”(文档在概要中列出了六个单独的调用!)。关于 Git 糟糕的“用户体验”模型有各种各样的咆哮(质量参差不齐:Steve Bennet's 在我看来实际上很有用,尽管我自然不会 100% 同意 :-)),包括 git checkout有太多的操作模式。

特别是,您可以git checkout一个分支(切换分支),或git checkout一个或多个文件。后者从特定提交或索引中提取文件。当 Git 从提交中提取文件时,它首先将它们复制到索引,然后将它们复制到索引,工作树.

这个序列有一个潜在的实现原因,但它完全显示出来的事实是一个关键元素。我们需要对 Git 的索引有很多了解,因为 git checkoutgit reset 都使用它,而且有时以不同的方式使用它。

我认为,绘制一个三向图或表格来说明当前(或HEAD)提交、索引和工作树是个好主意。假设:

  • 有两个普通的已提交文件README.mdfile.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” HEAD、索引和工作树有七种种可能的组合(第八个组合是“不是所有三个”,在这种情况下,我们首先在谈论什么文件?!)。

checkoutreset 命令

您询问的两个命令git checkoutgit 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.txtHEAD 中不存在。因此,显式的git checkout HEAD -- new.txt 会失败,而git checkout HEAD -- . 会复制HEAD 中的文件并保持现有的两个new.txt 版本不受干扰。

文件rmd.txt 已从索引中消失,所以如果我们git checkout -- .,Git 不会看到它,也不会做任何事情。但是如果我们git checkout HEAD -- .,Git 会将rmd.txtHEAD 复制到索引中(现在它回来了),然后从索引复制到工作树(现在它也回到了那里)。

git reset 命令在不使用路径名参数时有一个关键区别。在这里,它从字面上重新设置索引以匹配提交。这意味着对于new.txt,它注意到文件不在HEAD 中,因此它删除 索引条目。如果与--hard 一起使用,它也会删除 工作树条目。同时rmd.txt HEAD 中,因此它会将其复制回索引,并与--hard 一起复制到工作树。

如果有未暂存的,即仅工作树,则对其他两个文件README.mdfile.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
../

这里,我在顶级目录gitDocumentation 子目录中,所以. 表示Documentation 及其子目录中的所有内容。例如,使用git checkout -- . 将检出(从索引中)所有DocumentationDocumentation/RelNotes 文件,但不会检出任何../builtin 文件。但是git reset,当不使用路径名时,将重置所有条目,包括..../builtin的条目。

【讨论】:

  • If there are staged changes to those files—changes that have been copied into the work-tree— - 那应该是索引而不是工作树吗?
  • @ritsu:哎呀,是的。固定。
猜你喜欢
  • 2011-09-06
  • 2020-04-07
  • 2011-07-04
  • 2014-08-25
  • 1970-01-01
  • 2021-07-04
  • 2011-02-02
  • 2015-11-20
相关资源
最近更新 更多