最近,我意外地将我所有的项目文件都推送到了github仓库中,而没有创建.gitignore文件,然后在事实发生后将其添加到github中,并删除了在最初推送时会被忽略的文件(如果有.gitignore文件)存在。完成此操作后,我将存储库拉到本地git,以为我只会得到.gitignore文件,但是所有对开发很重要的文件(.project,.classpath,*。jar等)都将被忽略。我在日食中被删除了。
如何恢复这些丢失的文件,以及将来如何在不删除文件的情况下添加.gitignore文件。
感谢您的帮助。
答案 0 :(得分:0)
尝试删除.gitignore文件,将其推送到远程存储库,然后键入
git pull
答案 1 :(得分:0)
我从评论中看到您已经恢复了文件,这很好,这意味着我不必为此编写特定的说明(尽管我将在其中进行介绍)。但是:了解.gitignore
的作用很重要。它实际上并不会导致文件被忽略! (这意味着.gitignore
并不是很好的名字,但是 good 的名字确实很长。可能应该将其命名为.gitxyz
或.gitconfuse
或简短而令人难忘,但您不认为这意味着“忽略”。)
那么, .gitignore
到底是做什么的?好吧,这需要快速深入到Git的其他部分,许多教程或介绍对此都做了掩盖,这引起了很多混乱,这就是Git的 index 。
首先,让我们注意Git主要要做的是存储 commits 。提交可保存您所有文件的完整快照,包括该提交所包含的所有文件,但这有点多余:“提交具有提交所具有的内容。”这里的重要部分是每个文件都有一个完整副本,这些文件被冻结且不可变,可以永久保存(或至少在提交本身继续存在的情况下保存)。
(提交还包含一些元数据,例如一些信息,例如您的姓名和作为作者/提交人的电子邮件地址,以及您的日志消息。最重要的是,每个提交还都包含上一个的真实名称(哈希ID)或 parent 提交。但我们不在这里介绍。)
这些冻结的文件在每次提交时永久且不变地保存,如果不压缩它们将占用大量空间,因此它们采用特殊的,压缩的,仅Git的形式。实际上,由于 已冻结,因此如果两个不同的提交对文件使用相同的数据,则这两个提交实际上会 share 冻结的副本。这意味着Git始终将文件的相同副本放入每个新提交中,这一事实根本不占用空间,因为它实际上只是在重用旧文件。但是无论如何,这些文件对任何 Git都没有用:没有其他系统可以直接读取它们,甚至Git都没有写东西:它们被冻结了。
因此,要让您查看和处理文件,Git必须将保存在某些提交中的所有文件解冻到某种工作区中。 Git将此区域称为工作树或工作树。这是一个好名字,因为它是您工作的地方。
其他非Git版本控制系统通常在此处停止:它们具有已提交的文件(可能存储为增量而不是完整文件),工作树,仅此而已。当您使用这些系统之一并进行 new 提交时,这会花费时间,有时会花费很多时间。有时,您可以在等待时出去吃午餐。不过,使用Git,您可以运行git commit -m message
并- zip -完成。
Git从其 index 获得所有这些速度。但是 index 是这个名称的可怕名称,因此Git也将其称为临时区域,有时甚至称为缓存,具体取决于谁/什么正在打电话。索引的作用是保留(以一种特殊的仅Git形式,但这次不冻结),所有要在 next 提交中的文件。
最初,索引将从您签出的所有提交中填充。也就是说,git checkout <some-commit-specifier>
找到包含完整冻结文件集的提交。 Git将冻结的文件(以及指向其内容的链接)复制到索引中,一路找出文件的全名,以便索引包含Git需要放入工作树中的所有文件的列表。 。这些现在采用特殊的仅Git格式,但是未冻结。然后,Git还将文件放入工作树,将其扩展为有用的格式。
最终结果是索引与提交匹配,但是索引未冻结。工作树同时匹配提交和索引 ,当然它们是未冻结的,文件具有其有用的形式。您现在可以照常进行工作了,这解释了为什么为什么您必须始终git add
进行文件操作!
git add
的作用是将工作树文件复制到索引中。如果文件已在索引中,则这将覆盖先前的副本。现在,新副本为仅Git格式(但仍未冻结)。如果文件以前不在索引中,则它现在在索引中。无论哪种情况,索引仍然可以使用。 git commit
除了收集诸如您的姓名,电子邮件和日志消息之类的元数据外,所有要做的事情都是冻结索引。
因此,对于索引,我知道的最好的简短描述是:索引包含您建议的 next 提交。其中包含所有文件。特殊的仅Git形式,但尚未冻结。这就是为什么它也称为 staging区域:的原因,它具有所有文件,可以进行暂存并准备就绪。
现在您知道每个文件都有三个副本,您可以担心,所有这些都将变得有意义。例如,让我们考虑一个README.txt
文件。您运行git checkout master
开始,Git找到master
的提交并检出,使该提交成为当前或HEAD
提交:
HEAD:README.txt
被冻结在当前提交中。它永远不会改变-这是该提交的一部分。
:README.txt
被复制到索引中,并在此过程中取消冻结。可以更改,但当前与HEAD:README.txt
匹配。
:README.txt
从索引复制到工作树,扩展为有用的形式。可以更改,但当前与:README.txt
匹配。
所有三个副本都匹配,因此Git对该文件一言不发。
如果现在更改工作树副本并运行git status
,则Git的status
命令将HEAD
和索引副本进行比较。它们是相同的,因此对此一无所知。它比较索引和工作树副本,它们是不同的,因此git status
说文件未上演提交。
一旦运行git add README.txt
,它将复制(并压缩)工作树版本到:README.txt
中。现在,这两个匹配,但是HEAD:README.txt
和:README.txt
不同。因此,git status
将HEAD
与索引进行比较,并说文件已被暂存以提交。
请注意,您可以再次更改工作树副本。现在,文件在所有三个版本中都不同,并且git status
告诉您,文件都是为提交而准备的(HEAD和索引不匹配),也不是为提交而准备的(索引和工作-树也不匹配)。这全部基于两个git diff
的结果:一个从HEAD
到索引,一个从索引到工作树。
但是,如果您有一个HEAD
提交中的文件,您从索引和工作树中删除了,该怎么办?好吧,现在比较HEAD
与索引时,已将其删除。因此,Git表示已执行删除操作。索引和工作树匹配,因此Git对此一无所知。无论如何,您的下一次提交不会拥有文件。
如果您的文件在工作树中但不在索引中,该怎么办?如果它在HEAD
提交中,则它仍是分阶段删除:文件不会在下一个提交中。但这在索引和工作树中也有所不同,因此它是未跟踪的。
如果文件不在HEAD
中,并且不在索引中,但是在工作树中,则说明该文件为未跟踪。
这告诉我们拥有一个未跟踪文件的含义:当且仅当该文件当前不在索引 中时,该文件才被跟踪。由于您可以操纵索引(随时随地添加或删除文件),因此可以随时将其添加到索引中或从索引中删除,从而随时更改某些文件的跟踪性。索引。
如果文件不在索引中并且不在工作树中,则该文件不存在。只是 在工作树中,而不是在索引中的文件是未跟踪的。您可以git add
进行文件操作,然后Git对您发牢骚,,不休。在.gitignore
(或.git/info/exclude
)中列出文件主要是关闭Git up 。它实际上不会导致文件被取消跟踪,这与文件是否在索引中有关。文件进入索引后,便会对其进行跟踪,并且.gitignore
无效。它只是防止git status
困扰您。因此,也许应该是.gitignore
而不是.git-dont-complain-about-these-files-if-they-are-untracked
。
它还有另一个重要作用。您可以运行git add .
或git add somedir
或git add --all
来基于Git搜索目录/文件夹中的整个文件列表来添加一堆文件。如果您将某些文件列出为忽略文件,则git add
将跳过它们(如果尚未跟踪)。也就是说,跟踪的文件肯定在Git中,因此git add
会在更改后将其复制到索引中。但是未跟踪的文件还不在Git中,因此如果不忽略该文件,则会进行en-masse添加。在这里,“忽略”是正确的词。因此,也许该文件应命名为.git-dont-complain-about-these-files-if-they-are-untracked-and-dont-auto-add-them-with-an-en-masse-add-operation
。
不幸的是,在.gitignore
中列出文件还有另一个副作用,那就是告诉Git在某些情况下删除或破坏文件是可以的。因此,.gitignore
的全名可能为.git-dont-complain-about-these-files-if-they-are-untracked-and-dont-auto-add-them-with-an-en-masse-add-operation-but-do-feel-free-to-clobber-these-files-sometimes
。想象一下,如果那是文件名!至少不会那么混乱。
git rm --cached
删除文件的缺点如上所述,如果要使某些文件不被跟踪,则必须将其从索引中删除。如果您使用git rm --cached filename
,Git将从索引中删除该文件(因此现在未对其进行跟踪),但是 not 从工作树中删除该文件(因此仍然可以在其中使用该文件)它)。您的下一个提交不会拥有您想要的文件。
但是所有 old 提交,永久冻结的时间提交, do 都有文件...所有那些旧提交仍然存在。如果您检出了其中一项提交,Git将不得不将冻结的文件复制到索引中,然后将索引副本复制到工作树中。那会破坏您的工作树版本。那样行吗? Git的答案是检查.gitignore
中的文件!
如果.gitignore
中未列出文件 ,Git将无法随意对其进行破坏。但是您会抱怨它没有被追踪。为解决这些投诉,您可能会在.gitignore
中列出文件。然后,签出旧提交将使用提取的,未冻结的,未压缩的文件破坏您的文件,然后回到新的提交将删除文件,因为它们现在与冻结的文件相同一个,所以它是“安全的”。
Git需要(但没有)一种方法来列出工作树文件,因为对此进行了关闭,但从不破坏。如果以及何时添加,将使您处理自己的情况。但是,如果可能的话,最好不要完全陷入困境。
同时,如果您做丢失文件,请记住至少在旧的冻结提交中有一些版本。您可以提取那些旧的冻结版本。有两种方法可以做到这一点:
git show
:运行git show commit:path
,例如git show v1.0:README.txt
或git show a123456:path/to/file.ext
。这样会将冻结的保存文件扩展为标准输出,因此您可以使用I / O重定向保存它,例如git show v1.0:README.txt > README.txt.old
。
git checkout
具有一种模式,在该模式下,它不检出整个提交,而是从一些现有提交中填充索引和工作树的 part 。 (此命令可能永远不应该被称为git checkout
,因为如果您尚未保存更改,它会具有破坏性,请谨慎操作。)运行git checkout v1.0 -- README.txt
或git checkout a123456 -- path/to/file.ext
将从中提取命名文件。命名的提交,将其复制(解冻)到索引中-因此现在您的下一个提交将具有那个文件的那个版本-然后进入您的工作树。 / p>
如果您要恢复文件的整个目录,或者使用*.jar
之类的全局模式,则此功能更有用,因为您可以git checkout
的目录或模式:
git checkout HEAD~2 -- '*.jar'
此处HEAD~2
是要使用的提交(沿第一父级链从当前提交向后退了两步),还有*.jar
,如果有任何引用,则需要引用以保护它不受shell攻击当前目录中的*.jar
个文件是Git应该匹配的 pathspec 。 (我认为这应该等效于**/*.jar
,但如果不是,那也是有效的pathspec。)由于这会填充您的索引,因此您之后必须撤消该索引,例如再次git rm --cached
或{ {1}}(它也需要路径说明,因此可以git reset
)。
这些冻结的文件是否足以满足您的当前情况,当然取决于情况。