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