首页 > 解决方案 > .gitignore 应该放在 React-Native expo 应用程序的什么位置?

问题描述

enter code here该目录如下所示:

> Repo
    LICENSE
    README.md
    .gitignore
    > App
        'contents of application all in here'
        .gitignore

我们的 .gitignore 文件来自这里https://github.com/expo/expo/blob/master/.gitignore

不确定将 .gitignore 文件放在哪里,因为在我使用过的所有项目中,它们都直接位于 repo 文件夹中,但是 .gitignore 不需要在列出的所有文件前面有 App/_____ ?

谢谢

标签: gitreact-nativegithubexpo

解决方案


TL;博士

没有唯一的正确答案。将条目放在最适合的地方。

无论应用程序如何,规则.gitignore都是一致的(尽管相当复杂)。您将需要了解排除文件中每个条目的语法和语义,但首先,在您了解这一点之前,您必须了解在 Git 中要跟踪文件与未跟踪文件的含义,因为排除条目适用于未跟踪的文件。

跟踪文件是 Git 索引中的文件

跟踪文件的定义很简单,但很微妙。跟踪文件是当前位于 Git 索引中的任何文件。这里的微妙之处在于理解 Git 的索引。这什么东西?什么是“指数”?为什么 Git 给它起三个名字,叫它索引,或者——现在越来越常见——暂存区,或者——现在越来越少——缓存

索引:背景

索引,或暂存区,是 Git 向你隐藏了一段时间的 Git 的一部分——没有简单的方法可以直接看到它——但是,为了将 Git 拟人化,1 Git 随机跳出来打你一记耳光用它的索引,就好像你在这个 Monty Python 草图中一样。所以你需要了解它。

索引本身非常复杂,但使用它的方式非常简单:在其中暂存文件。这就是为什么它现在被更一致地称为暂存区的原因。但这仍然留下一个明显的问题:暂存文件意味着什么? 要回答这个问题,我们需要考虑什么是 Git提交


1不要将计算机拟人化。他们讨厌那样。


提交

Git 提交是:

  • 编号:每个提交都有一个唯一的哈希 ID,一个看起来很丑的随机数字,几乎总是用十六进制数字表示。这个哈希 ID 实际上是提交的完整内容的加密校验和2,这意味着提交内容字面上无法更改:如果您取出提交,进行一些更改,然后将结果放回去,您得到的是具有新的唯一哈希 ID 的提交;旧的提交仍然存在,具有旧的哈希 ID。

  • 贮存:

    • 每次提交都会以特殊的、只读的、仅限 Git 的格式存储所有源文件的完整快照,并进行压缩和重复数据删除。

    • 每个提交还存储一些元数据,或有关提交本身的信息。这包括诸如谁制作它以及何时制作之类的东西。

基于散列的编号系统具有已知的加密散列函数,这意味着宇宙中的每个 Git 都同意任何特定提交获得的散列 ID。这就是 Git 如何成为分布式版本控制系统的原因。两个不同的 Git 存储库可以通过检查哈希 ID 来判断另一个是否具有相同的提交。这不是我们在这里关心的,但这就是为什么提交是它们的方式,所以了解它很有用。


2密码学部分让人想起加密货币的区块链,尽管 Git 今天使用的密码学功能太弱了。Git 仅将其部分用于其Merkle 树属性;哈希具有良好熵的事实是最重要的方面。


工作树

在任何情况下,提交中的文件实际上不能被 Git 使用,这意味着要处理 / 提交,我们必须让 Git提取提交。我们让 Git 将此提交提取到我们的工作树中。

工作树保存从某个提交中提取的文件。如果我们切换到不同的提交,Git 将删除这些文件,并从其他提交中提取文件。

好吧,好吧,那又怎样?好吧,假设我们的系统——不管它是什么——需要“编译”或以其他方式处理文件。我们使用常规的 JavaScript 或 Typescript 并将这些文件转换为缩小文件,或者我们使用 Python 代码并将其字节编译为文件,*.pyc或者*.pyo我们使用 C 或 C++ 代码并将其编译为*.o目标文件,或其他任何东西。

这些构建工件 进入工作树。但他们不应该进行新的提交。有很多方法可以处理这个问题,但 Git 选择了一种奇怪的方法。

