Files
git-recipes/sources/2.3.5-git_ignore.md
2018-12-24 23:19:48 +09:00

12 KiB
Raw Permalink Blame History

.gitignore

Saving changes

git add / git commit / git diff / git stash / .gitignore

✍️ 童仲毅 | 2018 年 12 月 24 日

©️ 本文演绎自 Atlassian 编写的 Saving Changes。页面上所有内容采用知识共享-署名(CC BY 2.5 AU)许可协议。

Git 将工作副本中每个文件都视作以下三者之一:

  1. 被追踪的文件——之前被缓存或提交过的文件;
  2. 未被追踪的文件——尚未被缓存或提交过的文件;
  3. 被忽略的文件——Git 被明确告知要忽略的文件。

被忽略的通常是构建过程build和机器生成的文件。它们可以根据你的仓库源码生成或者不应该被提交。下面是一些常见的栗子

  • 缓存的依赖文件,例如 /node_modules/packages 里的内容
  • 编译后的代码,例如 .o.pyc.class
  • 构建输出的目录,例如 /bin/out/target
  • 运行时生成的文件,例如.log.lock.tmp
  • 隐藏的系统文件,例如.DS_StoreThumbs.db
  • 个人的开发环境IDE配置文件例如.idea/workspace.xml

忽略的文件通过一个名为 .gitignore 的文件追踪该文件位于仓库的根目录下。Git 没有显式的忽略命令。添加新文件时必须手动修改并提交 .gitignore 文件来添加忽略的文件。.gitignore 文件里的规则用于匹配文件名,从而判断该文件是否需要被忽略。

目录

Git 忽略文件的匹配规则

.gitignore 使用 GLOB 规则 匹配文件名。你可以使用多种符号创建你的规则:

