我的理解是:
- 当您对推送到 git hub 的文件没有问题时,将使用 .gitignore。
- 使用 .git/info/exclude 防止文件或文件夹被推送到 git hub。[剪辑]
这不准确吗?
这是不准确的。假设您了解未跟踪文件的含义:两者.gitignore都.git/info/exclude为您做的是防止意外跟踪文件,并让 Git 停止抱怨未跟踪文件。差不多就是这样。跟踪文件后,.gitignore和.git/info/exclude文件不再影响它。
但是,文件可以在不同时间被跟踪和不被跟踪。这里有很多要知道的。
未跟踪的文件
短语untracked file在 Git 中具有非常特殊的含义。我会在此处指向gitglossary,但不幸的是未在此处定义未跟踪的文件(!)。所以,我将使用我自己的定义:
- 未跟踪的文件
未跟踪的文件是目前在工作树中但现在不在索引中的任何文件。
我们稍后会回到我现在说两次的原因。不过,首先,这使用了另外两个术语,索引和工作树,这一次是在gitglossary中定义的:
要在脑海中全面了解这一切,请从以下内容开始:Git 存储库主要由两个数据库组成。一个包含你所有的提交和其他 Git对象(本质上,提交所需的其余东西:文件名和文件内容)。另一个数据库,通常要小得多,保存您的分支和标签名称以及其他此类名称。较小的数据库将名称映射到哈希 ID。
您将在git log输出中看到哈希 ID:
commit 745f6812895b31c02b29bdfe4ae8e5498f776c26
Author: Junio C Hamano ...
(这个特定的提交位于 Git 的 Git 存储库中,如果您愿意 ,可以从http://github.com/git/git/克隆它。这是该提交;如果您克隆存储库,您将拥有此提交。 )
每个 Git 对象都有自己的哈希 ID。每个提交都有一个哈希 ID,该哈希 ID 对于该特定提交是唯一的。该哈希 ID 永远不能用于任何其他提交。每个其他提交都有自己的不同哈希 ID。一个分支名称,如master,拥有一 (1) 个哈希 ID,并且为了向分支添加提交,Git 将一个新的哈希 ID 填充到 namemaster中,因此分支名称会随着时间的推移改变它们所指的哈希 ID。
同时,每个提交的哈希 ID 是完全静态和永久的。一旦你有了 commit 745f6812895b31c02b29bdfe4ae8e5498f776c26, commit745f6812895b31c02b29bdfe4ae8e5498f776c26就是那个commit。你要么在你的所有 Git 对象的数据库中拥有它,然后它就是那个提交,或者你根本没有它。关于此提交的任何内容都无法更改。你要么拥有它,然后它与我上面链接的完全相同745f6812895b31c02b29bdfe4ae8e5498f776c26,要么你没有它。
现在,提交包含文件——作为一个完整的快照——所以如果你有那个特定的提交,你就会拥有所有这些文件。但是任何提交中的文件都是特殊的、只读的/冻结的、仅限 Git 的格式。我喜欢称它们为“冻干”。这些冻干的文件可以随时重组,但解冻和再水化的文件只是副本。原件仍在原始提交中。1
这意味着提交非常适合存档——它们永远保留每个文件的每个版本的副本——但它们对于实际完成任何新工作完全没有用。您必须重新构建文件才能使用它们,为此,Git 将重新构建的文件放入您的工作树或工作树或任何类似这些行的名称中。
1从技术上讲,它们位于其他 Git 对象中,提交仅指向这些对象。Git 正在逐渐获得一个系统,通过该系统可以按需加载它们,而不是要求提交连同它的所有依赖项一起出现,所以有一天你将能够在没有文件的情况下进行提交。但是现在它们还不如直接在提交中,除非提交可以共享文件的冻干副本,如果它们没有从一个提交更改为另一个。
指数
上面定义的工作树或工作树非常简单:Git 永久保存的文件版本是一种特殊的、只读的、仅限 Git 的格式,因此 Git 必须将它们扩展为普通、有用的文件,并且将它们放在您可以看到它们并与它们一起工作的区域。这实际上是几乎每个版本控制系统都会做的事情。大多数只是停在这里——如果还有什么,VCS 会将其隐藏起来。Git 不像其他版本控制系统。Git 添加了它称为index的东西,然后迅速将它推到你的脸上。
该索引也称为暂存区,或者有时——现在很少见——缓存。这些只是同一事物的三个名称。正如gitglossary所说,它是文件的集合。事实上,最初,它是您签出的提交中的文件:
git checkout master
该名称master是一个分支名称,因此 Git 在其第一个数据库(名称到哈希 ID)中查找提交哈希 ID。结帐会将您置于分支master并提取该提交(无论其哈希 ID 是什么),以便您将其所有文件都放在工作树中。这个提取过程显然要做:
如果 Git 这样做——就像其他系统一样——Git 可以使用你的工作树,无论你对它做出什么改变,作为你提议的下一次提交。当您运行时git commit,Git 必须查看您的工作树,重新压缩所有内容,并查看它是否与之前的提交相比发生了变化。但相反,Git 这样做:
- 从提交中读取
- 写入(冻结格式,真正的哈希 ID)到索引/暂存区
- 解压缩/解冻/写入工作树
现在,当您运行git commitGit 时,可以忽略您的工作树并直接从索引中重新冻结。如果您在工作树中进行了任何更改,则必须运行:
git add whatever-file
告诉 Git:从工作树中取出任何文件并将其压缩为冻干形式并将其放入索引中,准备提交。
换句话说,不是你的工作树是你提议的下一次提交,实际上你的索引是你提议的下一次提交。 您可以在工作树中更改您想要的任何内容,而不会影响您的下一次提交,因为重要的是您的索引/暂存区域中的内容。
索引和您的工作树都是每个存储库的临时区域
在 Git 中真正重要的是提交。包含所有提交(及其文件)的大数据库是 Gits 相互交换的内容。较小的数据库,名称如分支和标签名称——Git使用它来相互发送提交,Git 将相互发送它们的名称(如果你愿意,你可以覆盖它),以便另一个 Git 可以使用该名称,如果它喜欢,记住提交。但重要的是提交。
你的工作树是你的,随你的便。Git 并没有真正使用它,但有一些例外:
git checkout从提交复制到索引,然后复制到您的工作树。(它还有其他模式可以做更多的事情。在某些方面,它有太多的模式,这就是为什么在 Git 2.23 中有两个命令,放在一起,可以git checkout在一个命令中完成所有可以做的事情。)
git reset从提交复制到索引(有时也复制到工作树)。(比如git checkout,它可以做很多事情——也许太多了。)
git add从您的工作树复制到索引。
git status 看着你的工作树。它首先查看当前提交,然后查看索引,然后查看您的工作树。
正是在这最后两个命令——<code>git add 和git status——.gitignore和朋友们开始变得有用。但是让我们再提一个命令:
git rm从索引和工作树中删除文件。它有一种模式,它只从索引中删除,不理会工作树文件。
当你运行时git commit,Git 将索引内容打包到一个新的快照中——一个新的提交——然后它成为当前的提交,所以现在提交和索引再次匹配。在这个过程中工作树不会改变:如果它曾经匹配索引,它仍然会;如果它不匹配索引,它仍然不匹配。
因此,索引是您构建下一次提交的临时区域,通过根据需要将文件暂存到其中。您没有明确暂存但由于先前提交而已经在索引中的所有文件仍然存在。他们进入新的快照。
跟踪/未跟踪如何与git add和git status
做什么git status——嗯,它所做的很大一部分,以及我们在这里关心的所有事情——是运行两个 git diff,实际上是--name-status选项,然后以更有用的形式显示结果:
第一个差异将当前提交与索引进行比较。无论是相同的,Git 什么都没说。对于每个不同的文件,Git 都会告诉你staged for commit。因此,索引中的更新文件(现在与其HEAD版本不同)称为staged。Git 对其他文件保持沉默。
第二个差异将索引(准备提交的暂存文件)与工作树进行比较。无论是相同的,Git 什么都没说。对于每个不同的文件,Git 都会告诉你not staged for commit。因此,工作树中的更新文件,现在不同于它们准备提交的分阶段副本,被称为not staged。
但是你可以在你的工作树中拥有现在不在你的索引中的文件。他们是怎么到那里的?好吧,当你运行. 如果提交中不存在名为的文件,则索引中不存在该文件。如果它没有被写入索引,它也没有被写入你的工作树。但也许你运行的东西在你的工作树中创建了它。也许你甚至使用它。所以现在它在你的工作树中,但不在你的索引中。git checkoutfoo.config
git status会做的是抱怨这个文件。它会说:未跟踪的文件。如果你想git status对这个文件闭嘴,你可以将它列在 a.gitignore或 a.git/info/exclude中,并且git status 不会抱怨。
这对是否foo.config在索引中没有影响。我们已经说过它不在git status索引中,所以在不抱怨时它仍然不在索引中。但那仍然离开git add。如果你运行:
git add foo.config
您是在告诉 Git:冻干工作树副本并将其放入索引中。 如果你在没有任何.gitignore或类似的情况下这样做,Git 将服从,foo.config现在将在你的索引中。
如果它不在当前提交中,git status它会告诉你它是新添加的并且准备好提交(暂存提交)。它在那里,在索引中,所以它将在下一次提交中。
如果您不希望它出现在下一次提交中,则必须将其从索引中删除:
git rm foo.config
现在它已经从索引和你的工作树中消失了。如果您不希望它从您的工作树中消失,请使用:
git rm --cached foo.config
现在它已经从索引中消失了,但仍在你的工作树中,现在git status会抱怨它为untracked。您可以将其添加到.gitignore或exclude文件中,以停止抱怨。
在未跟踪的情况下将其添加到排除文件(即,不在索引中,而是在工作树中)还有另一个有益的副作用。除了上述类型git add,您还可以执行以下操作:
git add .
或者:
git add *
添加一大堆文件。如果foo.config当前未跟踪(即,不在索引中,而是在工作树中),并且git add尝试添加它,git add 则默认情况下不会添加它。因此它将保持未跟踪状态。
但是请注意,如果您以任何方式将文件强制放入索引中(例如,通过执行git checkout其中包含的提交),则foo.config该文件现在会被跟踪,因为它在 index 中。跟踪索引中的文件(无论它以何种方式出现)。一个不在索引中的文件——不管它是如何得到的——是未被跟踪的。
把它们放在一起
...隐藏 API 密钥之类的秘密或将不需要放在 git hub 中的大型照片文件夹...
当你git push到 GitHub 时,你发送它commits。无论这些提交中的快照是什么,请转到 GitHub。如果你想确定secret.key并且big.file不去,你需要确保它们不进入索引,因此不要进入任何新的提交。
为了防止它们进入索引,它们应该以这种方式开始——不是在索引中,也不是在任何现有的提交中,这会使它们进入a 上的索引git checkout。如果他们已经在一些这样的提交中,你可以避免这些提交,或者——但这有点困难——努力工作并真正摆脱这些提交——但如果你不这样做,你就可以很好地从...开始。
为避免意外将文件放入索引并因此放入新提交,只需在a或 a中的一个或两个中列出两个文件名。如果将名称放入 a中,则可以进行新的提交。从现在开始,它就在那个提交中,并且会从那个提交中复制到索引中,以用于您从该提交中做出的每一个新的提交。所以这两个名字不会意外进入索引,因此也不会意外进入新的提交。.gitignore.git/info/exclude.gitignoregit add .gitignore.gitignoresecret.keybig.file
您不必执行其中任何一项。您所要做的就是确保没有新的提交生成这些文件的快照。新提交会从索引生成快照,因此您只需确保不会意外复制secret.key和/或big.file进入索引。
如果出于某种原因你真的想要某些提交中的那些,你可以这样做,但现在你必须确保你永远不会发送那些提交——那些有快照的提交——永远不要secret.key去big.fileGitHub。这有点难。如果您想对它们进行版本控制,最好将这些文件放在单独的存储库中。
点文件.gitignore和.git/info/exclude,实际上是关于:
- 保留当前未跟踪的文件,将来也未跟踪
- 无需仔细/手动
- 不
git status抱怨他们
.gitignore文件本身可以放在索引中,这样每个提交快照中都有副本。由于新克隆使用原始提交,因此新克隆具有这些提交。该.git/info/exclude文件无法放入索引中,因此在任何快照中都没有该文件的副本,并且新克隆将没有它。