首页 > 解决方案 > 未跟踪的文件已从本地目录中消失

问题描述

在我的项目中,我有一个.gitignore文件,除其他外,它public被列为未跟踪的文件夹(因此 public 不会出现在 Github 存储库中)。

前几天,我从 master 签出了一个单独的分支,并从.gitignore.

当我将这个新分支推送到 Github 时,它运行良好,我可以看到public新分支上的跟踪。

但是现在public已经从所有其他分支中完全消失了,当然包括master。有没有人遇到过类似的问题?我敢肯定有人有,所以这可能是多余的,但我不知道用更好的方式来表达这样一个奇怪的问题。

标签: gitgithubgitignore

解决方案


根据您所说的,这是完全正常的。

文件不会基于分支进行跟踪与未跟踪。分支,或者更准确地说,您的分支名称1完全不相关。但是,每个分支名称都会选择一个特定的提交,并且提交是相关的。一个提交,一旦做出,永远是一样的——但是分支名称会根据你告诉 Git 对它们做什么而移动,所以分支名称并不重要:重要的是提交。

当且仅当该文件当前位于 Git 的index中时,才会跟踪您在使用 Git 时使用的文件。 真正令人惊讶且有点令人费解的是,文件的可跟踪性甚至不是提交的属性。它往往提交控制,因为我们使用git checkout提取git switch提交。这会从该提交中填充 Git 的索引,这就是导致文件现在成为跟踪文件的原因。

您看到和使用的文件不在Git中。 这是真正的关键:当人们使用 Git 时,他们倾向于认为他们在工作树中的文件是“Git 文件”或“分支中的文件”或类似的东西。这是错误的。您使用的文件(工作树中的文件)可能是提交中提取的。 存储在提交中的文件在 Git 中。git push当您使用或 时,它们会从一个 Git 转移到另一个 Git git fetch工作树中的文件不在 Git 中。

如果 Git 从提交中复制了一个文件并将其放入您的工作树中,那么当您运行git checkout masterorgit checkout mybranch或时git checkout c0ffee900d,Git 会首先将该文件复制到 Git 的索引中。(假设所有这三个名称都选择了 commit c0ffee900d。)所以现在该文件存在于三个位置(也许还有更多提交,但至少这三个):

  • 该文件在提交中,您可以使用例如git show c0ffee900d:public/foo.html;
  • 该文件位于 Git 的索引中,您可以使用git show :public/foo.html;
  • 该文件在您的工作树中,您可以看到它,因为您的常规计算机程序会向您显示这些文件并使用它们。

但是假设你现在git checkout有一些其他的提交。通过哈希 ID 或分支名称选择任何其他提交。假设这个其他提交没有将文件存储public/foo.html在其中。Git 现在看到您正在从其中包含的某个提交转移到没有public/foo.html提交。所以Git:

  • :public/foo.html从 Git 的索引中删除,并且
  • public/foo.html从您的工作树中删除

因为你告诉它。


1另请参阅“分支”到底是什么意思?分支 这个词是模棱两可的:有时人们用它来表示分支的提示提交,在这种情况下,提交本身是相关的,并且您通过使用分支名称找到它,所以从这个意义上说,您的分支名称很重要。但是明天,您可能会更改与分支名称关联的哈希 ID,这可能会改变一切。但是,您无法更改有关某个特定提交的任何内容,并且您始终可以使用其哈希 ID 获取提交。


对于这一切你能做些什么

存储库c0ffee900d:public/foo.html中仍然有 的副本。该副本与 commit 一样永久:只要提交在存储库中,该文件的副本也是如此。但是那个文件不再在你的工作树中,因为它被跟踪了——它在 Git 的索引中——你告诉 Git 切换到 commit ,或者你选择的任何其他提交哈希 ID,并且那个提交没有那个文件。c0ffee900dbadcafe

您可能希望回到拥有未跟踪文件的状态,并以这种方式保存它们。未跟踪的文件不会像这样被删除或改组。当然,未跟踪的文件也不在每个提交中,也不会出现在克隆中,所以也许你不想让它们不被跟踪。或者,也许您希望它们在某些提交中而不是在其他提交中,并且当您检查其中一个其他提交时仍然可以将它们取回。

切换到其他提交后如何取回文件

只要任何给定的文件未被跟踪——不在 Git 的索引中——然后从这个提交切换到那个提交就不会删除它(尽管你会得到一个有趣的抱怨):

$ git rm --cached file
rm 'file'
$ git checkout HEAD^
error: The following untracked working tree files would be removed by checkout:
        file
Please move or remove them before you switch branches.
Aborting

发生这种情况是因为当前提交(在我的情况下8969ef2)和目标提交之间的差异bb2af52需要删除 file file. 我file在 commit 中添加并提交了文件8969ef2

所以,我现在可以mv file file.keep,git checkout HEAD^mv file.keep file. bb2af52现在,当我作为分离的 HEAD提交时,它是一个未跟踪的文件。

作为替代方案,我可以这样做:

$ git restore --staged file
$ git status
On branch master
nothing to commit, working tree clean

(这个特定git restore的命令直接来自git status,作为撤消我要提交的删除的建议。其他命令,例如git reset -- file,也可以。)

$ git checkout HEAD^
Note: switching to 'HEAD^'.

You are in 'detached HEAD' state. You can look around, make experimental
...
HEAD is now at bb2af52 initial

我的结帐现已成功,但我的工作树中不再有文件file(当然,Git 的索引中也没有)。8969ef2现在我使用哈希 ID或分支名称取回它master

$ git restore --source master file
$ git status
HEAD detached at bb2af52
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        file

nothing added to commit but untracked files present (use "git add" to track)

我的文件名为file,作为未跟踪文件回到我的工作树中,从我选择的提交中复制出来。如果您没有 Git 2.23 或更高版本,请使用:

git show master:file > file

而不是

git restore --source master file

推荐阅读