匹配规则 样例 解释*
**/logs logs/debug.log logs/monday/foo.bar build/logs/debug.log 在规则前接两个星号,从而在仓库任何位置匹配该目录。
**/logs/debug.log logs/debug.log build/logs/debug.log 但不会匹配 logs/build/debug.log 使用两个星号匹配文件名和父目录名称。
*.log debug.log foo.log .log logs/debug.log 单个星号为通配符,匹配零或多个字符。
*.log !important.log debug.log trace.log 但不会匹配 important.log logs/important.log 在规则前接一个感叹号作为否定。如果文件同时符合一个先定义的规则和一个后定义的否定规则,它将不会被忽略。
*.log !important/*.log trace.* debug.log important/trace.log 但不会匹配 important/debug.log 在否定规则后定义的规则会覆盖之前定义的否定规则。
/debug.log debug.log 但不会匹配 logs/debug.log 前接斜杠只匹配仓库根目录下的文件。
debug.log debug.log logs/debug.log 规则默认匹配任何目录下的文件。
debug?.log debug0.log debugg.log 但不会匹配 debug10.log 一个问号用于匹配一个符号。
debug[0-9].log debug0.log debug1.log 但不会匹配 debug10.log 方括号用于从特定范围中匹配单个字符。
debug[01].log debug0.log debug1.log 但不会匹配 debug2.log debug01.log 方括号用于从特定集合中匹配单个字符。
debug[!01].log debug2.log 但不会匹配 debug0.log debug1.log debug01.log 感叹号用于匹配除去特定集合中的任一字符。
debug[a-z].log debuga.log debugb.log 但不会匹配 debug1.log 范围可以是数字,也可以是字母。
logs logs logs/debug.log logs/latest/foo.bar build/logs build/logs/debug.log 如果你不后接斜杠,规则将会同时匹配相符的文件和目录。在左边的栗子中,名为 logs 的目录和文件都被忽略了。
logs/ logs/debug.log logs/latest/foo.bar build/logs/foo.bar build/logs/latest/debug.log 后接斜杠表示该规则对应的是一个目录。仓库中符合该规则的任何目录中的所有内容(包括文件和子目录)都会被忽略。
logs/ !logs/important.log logs/debug.log logs/important.log 注意,为什么左边栗子中被加上否定的 logs/important.log 没有被忽略?由于 Git 的性能优化,你 不能 否定一个根据目录匹配规则被忽略的文件。
logs/**/debug.log logs/debug.log logs/monday/debug.log logs/monday/pm/debug.log 两个星号匹配零个或多个目录。
logs/*day/debug.log logs/monday/debug.log logs/tuesday/debug.log 但不会匹配* logs/latest/debug.log 通配符也可被用于目录名中。
logs/debug.log logs/debug.log 但不会匹配* debug.log build/logs/debug.log 一些规则指定特定目录下的文件,这些路径相对于仓库的根目录。你可以在前接一个斜杠,但这不是必须的。

** 这些解释假设你的 .gitignore 文件按照惯例位于仓库根目录。如果仓库中存在多个 .gitignore 文件,你只需要将“包含 .gitignore 文件的目录”想成是“仓库的根目录”。同时,为了便于团队合作,你应该考虑将它们合并*

除了这些符号之外,你可以使用 # 在 .gitignore 文件中添加注释:

# ignore all logs
*.log

你可以在 .gitignore 规则字符中使用 \ 转义,如果文件名或目录名中包含特殊字符:

# ignore the file literally named foo[01].txt
foo\[01\].txt

仓库内的共享 .gitignore 文件

Git 忽略规则通常被定义在仓库根目录的 .gitignore 文件中。但是,你也可以在仓库内不同文件夹下定义多个 .gitignore 文件。 .gitignore 文件中的每个规则都会在所在文件夹进行匹配。不过,我们一般只在根目录定义一个 .gitignore 文件,这也是最简单的做法。当 .gitignore 文件被检入时,它和仓库内其它所有文件一样也有版本,在你推送后将与他人共享。在 .gitignore 中,你应该只添加对其它用户也有用的规则。

个人的 Git 忽略规则

你可以在 .git/info/exclude 这个文件中为某个仓库定义个人的忽略规则。它们没有版本,也不会跟随仓库发布,因此它们适合存放只对你有用的规则。例如,如果你有一个自定义的登陆配置,火烧会在仓库的工作目录下生成文件的特殊开发工具,你可以将它们添加到 .git/info/exclude 以避免被意外提交到仓库中。

全局的 Git 忽略规则

此外,通过设置 Git 的 core.excludesFile 属性,你可以在本地系统中为所有仓库设置全局的 Git 忽略规则。你需要自己创建这个文件。如果你不确定在哪里放置这个全局的 .gitignore 文件home 目录会是一个好的选择,也便于以后的查找。创建这个文件之后,你需要使用 git config 配置它的位置:

$ touch ~/.gitignore
$ git config --global core.excludesFile ~/.gitignore

你应该特别注意哪些规则是应该全局忽略的,因为不同的项目会用到不同类型的文件。某些操作系统文件(如 .DS_Storethumbs.db)和开发者工具生成的临时文件往往可以被全局忽略。

忽略一个被提交过的文件

如果你想要忽略一个已经提交过的文件,你需要将这个文件从仓库中删除,然后在 .gitignore 中添加一条规则。使用 git rm--cached 选项表示这个而文件将从仓库中被删除,但将作为一个被忽略的文件存在于工作目录下。

$ echo debug.log >> .gitignore
$ git rm --cached debug.log
rm 'debug.log'
$ git commit -m "Start ignoring debug.log"

如果你希望将某个文件同时从仓库和本地文件系统中删除,你可以省略 --cached 选项。

提交被忽略的文件

使用 git add-f(或者--force)选项,你可以强制提交一个被忽略的文件:

$ cat .gitignore
*.log
$ git add -f debug.log
$ git commit -m "Force adding debug.log"

使用这个命令的一个场景是,你定义了一个通用的规则(如 *.log),但是想要提交某个特定的文件。不过,一个更好的解决方案是为这个通用的规则定义一个例外:

$ echo !debug.log >> .gitignore
$ cat .gitignore
*.log
!debug.log
$ git add debug.log
$ git commit -m "Adding debug.log"

上面的这个方法更加清晰易懂,尤其是对于其它团队成员。

储存被忽略的文件

git stash 是一个强大的 Git 功能。它将本地的更改临时储存起来然后撤销,允许你随后再重新应用这些更改。正如你所想的一样,git stash 默认跳过被忽略的文件,它只储存被 Git 追踪的文件中的更改。然后,你可以使用 git stash 的 --all 选项来储存被忽略和为追踪的文件。

调试 .gitignore 文件

如果你的 .gitignore 规则十分复杂,或者规则分散于多个 .gitignore 文件,要理解某个文件为什么被忽略了不是一件容易的事情。你可以使用 git check-ignore 命令的 -v(或者 --verbose)选项来确定是哪条规则让某个文件被忽略了:

$ git check-ignore -v debug.log
.gitignore:3:*.log debug.log

输出的格式如下:

<file containing the pattern> : <line number of the pattern> : <pattern> <file name>

你可以向 git check-ignore 传入多个文件名。这些文件名不一定要对应于仓库中已存在的文件。

这篇文章是「git-recipes」的一部分,点击 目录 查看所有章节。

如果你觉得文章对你有帮助,欢迎点击右上角的 Star 🌟Fork 🍴

如果你发现了错误,或是想要加入协作,请参阅 Wiki 协作说明