撤消git命令-git checkout-

时间:2018-07-15 21:41:15

标签: git git-checkout

是否可以撤消以下git命令:

git checkout -- .

我正在尝试删除添加到repo目录中但未暂存或未提交的文件。该命令似乎没有执行此操作,而是更改了一些其他文件。

更新

未跟踪的文件和未暂存的文件之间存在区别。在这种情况下,我想找到一种丢弃未跟踪和未暂存文件的方法。当我运行git checkout -- .时,我以为它将除去未跟踪的文件,但据我所知,它只能除去未暂存的文件。

1 个答案:

答案 0 :(得分:2)

git checkout -- path索引/登台区域复制到工作树

如果您命名的 path 是目录,则Git将从其开始将其知道的所有文件(在索引/暂存区域中找到)复制到工作树中该目录及其所有子目录。

不过,要利用此答案,您需要了解每个文件的三个活动副本。

每个文件的(最多)三个副本

请记住,在Git中,每个文件始终有多达三个版本。例如,假设您在存储库中已提交名为README.txta.ext的文件。 README.txt三份a.ext三份在任何给定时间都可以使用。三份副本中的两份采用特殊的仅Git格式。

如果我们使用git show来访问仅Git格式文件的语法,则可以通过以下方式描述这三个副本:

    HEAD             index        work-tree
---------------   -----------     ----------
HEAD:README.txt   :README.txt     README.txt
HEAD:a.ext        :a.ext          a.ext

如果您现在创建一个新的未跟踪文件b.dat,则具有以下内容:

    HEAD             index        work-tree
---------------   -----------     ----------
HEAD:README.txt   :README.txt     README.txt
HEAD:a.ext        :a.ext          a.ext
                                  b.dat

在索引/暂存区域中尚无b.dat的副本。在其他两个文件中,有 两个逻辑上分开的副本,尽管它们在HEAD和索引中都是相同的。 。 (当它们相同时,Git会自动共享基础副本,因此不需要额外的空间。)

工作树副本是普通文件

存储在工作树中的任何文件的任何副本都只是一个普通文件。您可以使用计算机执行的任何操作。 Git不在乎您如何处理此类文件。如果您询问Git有什么不同,Git 告诉您工作树副本与索引副本不同。

git add path工作树复制到临时区域

此时,假设您使用任何喜欢的编辑器来修改README.txt,该编辑器将编辑工作树副本(除非它非常熟悉Git,否则它将完全无法使用或触摸索引副本)。现在,工作树副本不同于索引副本。索引副本采用特殊的仅Git格式,可以进行下一次提交。

您现在将需要运行git add README.txt,以将更新的工作树文件复制到索引中。完成此操作后,旧版本的README.txt仍处于HEAD提交中,也是仍采用特殊的仅Git格式,但是现在HEAD:README.txt是与:README.txt不同,而:README.txtREADME.txt相同。

每个文件的HEAD提交副本是只读的;索引副本不是

任何提交中的任何内容都无法更改。因此,您提交的README.txt的副本和您提交的a.ext的副本将永远安全地保存在存储库中 1 。索引/暂存区中的副本可能与HEAD提交中的副本相同, 可以随时被覆盖。它的开始与HEAD提交中的 2 相同,但是git add从工作树到< / em>索引。


1 如果您放弃或删除提交(通常通过git resetgit rebase -i),则可能导致Git丢失冻结副本:冻结副本仅持续到只要包含它的提交即可。但是,大多数Git都是基于添加新提交而不删除旧提交的想法构建的。

2 如果您Checkout another branch when there are uncommitted changes on the current branch,您可以克服“签出或提交后HEAD和索引匹配”的正常情况。这个答案没有足够的空间来详细说明这些细节。


git commit将所有索引副本冻结到一个新的提交中

git commit的作用是将当时索引中的每个文件以当时索引中的格式获取,并将其冻结为只读的提交副本。此提交的文件集成为新的HEAD提交。 git commit完成运行并返回提示后,您将有一个新的提交,并且您的HEAD提交和您的索引匹配-因为Git使新提交 from 为索引!

未跟踪的文件

Git非常简单地定义了一个未跟踪文件:它是不在索引中的文件。就这样—就是所有的一切—但却有很强的后果:如果b.dat不在索引中,则git commit不会将其放入新提交中。而且,git checkout --无法查找 b.dat,因为它不在索引中,因此它不能覆盖工作树副本。