索引,第 2 部分:它作为暂存区的作用

Git 处理哪些文件进入新提交,哪些文件不进入新提交的想法的方式是在其索引(即暂存区)中保留每个要提交的文件的单独副本。这些额外的副本采用 Git 的内部形式,经过压缩和重复数据删除,可以提交。因为它们是重复数据删除的,所以从提交中出来的文件实际上不占用空间。3

Git 处理这个问题的方式是,当你第一次签出一些提交时,Git 不只是填写你的工作树。Git 会填充您工作树及其索引。所以索引和你的工作树现在匹配了。

当你做你的工作时,你会改变一些工作树文件。正如你所做的那样——以及你选择何时——Git 要求你git add在这些更新的文件上运行。此步骤读取并压缩工作树文件。Git 现在检查压缩版本是否是任何文件的任何先前版本的副本,如果是,则简单地重新使用旧文件。如果没有,Git 会准备好提交的内容。无论哪种方式,Git 现在都会更新索引条目以记录新的或重用的内容。

这意味着该索引始终包含您提议的下一次提交不在索引中的文件不在您提议的 next commit中。来自当前提交的文件,在git checkoutgit switch时间,索引中,除非您已删除或替换它们:这些文件在下一次提交中,除非您已删除或替换它们,但它们将是相同的内容作为当前提交(除非您已删除或替换它们),因此它们不会占用空间。

通过这种方式,索引始终保持您提议的下一次提交。它包含“暂存于提交”的所有文件。

git status命令将告诉您任何与当前提交中的文件不同的暂存提交文件。不会告诉您与当前提交匹配的暂存文件,因为这通常并不有趣。因此,如果您有 3000 个文件准备提交,并且其中两个不同,git status则告诉您有两个文件staged for commit。你实际上有 3000 个文件;只是他们两个不同,剩下的2998是一样的

  • 练习:如果git status告诉你所有 3000 个文件,你会如何找到有趣的两个?

请注意,使用git commit -a大致意味着4

  • run git add -u:这会扫描所有现有的索引(暂存)文件,以查看是否有任何工作树版本较新,如果是,则git add在它们上运行;
  • 然后运行git commit

这种-a标志可以让您暂时忽略索引。但是,过多地忽略它是错误的。我将在下一节简要介绍这一点。还要注意,它永远不会添加文件:为此,您必须自己创建git add.


3从技术上讲,文件的内容不占用空间。索引条目及其在工作树中出现的文件缓存数据会占用一些空间,每个文件大约需要 40 到几百个字节,具体取决于许多细节。

4runninggit add和你在这里为你git commit运行之间的最大区别在于git add,如果你的提交失败会发生什么(例如,由于预提交挂钩,或者你告诉 Git 停止并且毕竟不进行提交)。在这种情况下,由 完成的添加将git commit -a取消。如果您git add手动运行自己,则添加会保持添加。


索引的其他用途

索引在冲突合并中起着重要作用。Git 合并涉及的不是一个而是三个提交,为了进行合并,Git 将所有三个提交读入它的索引。这涉及“扩展”索引,以便每个文件获得三个插槽。如果合并顺利,并且 Git 能够自行解决每个冲突,则三个插槽将降级为正常的单插槽,准备提交条目。如果不是,Git 会通过保留所有三个插槽来记住存在冲突。此处不赘述,但索引在合并过程中扩展的事实意味着您确实不能忽略它。

此外,Git 有git add -p: 这可以让你添加文件的一部分,就像它一样。Git 通过在文件系统中的某个常规文件中制作索引中看到的文件的临时副本来处理此问题,然后使用更新修补该文件,然后将该文件的内容添加索引。最终结果是索引中的副本(建议用于下一次提交)与当前提交版本工作树版本都不同。理解这一点的唯一方法是认识到索引包含文件的待提交副本,该副本可能与任何其他副本不同。

最后,索引中文件的存在与否决定了文件当前是被跟踪还是未跟踪由于这会影响文件是否可以忽略,因此您必须了解索引才能理解.gitignore.

指数摘要

