跳转至

5.忽略Git中的文件

你已经花了不少时间学习如何让Git追踪仓库中的文件,以及如何处理Git对你的活动几乎无时无刻的监视。所以你可能会觉得奇怪,为什么要让Git主动忽略你仓库里的东西。

为什么你不希望Git追踪你项目中的一切呢?好吧,在很多情况下,你可能不希望Git追踪所有东西。

一个很好的例子是任何包含API密钥、令牌、密码或其他秘密的文件,你肯定需要进行测试,但你不希望它们放在仓库里--尤其是公共仓库--让所有人看到。

根据你的开发平台,你可能有很多构建工件或生成的内容在你的项目目录里,比如链接器文件、元数据、生成的可执行文件和其他类似的东西。这些文件在你每次构建项目时都会重新生成,所以你肯定不希望Git跟踪这些文件。还有那些顽固的东西,有些操作系统不经询问就把它们添加到你的目录里,比如macOS上的.DS_Store文件。

引入.gitignore

Git对此的回答是.gitignore文件,它是一组保存在文件中的规则,告诉Git不要追踪文件或文件集。这似乎是一个非常简单的解决方案,而且确实如此。但.gitignore的真正威力在于它能够对各种文件进行模式匹配,这样你就不必对每一个你想让Git忽略的文件进行说明,你甚至可以指示Git忽略多个项目中的相同类型的文件。再进一步,你可以有一个适用于所有仓库的全局的.gitignore,然后把特定项目的.gitignore文件放在需要特别严格控制的项目的目录或子目录中。

在本章中,你将学习如何配置你自己的.gitignore,如何使用一些来自GitHub等地方的预制.gitignore文件,以及如何设置一个适用于所有项目的全球.gitignore

开始工作

想象一下,在你的武器库中,有一个工具可以将你的markdown"构建"成HTML,以准备将你令人惊叹的书、教程和其他想法部署到一个私人网站,供你的团队评论。

在这种情况下,HTML文件是生成的内容,你不想在版本库中跟踪。你想把它们作为构建过程的一部分在本地渲染,这样你就可以预览它们,但你绝不会直接编辑HTML。它总是用工具渲染的。

在你项目的根目录下创建一个新的目录来存放这些生成的文件,使用下面的命令:

mkdir sitehtml

现在,在那里创建一个空的HTML文件(保持想象力,朋友),使用以下命令:

touch sitehtml/all-todos.html

运行git status,看看Git是否识别了新内容:

~/GitApprentice/ideas $ git status
On branch main
Your branch is ahead of 'origin/main' by 7 commits.
  (use "git push" to publish your local commits)

Untracked files:
  (use "git add <file>..." to include in what will be committed)
  sitehtml/

nothing added to commit but untracked files present (use "git add" to track)

因此,Git又一次看到了你在做什么。但这里是如何让Git视而不见的。

在你项目的根目录下创建一个名为.gitignore的文件:

touch .gitignore

并使用文本编辑器在你新创建的.gitignore中添加以下一行:

*.html

保存并退出。你所做的是告诉Git,"对于这个项目,忽略所有符合这个模式的文件"。在这个例子中,你要求它忽略所有扩展名为.html的文件。

现在,看看git status告诉你什么:

~/GitApprentice/ideas $ git status
On branch main
Your branch is ahead of 'origin/main' by 7 commits.
  (use "git push" to publish your local commits)

Untracked files:
  (use "git add <file>..." to include in what will be committed)
  .gitignore

nothing added to commit but untracked files present (use "git add" to track)

Git看到你添加了.gitignore,但它不再认为那个HTML文件是"未被追踪的",即使它被埋在一个子目录里。

现在,如果你对忽略子目录中的HTML文件没有意见,但你想让项目顶层目录中的所有HTML文件都被跟踪呢?理论上,你可以在每个子目录中重新创建相同的.gitignore文件,并删除这个顶层的.gitignore,但这将是非常繁琐的,而且不能很好地扩展。

相反,你可以在顶层的.gitignore中使用一些巧妙的模式匹配,只忽略子目录。

编辑你的.gitignore中的单行,如下所示:

