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),找到适合你本地系统的。

有一个Windows.gitignore,一个macOS.gitignore,一个Linux.gitignore,还有更多,都等着你把它们加入你自己的.gitignore。这就是本章的挑战!
挑战¶
挑战:填充你的全局.gitignore¶
这个挑战应该很简单,为你的全局.gitignore提供一个好的起点。你的目标是为自己的操作系统找到正确的.gitignore,从GitHub仓库获取该文件,并将该文件的内容添加到你的全局.gitignore。
- 导航到https://github.com/github/gitignore/tree/master/Global。
- 为你自己的操作系统找到正确的
.gitignore。 - 将特定操作系统的
.gitignore的内容添加到你自己的全局.gitignore。
如果你被卡住了,或者想检查你的解决方案,你可以在本章的challenge文件夹中找到这个挑战的答案。
关键点¶
.gitignore可以让你配置Git,让它忽略特定的文件或符合特定模式的文件。*.html在你的.gitignore中匹配你项目的任何目录或子目录中的所有以.html为扩展名的文件。*/*.html匹配所有以.html为扩展名的文件,但只在项目的子目录下。!否定一个匹配规则。- 你可以在项目的不同目录下有多个
.gitignore文件来覆盖项目中更高层次的匹配。 - 你可以通过
git config --global core.excludesfile命令找到你的全局.gitignore的位置。 GitHub在https://github.com/github/gitignore,提供了一些很好的.gitignore起始文件。
接下来去哪?¶
随着你在越来越复杂的项目上工作,特别是跨越多种代码和编码语言,你会发现全局的.gitignore的力量,加上特定项目(甚至特定文件夹)的.gitignore文件,将成为你的Git工作流程中不可缺少的一部分。
下一章将带你简短地了解一下git log的各种工作原理。是的,你已经用过这个命令了,但这个命令有一些聪明的选项,可以帮助你以一种高效且高度可读的方式查看项目的历史。