除了在合并、索引或暂存区中的作用之外,它还只是保存了您现在运行时将要提交的每个文件的副本。git commit您可以随时更改索引中的文件:

  • 你可以运行git checkoutgit switch选择一个的提交,同时填写 Git 的索引和你的工作树。
  • 您可以运行git rm以从 Git 的索引和工作树中删除文件。
  • 您可以运行git rm --cached(有旧的坏字缓存,而不是staging area)从 Git 的索引中删除文件,而无需触及工作树中的副本。5
  • 您可以使用将文件复制到 Git 索引中git restore的选项运行。--staged
  • 可以使用多种方式git reset来影响索引文件(这个命令很大,可能过于灵活,这里不再赘述)。

基本上,有很多方法可以随时更改 Git 索引中的内容。索引不是只读的,不像提交是只读的。它包含建议的下一次提交,并且当您运行时git commit,它将立即打包索引中的所有文件并将它们永远冻结到一个新的提交中。6 这让我们回到了跟踪文件与未跟踪文件: 跟踪文件是目前在 Git 索引中的文件。未跟踪的文件是当前不在 Git 索引中的文件。而且,您只能忽略未跟踪的文件。


5请注意,这意味着下一次提交将没有该文件。如果您曾经检查过确实有文件的提交,这会造成一个糟糕的情况:现在,当您切换回没有文件的提交时,工作树副本可能会被删除。

6当然,新的提交只有在它被提交时才会被提交——例如,参见前面关于预提交钩子的评论——并且,虽然新提交为新的冻结文件和元数据集永久保留其新哈希 ID,但您可以通过一些工作让 Git忘记这个提交存在。提交后,您无法更改提交,但可以停止使用它。带有哈希 ID 的新提交永远是只读的,但它只持续只要它持续. 提交是只读的,但只是永久性的。


排除文件如.gitignore

工作树中但不在 Git 索引中的文件是未跟踪文件。我们可以在这里停下来,因为这就足够了。您运行git commit并且只有跟踪的文件被提交。您只需非常小心地git add只提交正确的文件,并且只有那些文件,加上之前提交的文件,才会被提交。

但是这种工作方式很烦人而且效率低下。我们运行git status,哇,嘿,Git抱怨大约 3000 个未跟踪的文件。我们的信息在哪里?它被隐藏在所有这些“未跟踪文件”的废话之下。

(你之前做过那个练习,关于在大量无用信息中找到好的信息吗?)

那么:如果我们能让 Git关闭这些未跟踪文件中的大多数会怎样?当我们使用 Git 时,这可能是我们接下来可以做的最重要的事情。这使得git status只打印有趣的东西。

当然,我们可以让 Git 闭嘴。我们只需要列出它不应该告诉我们的文件。我们可以将这些文件的名称放在.gitignore, or .git/info/excludes, or ~/.config/git/ignore, 或其他文件中。这些文件统称为排除文件。通俗地说,大多数人只是称他们为.gitignore

一个.gitignore文件可以包含:

  • 球状图案,例如*.pyc
  • 一个简单的文件名,比如debug
  • 带有前导斜杠的路径名,例如/tags
  • 带有嵌入斜杠的路径名,例如contrib/buildsystems/out

和更多。

当其中一个文件列出了一个简单的文件名或模式(如debugor *.pyc)时,此名称与该文件所在的同一目录中的任何文件或目录名匹配.gitignore或者该点下的任何目录中的任何文件或目录名匹配。因此,如果我们有一个项目,如您所说:

.gitignore
LICENSE
README.md
App/
    .gitignore
    main.py
    [more files and directories]

然后我们有两个/.gitignore,一个在顶层,/App/.gitignore一个在App子目录中。否则不必要的,有时是误导性的,在此处引导/- <code>/.gitignore - 只是为了告诉我们在哪个级别找到了文件。

/.gitignoreapply here 和 to stuff in中的简单条目,如果存在则App/to stuff inApp/sub/等等。但是/.gitignore文件中带有前导斜杠的条目,例如/README.html我们可能为我们构建了一些软件的 HTML 化版本的 markdown 文件,不会匹配README.htmlin App,如果有的话。

.gitignore因此,文件中条目中的前导斜杠具有锚定条目的效果:它仅在此特定级别匹配。如果/App/.gitignorecontains /LICENSE,这将忽略/App/LICENSE但不是/LICENSE顶层的。

