git checkout head "IgnoreMyChanges.cs"
IgnoreMyChangesdid not match any file(s) known to git.
git命令是否有一个参数说“即使文件在排除列表中也可以获取文件”
git checkout head "IgnoreMyChanges.cs"
IgnoreMyChangesdid not match any file(s) known to git.
git命令是否有一个参数说“即使文件在排除列表中也可以获取文件”
如果文件在某个提交中,您可以使用以下命令将其从该提交中取出:
git checkout <commit-specifier> IgnoreMyChanges.cs
之后您可能应该运行:
git rm --cached IgnoreMyChanges.cs
几乎可以commit-specifier肯定不会。HEAD
如果你有 Git 2.23 或更高版本,你可以使用:
git restore --source=<commit-specifier> -w IgnoreMyChanges.cs
并且您不需要后续的git rm --cached. 或者,正如ElpieKay 在评论中建议的那样,您可以使用:
git show <commit-specifier>:IgnoreMyChanges.cs > IgnoreMyChanges.cs
它依赖于您的外壳重定向将文件写入您的工作树。请注意,在某些情况下,git show像这样使用会绕过 CRLF 行尾处理。
首先,一些一般性建议:
您应该始终拼写HEAD全部大写。小写拼写有时有效,有时无效。不要那样做。如果您不喜欢输入那么多大写字母,请考虑使用@而不是HEAD.
如果您的 Git 版本是 2.23 或更高版本,请考虑使用这两个命令git switch并git restore执行两个单独的作业,这些作业git checkout堆积成一个命令。
鉴于您没有提及git restore,我将在git checkout下面坚持,但请注意有两种git checkout:
一种检出检查整个提交。这就是git switch您使用新命令时所做的事情。这种检出也会更改名称HEAD(或@)所指的提交和分支。(请记住,任何提交的“真实名称”都是它的原始哈希 ID。 HEAD是当前分支名称 和当前提交哈希 ID的缩写。)这种检查是安全的,因为它首先检查以确保它会不要破坏您的任何文件。
另一种结帐检查一些特定的文件。这就是git restore您使用新命令时所做的事情。这种结账方式根本不会改变HEAD,而且这种结账方式是不安全的:如果你要求它,它会破坏未保存的工作。
两种结帐都git checkout使用 2.23 之前的命令拼写。有时很难确定你会得到哪种。在 Git 2.23 或更高版本中,如果该git checkout命令可以执行任何一项,git checkout将强制您选择一项,而不是只做错误的一项。不幸的是,在 2.23 之前的 Git 中,git checkout有时会在您没有预料到的情况下选择销毁您未保存的工作变体。
使用:
git checkout <commit-specifier> -- <file>
总是调用第二种git checkout——现在由 . 更直接地处理的那种git restore。该commit-specifier部分可以是指定特定提交的任何内容,包括:
HEAD。双连字符将此部分与文件名部分分开,并且是可选的。如果文件的名称类似于git checkout选项,例如,如果文件被命名--force或-m类似这些行的东西,您将需要它。
您可以将文件名放在双引号中,以保护它不受命令行解释器的影响。何时以及是否需要这样做并不取决于 Git,而是取决于您的命令行解释器。
.gitignore内容现在,Git 中的文件永远不会被忽略。事实上,“忽略”这个词是错误的动词。我们使用这个词是因为正确的词集太长,大多数时候都懒得说。这里真正的技巧是正确区分Git 中的文件和 Git中没有的文件。
每个提交(通过哈希 ID 或根据gitrevisions 文档可接受的其他名称找到)都包含一组文件,作为快照。所以任何给定的文件要么在某个提交中,要么不在那个提交中。
如果:
git checkout HEAD -- IgnoreMyChanges.cs
说:
IgnoreMyChanges.cs did not match any file(s) known to git.
那么该文件不在该提交中。如果你想知道哪个提交——具体来说是哪个哈希 ID——你可以运行:
git rev-parse HEAD
它向 Git 提出了一个问题:特殊名称的哈希 ID 是什么HEAD意思?
IgnoreMyChanges.cs不在该提交中的事实并不能告诉您该文件IgnoreMyChanges.cs是否在任何其他提交中。虽然每次提交都是您所有文件的完整快照,但它是您(或任何人)在您(或任何人)创建它时告诉 Git 放入其中的所有文件的快照。一旦制作完成,该快照将永远保存这些文件的该版本……或者至少,只要该提交本身继续存在。如果您可以向 Git 提供哈希 ID,并且该提交位于 Git 的所有 Git 对象的大数据库中,那么 Git 可以取回这些文件的这些版本。
这些文件位于 Git 中。他们永远被冻结在提交中。每个提交都有每个文件的完整快照,重复数据删除有效。由于大多数提交大多包含与其他提交相同的文件,因此这种重复数据删除意味着冻结的提交文件集合不会很快增长得非常快。但是由于它们被冻结并且采用这种特殊的、奇怪的、仅限 Git 的格式,因此您计算机上的其他任何东西都无法使用它们。
要使用这些文件,您必须让 Git从提交中删除它们。这就是第一种类型的git checkout内容:我们选择一个提交(通常按分支名称)并让 Git 提取其中的每个文件。这些文件被复制到工作区,现在它们是普通的日常文件。工作区称为您的工作树或工作树。您工作树中的这些日常文件是您的,而不是 Git 的。
始终牢记这一点很重要。 您的工作树文件根本不在 Git 中。 它们就在您的工作树中;它们是你认为合适的,你可以使用它们;而且它们也不是将进入新提交的文件。
当你让 Git 提取一些提交时——如git switch第一种git checkout——Git 实际上首先将冻结格式的文件复制到 Git 的index中。这个索引非常重要和/或命名不佳,以至于它还有两个名称——它也被称为staging area,或者有时(现在很少)缓存——具有某种“半在”Git 中的文件。
提取完整提交:
这就是git switch风格git checkout,它通常确保您的工作树文件不会被破坏,方法是确保它们都保存在当前提交中——即切换之前的当前提交。
现在所有目标(切换到)文件都在 Git 的索引中,Git 可以更新您的工作树:Git 将删除不在目标提交中的任何文件,即之前在索引和您的工作树中的文件,因此把它排除在外。Git 将替换目标提交中任何不同的文件。在先前的当前提交和目标提交中相同的文件可以保留,Git 会这样做。因此,从一个提交切换到另一个提交只会更新或删除需要更新或删除的工作树文件。
最终结果是您的工作树和Git 的索引现在都与您选择的提交匹配。2 这很重要,因为当您进行新的提交时,Git 真正做的是冻结到新的提交中,正是那些当时在索引中的文件。
因此,您在准备新提交时要做的是:
git add(and/or git rm) 来更新Git 的索引,因为索引保存了提议的下一次提交。一旦你有了索引的文件——暂存的副本——按照你想要的方式排列,你运行git commit,Git 会为索引或暂存区域中的文件创建一个新的快照。由于索引确实与您签出的提交匹配,因此实际上只有您复制回索引的任何内容发生了更改。
1从技术上讲,索引中的内容不是文件的完整副本,而是文件的名称和模式以及blob 哈希 ID。git ls-files --stage使用或将索引分解为单独的条目时,您可以看到差异git update-index。但是当你不使用这些低级的 build-a-new-Git-command 子命令时,你不必担心:你可以将索引视为保存文件的副本,准备就绪进入下一个提交。
2当您从一个提交切换到另一个提交同时保留一些未提交的更改时,会发生一种特殊情况。您不能总是这样做,描述何时可以这样做有点复杂,但这与 Git 是否可以在不覆盖 Git 索引和工作树中任何已修改数据的情况下切换提交有关。要更全面地了解这种特殊情况,请参阅Checkout another branch when there are uncommitted changes on the current branch。
工作树中的文件要么被跟踪,要么未被跟踪。一个被跟踪的文件,很简单,就是现在在你的工作树和Git的索引中的一个文件。未跟踪的文件是在您的工作树中但现在不在Git 索引中的文件。这就是全部,但也很多。
一旦你真正理解了 Git 如何使用 Git 的索引,跟踪文件的概念就变得有意义了。跟踪的文件将在下一次提交中。一个未跟踪的文件不会。Git在您运行时从索引中的文件构建新git commit的提交。如果文件在那里,它就在新的提交中。如果该文件不在其中,则它不在新提交中。
正如我之前所说,索引中的文件有点像“一半” Git:它们已准备好被冻结到提交中,一旦它们被冻结到提交中,它们就会被安全地存储。现在他们肯定在 Git 中了。
工作树中的文件根本不在 Git 中。它们可以被复制到索引中,然后它们是半进去的,提交肯定会让它们一直进去,但在那之前它们只是不在 Git 中的普通文件。
.gitignore列出一个文件会.gitignore做三件事:
它告诉 Git:如果这个文件现在不在索引中(即未跟踪),当我运行git status.
该git status命令打印一些通用的有用数据,然后运行两个比较:
第一个比较比较当前提交( HEAD) 与 Git 的索引。对于每个完全相同的文件,git status什么都不说。对于每个不同的文件,无论以任何方式——修改、删除或新——<code>git status 在为 commit 暂存的更改部分下列出文件的名称。
第二个比较将 Git 的索引与您的工作树进行比较。对于每个完全相同的文件,git status什么都不说。对于不同的文件(修改或删除),git status在部分changes not staged for commit下列出文件名。
请注意,未跟踪的文件尚未在第二次比较中列出:不在索引中但在工作树中的文件,还没有关于它们的任何内容。列出了暂存和未暂存的文件(如果有)之后,现在Git 会抱怨这些未跟踪的文件……除非您将它们列在.gitignore.
因此,列出文件.gitignore告诉 Git:如果文件未被跟踪,请保持沉默。 但它对被跟踪的文件没有影响,因为被跟踪的文件将进入新的提交。
Git 具有整体git add操作,例如git add *or git add .。列出一个文件会.gitignore告诉 Git,如果该文件未被跟踪,则整体add不应将其复制到索引中。
通常,未跟踪的文件(不在索引中的文件)只会被复制到索引中,现在它将是一个跟踪文件,索引副本与您运行时的工作树副本匹配git add。但大概你已经列出了文件.gitignore以防止它被提交。由于 Git 将提交 Git 索引中的任何内容,因此您不希望它被添加到 Git 的索引中。跳过git add未跟踪的文件可以实现该目标。
不过,这再一次对跟踪的文件没有影响。跟踪的文件已经在 Git 的索引中。
最后——通常是不可见的,但有时这会导致问题——在其中列出文件.gitignore会给 Git 额外的权限来破坏文件的内容。通常,Git 会告诉您某些文件将被 agit checkout或覆盖或删除git merge,但在某些情况下,列在 a 中.gitignore会授予 Git 销毁(或删除)该文件的权限。
所以与其调用这个文件.gitignore,Git 或许应该调用它.git-ignore-these-files-when-they-are-untracked-and-also-do-not-automatically-add-them-with-en-masse-add-operations-unless-they-are-already-tracked。(它甚至可能提到偶尔破坏他们的方面。)但这是一个必须输入的荒谬的事情,所以.gitignore它是。
重要的是要了解跟踪与未跟踪的真正含义:在索引中或不在索引中。重要的是要意识到 Git从索引而不是您的工作树中进行新提交,并且您的工作树文件实际上根本不在Git中。重要的是要知道,在.gitignore跟踪文件时,将文件列在其中没有任何影响。
通常,如果文件不在当前 ( HEAD) 提交中,则现在也不会对其进行跟踪。那是因为您通过运行git checkout或git switch从提交中完全填充 Git 的索引和您的工作树进入了这种状态HEAD。因此,如果它不是,也不是, in HEAD,则它没有被放入(甚至被取出)索引,因此未被跟踪。但是因为你可以故意从索引中取出东西:
git rm --cache somefile
或将内容放入索引中:
git add somefile
这不是一个硬性的保证。
如果某些文件未被跟踪,请将其列在.gitignore事项中。但如果它被跟踪,那才是真正重要的:它被跟踪并且它将在下一次提交中。