使用 .gitignore 和 .git/info/exclude 的步骤

Steps to use .gitignore and .git/info/exclude

我无法理解如何使用和写入 .gitignore、.git/config 文件和 .git/info/exclude 文件。

我已经通读了 this post and this documentation 但它就是不适合我。

我的理解是: - .gitignore 用于将文件推送到 git hub。
- 使用 .git/info/exclude 防止文件或文件夹被推送到 git 中心。因此,您可以在这里隐藏 API 密钥之类的秘密,或者将不需要放在 git 中心但只需放在我的机器上进行深度学习训练的大型照片文件夹。
这不准确吗?

如何使用命令行或 git bash 写入 .gitignore 或 .git/info/exclude 文件?我已经尝试过多次尝试语法,但现在不知所措。而且我也不知道如何通过jupyter界面打开它们。

.gitignore 文件中包含的文件和文件夹未在 git 中跟踪,因此不会推送到 GitHub。

如果我想 git 忽略一个文件,我的 .gitignore 看起来像这样:

file_to_ignore.txt

您也可以忽略文件夹:

folder_to_ignore/

如果我希望 git 忽略除文件之外的所有内容,我的 .gitignore 将如下所示:

*
!file_to_include.txt

*是通配符,表示一切! 表示 忽略此 file/folder.

my understanding is that:

  • .gitignore is to be used when you are okay with the file being pushed to git hub.
  • use .git/info/exclude to keep files or folders from being pushed to git hub. [snip]

Is this not accurate?

这不准确。假设您了解 untracked file 的含义:.gitignore.git/info/exclude 都为您做的是防止 accidentally 跟踪一个文件,并停止 Git 对未跟踪文件的抱怨。差不多就是这样。一旦文件被 跟踪.gitignore.git/info/exclude 文件就不再影响它。

不过,文件可能会在不同时间被跟踪和取消跟踪。这里有很多知识。

未跟踪的文件

短语未跟踪的文件在Git中有非常特殊的含义。我会在此处指向 gitglossary,但不幸的是 未跟踪文件 未在此处定义(!)。所以,我将使用我自己的定义:

  • 未跟踪文件
    未跟踪的文件是 现在在工作树中 ,但现在 不在索引中 的任何文件。

稍后我们会回到为什么我说 现在 两次。不过,首先,这又使用了两个术语,indexworking tree,这次 are 已定义在 gitglossary:

  • index
    A collection of files with stat information, whose contents are stored as objects. The index is a stored version of your working tree. ...

  • working tree
    The tree of actual checked out files. The working tree normally contains the contents of the HEAD commit’s tree, plus any local changes that you have made but not yet committed.

要在脑海中清楚地了解所有这一切,请从以下内容开始:Git 存储库主要由两个数据库组成。一个保存所有提交和其他 Git objects(本质上,提交所需的其余内容:文件名和文件内容)。另一个数据库通常要小得多,用于保存您的 b运行ch 和标签名称以及其他此类名称。较小的数据库将名称映射到哈希 ID。

您将在 git log 输出中看到哈希 ID:

commit 745f6812895b31c02b29bdfe4ae8e5498f776c26
Author: Junio C Hamano ...