在文件中锚定有点奇怪.gitignore,因为任何嵌入的斜线也会有这种锚定效果。因此,如果您想忽略contrib/buildsystems/out,就像 Git 的 Git 存储库一样,您可以编写:

contrib/buildsystems/out

或者:

/contrib/buildsystems/out

在顶级.gitignore文件中:两者的含义相同。Git 的人选择使用后者,也许是基于它更清晰的理论(我认为它是,稍微)。

我们可以在.gitignore文件中使用更多的模式和规则,但现在这可能就足够了。详细信息在gitignore 文档中进行了描述。在这里我们真正需要谈论的是条目的其他影响。.gitignore

我们已经知道,对于一些未跟踪的文件,列出一些模式会导致git status对它闭嘴。这很重要:它git status 使. 但它还有两个作用:

  • git add更易于使用。
  • 它有一个不幸的“破坏许可”副作用。

现在让我们解决第一个问题。

集体git add

为了git add方便使用,我们可以在.gitignore文件中列出那些如果还没有被跟踪则不应添加的文件。例如,如果.gitignore文件包含*.pycand *.pyo__pycache__那么无论我们使用的是 Python 2 还是 Python 3,我们都可以运行:

git add .

不用担心我们的字节码编译的 Python 文件会被提交。git add .这是因为扫描当前目录的 en-masse不会将未跟踪和忽略的任何文件添加为跟踪文件。

请注意,如果一个文件已经被跟踪,git add .将添加它。 也就是说,如果某个与某个.gitignore模式匹配的文件已经Git 的索引中,并且您使用了一个git add命令来添加它(如果它没有被列为忽略),那么 Git 就好像它没有被列为被忽略一样。它现在在索引中的事实覆盖了其他所有内容:它不会被忽略,所以它不会忽略。

您还可以使用git add -f强制覆盖忽略规则。请参阅如何使用 .gitignore 忽略目录中除一个文件之外的所有内容?例如。这使您可以“第一次”将一个原本被忽略的文件放入索引中,之后它在索引中的存在确保了它在索引中的持续存在(和更新)。我个人不喜欢这种技术,因为这意味着如果你曾经git rm在文件上运行过,以后 git add不会注意到它应该被添加回来:一旦它超出了索引,它就不会出现!

破坏许可

这个很棘手。它也不会经常发生。触发它的主要方法是拥有一个被跟踪和提交的文件,然后决定您不希望它被跟踪,但希望将其作为典型工作树中的未跟踪文件保留。因此,您可以git rm --cached将其从 Git 的索引中删除,然后提交,然后仔细更新此存储库克隆的所有用户。

但是,有一天,你决定检查一些旧的提交,看看情况如何。这会覆盖文件的工作树副本。Git 需要一种方式来说明某些文件不应该被提交,但也不应该被破坏。它没有一个。有关更多详细信息,请参阅Git checkout has deleted untracked files unintentionally

结论

如果你做到了这一步,恭喜!你现在比大多数普通的 Git 用户了解的多得多,了解 Git 的索引和.gitignore文件之间的交互,以及可以进入这些排除文件的内容。

最终的答案是你应该做对你有用的事情。毕竟,Git 是一组工具,而不是解决方案。任何一个给定的问题都没有一个正确的答案(尽管一些简单的问题确实有一个简单的答案,因此可能是可以使用的答案)。如果您遇到不寻常的情况,您可能需要一个不寻常的解决方案。Git也许能够提供它。

记住排除文件条目是如何匹配的(请参阅如何使用 .gitignore 忽略目录中除一个文件之外的所有内容?)。根据需要使用git check-ignore -v以查看是否匹配某个文件名,如果匹配,则根据哪个规则。请记住,您的个人排除文件~/.gitignoreor~/.config/git/ignore可用于防止 Git 集体添加编辑器临时文件,如*.swpor *.swo(vim)、*.~(emacs 备份) 等。如果您不想将它们列在个人排除文件本地.git/info/exclude.gitignore被提交到这个存储库中。

你有很多工具。其中一些具有锋利的边缘(例如可能破坏文件),因此请使用它们,但要小心使用它们。


推荐阅读