*/*.html

保存并退出。这个新模式告诉Git,"忽略所有不在顶层目录中的HTML文件"。

为了证明这一点,在项目的顶层目录下创建一个新的HTML文件:

touch index.html

运行git status,看看Git是否真的识别了顶层目录中的HTML文件,而仍然忽略了下面的文件:

~/GitApprentice/ideas $ git status
On branch main
Your branch is ahead of 'origin/main' by 7 commits.
  (use "git push" to publish your local commits)

Untracked files:
  (use "git add <file>..." to include in what will be committed)
  .gitignore
  index.html

nothing added to commit but untracked files present (use "git add" to track)

Git看到顶层的HTML文件没有被追踪,但它仍然忽略了sitehtml目录下的另一个HTML文件,就像你计划的那样。

嵌套.gitignore文件

你可以在你的项目中轻松地嵌套.gitignore文件。想象一下,你有一个子目录,里面有从index.html引用的HTML文件。这些文件不是由你想象中的构建过程生成的,而是由手工维护的,你想确保Git能够跟踪这些文件。

创建一个新目录,命名为htmlrefs

mkdir htmlrefs

现在,在该子目录下创建一个HTML文件:

touch htmlrefs/utils.html

并在该目录下创建一个.gitignore文件:

touch htmlrefs/.gitignore

打开htmlrefs/.gitignore并添加以下一行:

!/*.html

保存并退出。惊叹号(!)在这种情况下否定了模式,而斜线(/)意味着"从这个目录开始执行这个规则"。所以这条规则说:"尽管有更高级别的规则,但不要忽略任何HTML文件,从这个目录或更低的目录开始。"

执行git status来看看这是否是真的:

~/GitApprentice/ideas $ git status
On branch main
Your branch is ahead of 'origin/main' by 7 commits.
  (use "git push" to publish your local commits)

Untracked files:
  (use "git add <file>..." to include in what will be committed)
  .gitignore
  htmlrefs/
  index.html

nothing added to commit but untracked files present (use "git add" to track)

现在Git把htmlrefs目录下的内容看作是未被追踪的,就像你想的那样。

现在你对当前.gitignore文件的安排感到满意了,你可以对这些改动进行阶段化和提交。

用下面的命令将所有的修改分阶段:

git add .

并把这些变化也提交上去:

git commit -m "Adding .gitignore files and HTML"

在每个项目的基础上设置.gitignore文件,只能让你走到这一步。有些东西--比如前面提到的.DS_Store文件,macOS地将其添加到你的目录中--你想一直忽略它们。Git有一个global .gitignore的概念,你可以用来处理这样的情况。

查看全局.gitignore

执行下面的命令,看看你是否已经有一个全局的.gitignore

git config --global core.excludesfile

如果该命令没有返回,那么你还没有设置好。不用担心;创建一个很容易。

在一个方便的地方创建一个文件--在这种情况下,就是你的主目录--并给它起一个明显的名字:

touch ~/.gitignore_global

现在你可以用git config命令告诉Git,它应该从现在开始把这个文件作为你的全局.gitignore来看:

git config --global core.excludesfile ~/.gitignore_global

所以现在如果我问Git我的全局.gitignore在哪里,它会告诉我如下:

~/GitApprentice/ideas $ git config --global core.excludesfile
/Users/chrisbelanger/.gitignore_global

但现在你有了一个全局的.gitignore......你应该把什么放在里面?

寻找.gitignore文件样本

这是其中一种情况,你不必重新发明轮子。成千上万的开发者在你之前,他们已经找出了适合你特定情况的最佳配置。

一个更好的预制.gitignore文件集合是由GitHub托管的--我相信这并不奇怪。GitHub有大多数操作系统、编程语言和代码编辑器的文件。

请到https://github.com/github/gitignore,看看它提供的软件包。适合你的操作系统的样本文件可以在资源库的Global子文件夹中找到。

进入Global子文件夹(或者直接导航到https://github.com/github/gitignore/tree/master/Global),找到适合你本地系统的。

img

有一个Windows.gitignore,一个macOS.gitignore,一个Linux.gitignore,还有更多,都等着你把它们加入你自己的.gitignore。这就是本章的挑战!

挑战

挑战:填充你的全局.gitignore

这个挑战应该很简单,为你的全局.gitignore提供一个好的起点。你的目标是为自己的操作系统找到正确的.gitignore,从GitHub仓库获取该文件,并将该文件的内容添加到你的全局.gitignore

  1. 导航到https://github.com/github/gitignore/tree/master/Global
  2. 为你自己的操作系统找到正确的.gitignore
  3. 将特定操作系统的.gitignore的内容添加到你自己的全局.gitignore

如果你被卡住了,或者想检查你的解决方案,你可以在本章的challenge文件夹中找到这个挑战的答案。

关键点

  • .gitignore可以让你配置Git,让它忽略特定的文件或符合特定模式的文件。
  • *.html在你的.gitignore中匹配你项目的任何目录或子目录中的所有以.html为扩展名的文件。
  • */*.html匹配所有以.html为扩展名的文件,但只在项目的子目录下。
  • !否定一个匹配规则。
  • 你可以在项目的不同目录下有多个.gitignore文件来覆盖项目中更高层次的匹配。
  • 你可以通过git config --global core.excludesfile命令找到你的全局.gitignore的位置。
  • GitHubhttps://github.com/github/gitignore,提供了一些很好的.gitignore起始文件。

接下来去哪?

随着你在越来越复杂的项目上工作,特别是跨越多种代码和编码语言,你会发现全局的.gitignore的力量,加上特定项目(甚至特定文件夹)的.gitignore文件,将成为你的Git工作流程中不可缺少的一部分。

下一章将带你简短地了解一下git log的各种工作原理。是的,你已经用过这个命令了,但这个命令有一些聪明的选项,可以帮助你以一种高效且高度可读的方式查看项目的历史。