(此特定提交位于 Git 的 Git 存储库中,您可以从 http://github.com/git/git/ if you like. Here is that commit 克隆它;如果您克隆存储库,您将拥有此提交。)

每个 Git 对象都有自己的哈希 ID。每个提交都有一个哈希 ID,该哈希 ID 对于该特定提交是唯一的。该哈希 ID 永远不能用于任何其他提交。每个其他提交都有自己的 不同 哈希 ID。 b运行ch 名称,如 master,包含一 (1) 个哈希 ID,并向 b运行ch 添加提交,Git 填充 哈希 ID 到名称 master 中,因此 b运行ch 名称会随着时间的推移改变它们所指的哈希 ID。

同时,每次提交的哈希 ID 都是完全静态和永久的。提交 745f6812895b31c02b29bdfe4ae8e5498f776c26 后,提交 745f6812895b31c02b29bdfe4ae8e5498f776c26 始终是 that 提交。您要么在 all-Git-objects 的数据库中拥有它,然后 that 提交,要么根本没有。此提交的任何内容都永远 无法更改。你要么拥有它,然后它与我上面链接的 745f6812895b31c02b29bdfe4ae8e5498f776c26 完全相同,要么你没有它。

现在,提交 包含 个文件——作为一个完整的快照——所以如果你有那个特定的提交,你就拥有所有这些文件。但是 any 提交中的文件采用特殊的 read-only / 冻结的 Git-only 格式。我喜欢称它们为“freeze-dried”。这些 freeze-dried 个文件可以随时重组,但解冻和复水的文件只是 。原件仍在原始提交中。1

这意味着提交非常适合存档——它们会永久保留每个文件的每个版本的副本——但它们对于实际完成任何新工作毫无用处。您必须重构文件才能使用它们,为此,Git将重构的文件放入您的工作树,或 work-tree,或这些行中的任何名称。


1从技术上讲,它们位于附加的 Git 对象中,提交仅指向这些对象。 Git 正在逐渐获得一个可以加载它们的系统 on-demand 而不是要求提交与其所有依赖项一起出现,所以有一天你将能够在没有文件的情况下进行提交也。但是现在它们还不如直接在提交中,除了提交可以 share 文件的 freeze-dried 副本这一事实,如果它们没有从一次提交中更改的话给另一个。


指数

上面定义的工作树或 work-tree 非常简单:Git 的 permanently-saved 版本的文件位于特殊的 read-only、Git-only 格式,因此 Git 必须将它们扩展为普通的、有用的文件,并将它们放在您可以看到和使用它们的区域。这实际上是几乎每个版本控制系统所做的事情。大多数只是到此为止——如果还有其他内容,VCS 会将其隐藏起来。 Git 与其他版本控制系统不同。 Git 添加这个叫做 index 的东西,然后立即将它推到你的脸上。

索引也被称为暂存区,或者有时——现在很少——缓存。这些只是同一事物的三个名称。正如 gitglossary 所说,它是一个文件集合。事实上,最初,它是来自您签出的提交的文件

git checkout master

名称 master 是一个 b运行ch 名称,因此 Git 在其第一个数据库(名称到哈希 ID)中查找提交哈希 ID。结帐将您置于 b运行ch master 并提取该提交——无论它的哈希 ID 是什么——这样您就可以在 work-tree 中拥有它的所有文件。这个提取过程显然要做:

  • 从提交中读取
  • 解压/un-freeze/写入work-tree

如果 Git 像其他系统一样做到这一点 - Git 可以使用您的 work-tree,无论您对它进行什么更改,就像您提议的 next 提交。当您 运行 git commit、Git 将不得不查看您的 work-tree、re-compress 所有内容,并查看它是否与上次提交相比发生了变化。但是,Git 这样做:

  • 从提交中读取
  • write (frozen format, really hash ID) to index / staging-area
  • 解压/un-freeze/写入work-tree

现在当你 运行 git commit Git 可以 忽略 你的 work-tree 并且直接 re-freeze索引。如果您对 work-tree 进行了任何更改,您 必须 运行:

git add whatever-file

告诉Git:从work-tree中提取whatever-file并将其压缩为freeze-dried形式并将其放入索引中,准备提交.

换句话说,不是你的 work-tree 是你提议的下一次提交,实际上你的 index 是你提议的下一次提交。 您可以在 work-tree 中更改任何内容,而不会影响您的下一次提交,因为索引 / staging-area 中的内容才是最重要的。

索引和您的work-tree都是per-repository临时区域

在 Git 中,真正重要的是提交。所有提交(及其文件)的大数据库是 Git 彼此之间的交换。较小的数据库,名称如 b运行ch 和标签名称—Gits use 用于相互发送提交,Gits 将互相发送他们的名字(如果你愿意,你可以覆盖)这样另一个 Git 可以使用这个名字,如果它喜欢的话,来记住提交。但重要的是提交。

你的work-tree是你的,随心所欲。 Git 并没有真正使用它,除了一些例外:

  • git checkout 从提交复制到索引,然后是您的 work-tree。 (它有其他模式可以做更多的事情。在某些方面,它有太多模式,这就是为什么在 Git 2.23 中有 两个 命令,放在一起,可以做 git checkout 可以在一条命令中完成的所有事情。)
  • git reset 从提交复制到索引(有时也复制到 work-tree)。 (与 git checkout 一样,它可以做很多事情——也许太多了。)
  • git add 从您的 work-tree 复制到索引。
  • git status看着你的work-tree。它首先查看当前提交,然后查看索引,然后查看您的 work-tree.

正是在这最后两个命令——git addgit status——.gitignore 和朋友开始变得有用。但是让我们再提一个命令:

  • git rm 从索引 您的 work-tree 中删除文件。它有一种模式,它只从索引中删除,单独留下 work-tree 文件。

当您 运行 git commit、Git 将索引内容打包成一个新的快照——一个新的提交——然后成为 current 提交,所以现在提交和索引再次匹配。 work-tree 在此过程中没有改变:如果它曾经匹配索引,它仍然匹配;如果它与索引不匹配,它仍然不匹配。

因此,索引是一个临时区域,您可以在其中构建 next 提交,方法是根据需要将文件暂存到其中。您没有显式暂存但由于先前提交而已经在索引中的所有文件,仍然存在。他们进入新快照。

跟踪/未跟踪如何与 git addgit status

一起工作

git status 所做的——好吧,它所做的很大一部分,以及我们在这里关心的所有事情——是 运行 two git diffs 实际上是 --name-status 选项,然后以更有用的形式显示结果:

  • 第一个差异将当前提交与索引进行比较。 一样,Git什么都不说。对于每个 不同 的文件,Git 告诉您 staged for commit。因此,索引中的 updated 文件现在与其 HEAD 版本不同,被称为 staged。 Git 对其他文件保持沉默。

  • 第二个diff比较将索引 — ready-to-be-committed、暂存文件 — 添加到 work-tree。 一样,Git什么都不说。对于每个 不同 的文件,Git 告诉您 not staged for commit。 work-tree 中的更新文件现在不同于 ready-to-commit 分阶段副本,称为 未分阶段

但是您 work-tree 中的文件 可能 现在 不在索引中 。他们是怎么到那里的?好吧,当你 运行 git checkout 时,Git 填写了你的索引——你的暂存区。如果名为 foo.config 的文件不在提交中,那么它也不在索引中。如果它没有写入索引,它也不会写入您的 work-tree。但也许 你 运行 在你的 work-tree 中创建的东西。也许您甚至使用过它。所以现在它就在那里,在你的 work-tree 中,但不在你的索引中。

git status所做的就是投诉这个文件。它会说:未跟踪文件。如果你想让git status闭嘴这个文件,你可以把它列在.gitignore.git/info/exclude里,git status 不会抱怨。

这对 foo.config 是否在索引中没有影响。我们已经说过它 不在索引中 ,所以当 git status 没有抱怨时它仍然不在索引中。但这仍然留下 git add。如果你 运行:

git add foo.config

你告诉 Git: freeze-dry work-tree 复制并将其放入索引中。 如果你这样做没有任何.gitignore 或类似的,Git 将服从,并且 foo.config 现在将 您的索引中。

如果它不在当前提交中,git status 也会告诉您它是新添加的并准备提交(准备提交)。它就在那里,在索引中,所以它在下一次提交中。

如果您不希望它在下一次提交中,您必须从索引中删除它:

git rm foo.config

现在它已经从您的 work-tree 的索引 中消失了。如果您不希望它从您的 work-tree 中消失,请使用:

git rm --cached foo.config

现在它已从索引中消失,但仍在您的 work-tree 中,现在 git status 会抱怨它为 未跟踪。您可以将它添加到 .gitignoreexclude 文件中,以停止抱怨。

将其添加到排除文件而未跟踪(即不在索引中,但在 work-tree 中)还有另一个有益的副作用。除了上面那种git add,你还可以:

git add .

或:

git add *

添加一大堆文件en-masse。如果 foo.config 当前未被跟踪(即不在索引中但在 work-tree 中),并且 git add 遇到添加它的尝试,git add 默认不会添加。所以它将保持未跟踪状态。

但是请注意,如果您以任何方式强制文件进入索引,例如,通过执行 git checkout 的提交, 执行 里面有 foo.config——文件现在是 tracked,因为它在索引 中。索引中的文件——不管它是怎样得到的——都会被跟踪。不在索引中的文件——不管它是怎样得到的——是未跟踪的。

综合起来

... hide secrets like API keys or put large folders of photos that do not need to be in git hub ...

当您 git push 到 GitHub 时,您发送它 提交 。无论这些提交中有什么快照,请转到 GitHub。如果你想确保 secret.keybig.file 不去,你需要确保它们不进入索引,因此不进入任何新的提交。

为了防止它们进入索引,它们应该开始——不在索引中,也不在任何现有的中提交,这将使他们 进入 git checkout 上的索引。如果他们已经进行了一些这样的提交,您可以避免这些提交,或者——但这有点困难——努力工作并实际上摆脱这些提交——但如果你不这样做,你就处于良好状态从.

开始

为了避免不小心将文件放入索引并因此放入新的提交中,只需在中列出两个文件名或两者 .gitignore.git/info/exclude。如果将名称放入 .gitignore,则可以 git add .gitignore 并进行新的提交。从现在开始,那个 .gitignore 就在那个提交中,并且在你从 那个提交做的每一个额外的新提交中被复制到索引中。因此 secret.keybig.file 这两个名称不会 意外地 进入索引,因此不会意外地进入新的提交。

不需要 做这些中的任何一个。您 要做的就是确保没有 new 提交为这些文件制作快照。新的提交从索引创建快照,所以你只需要确保你不会不小心将 secret.key and/or big.file 复制到索引中。

如果出于某种原因你真的想要在某些提交中使用它们,你 可以 这样做,但现在你必须确保你永远不会发送 那些 提交——那些有 secret.keybig.file 快照的提交——永远不会去 Git中心。这有点难。如果您想要 version-control 它们,最好将这些文件放在单独的存储库中。

dot-files、.gitignore.git/info/exclude,实际上是关于:

  • 保留当前未跟踪的文件,将来也未跟踪
  • 无需仔细/手工操作
  • 没有git status抱怨他们

.gitignore文件本身可以放在索引中,这样每次commit snapshot中都有副本。由于新克隆使用原始提交,因此新克隆具有这些提交。 .git/info/exclude 文件不能放在索引中,因此在任何快照中都没有该文件的副本,新克隆也不会有它。

.gitignoreinfo/exclude 之间的主要区别在于第一个是版本化的,可以与其他文件一起签入和签出。因为它在多个存储库中是持久的。

info/exclude 不受版本控制,仅影响单个存储库。您需要将其物理复制到另一个存储库才能在那里产生效果。

这两个文件都用于防止git 跟踪但未跟踪 文件。它们不会影响已经提交的文件。

core.excludeFile 是另一种可能指定系统范围忽略文件的机制。

文档指定了 git 考虑文件的顺序:.gitingore,info/exlude,然后是 core.excludeFile。

当您需要文件时,可以构建示例,它在与源文件相同的工作树中生成 .o 文件。他们 *.o 模式可以放在任何这些文件中。它将使大多数 git 命令忘记这些文件的存在。它们不会在 'git status' 中列出,也不会被 'git add' 添加。

因此,这些文件只能用于防止将 未跟踪 文件添加到本地 git 存储库中。但是一旦您设法提交未跟踪的文件,就不会阻止它们被推送。