请注意,仅仅是因为某些文件存在于存储库中的 some 提交中,并不意味着文件已被跟踪!当且仅当该文件现在位于索引为 时,才会跟踪该文件。如果您运行git checkout包含 的文件的提交,则 then (此时),Git会将提交中的文件复制到索引中,然后进入工作树。 当时将跟踪该文件。如果您随后从索引中明确删除文件,则那时将停止跟踪该文件。因此,您必须时刻牢记或测试索引中是否存在某些特定文件的副本,以了解是否已对其进行跟踪。

git checkout commit -- path提交复制索引和工作树

在这里,通过git reset,Git通过将多个不同的东西塞到一个命令中而变得过于复杂。当使用git checkout with 路径,但没有提交或树说明符时,Git将从索引复制到工作树。当您同时使用git checkout路径作为提交或树时,Git会将索引的工作复制到 树。

git reset -- path提交提交,复制索引,仅保留工作树

git reset的这种特殊形式,与路径一起使用,从提交复制到索引/临时区域。请记住,索引已经包含所有跟踪文件的副本,因此这只是将它们与其他副本一起覆盖。默认情况下,git reset用于获取文件的提交是HEAD提交-因此,此副本将从有效的HEAD副本复制到索引中。

任何文件的工作树副本都保留下来。该文件存在于HEAD提交中这一事实意味着该文件已被可能跟踪:取消跟踪该文件的唯一方法是:签出该提交,然后显式删除该提交。索引副本。在这种情况下,git reset -- path将文件放回索引中,以便再次对其进行跟踪。

但是请注意,您可以使用git reset commit -- path从特定的提交中复制文件。如果该文件不是HEAD提交中,则该文件很可能在您进行git reset操作之前已被取消跟踪(不在索引中),但已被跟踪(在索引中)之后。这完全取决于您已经对索引进行了哪些更改。

摘要

运行git status进行两次比较:

  • 第一个比较是HEAD vs索引。

    HEAD中的文件也可能在索引中(因此所有这些文件都被跟踪)。如果索引中的副本与HEAD中的副本不同,则Git会调用准备提交的副本。如果索引中的副本与HEAD中的副本相同,则文件本身仍会被跟踪和暂存-只是git status不会困扰提及它。

    这里的关键思想是,即使每次提交都是所有文件的完整快照,我们还是想知道关于 提交的内容:此提交有何不同之处因此,git status告诉我们,如果我们采用当前暂存区(建议的新提交)并将其实际转换为新提交,会有什么不同。

  • 第二个比较是索引与工作树。此处有什么不同之处是不上演提交阶段

    跟踪索引中的文件。对于那些与工作树中的内容相匹配的内容,git status不用理会它们。对于那些不同的内容,git status提及了它们,因为未上演提交。对于根本不在索引中但在工作树中是 的文件,Git抱怨说它们是未跟踪的

    再一次,这里的总体思路是,我们关心与前一个提交相比,每个提交实际上有什么不同。如果我们已取消暂存或什至未跟踪的文件与暂存副本不同(或缺少暂存副本),我们可以 使用git add将它们复制到暂存区域。如果我们有一个与暂存的a.ext完全相同的工作树a.ext和与HEAD:a.ext完全相同的工作树,那么我们可能不在乎,所以我们根本就不需要完全看到它。

    要关闭绝对不应该提交的未跟踪文件,您可以列出这些未跟踪文件(按名称或全局模式,例如*.o*.pyc)在.gitignore指令中。这样可以防止Git自动将文件添加到git add .git add --all中,也可以防止git status发出抱怨。但是请注意,如果某个文件已经在索引中(无论它已经到达那里了),则在.gitignore 中列出该文件的名称或模式没有任何作用。

    < / li>

复制文件的主要操作是:

  • git add path:从工作树复制到索引
  • git checkout -- path:从索引复制到工作树
  • git checkout commit -- path:从 commit 复制到索引和工作树
  • git reset [commit] -- path:从 commit (默认为HEAD)复制到索引

删除文件的主要操作是:

  • git add path:如果 path 在索引中但在工作树中丢失,则从索引中删除
  • git rm --cached path:从索引中删除,但不从工作树中删除
  • git rm path:从索引和工作树中删除
  • git reset [commit] -- path:如果 path 中不包含 commit (默认为HEAD),则从索引中删除

除这些以外,您还可以使用git commit --only pathsgit commit --include paths触发一些特殊情况,但这些本质上等同于首先在这些路径上进行git add。始终牢记索引,并注意git status 总结了索引的差异,而不是列出索引的内容,因此,如果您有30,000个大型文件项目,则只会看到很少有趣的文件,而不是全部30,000个文件。