【Git】 Git之忽略文件(gitignore)

Posted by 西维蜀黍 on 2017-04-03, Last Modified on 2021-09-21

今天分享一下Git中一个非常重要的文件.gitignore,这个文件用来定义哪些文件或文件夹,Git不需要跟踪,从而也不需要将这些文件添加到版本管理中。

文件意义

在实际项目中,可能存在一些文件或文件夹是不需要做版本跟踪的,也不需要做版本管理,但是又必须将其放到本地的Git的工作目录中,比如,编译过程中生成的一些临时文件(Java字节码文件.class)、数据库密码的配置文件等等。

当然,他们仍然存在于本地 repostitory,但是在执行git push时不会上传到远端 repository ,因此远端 repository 中自然也不会存在这些文件。

对于这些文件或文件夹,每次git status时,都会出现Untracked files ...,感觉非常的蛋疼!

好在Git在设计之初,就考虑到了这个问题。在一个以Git做为版本管理工具的项目中,可以在.gitignore文件中定义,哪些文件或文件夹不需要被Git跟踪。定义之后,Git就会自动忽略这些文件了。

文件模板

当然,对于各个技术栈或编程语言,在GitHub中,大神们已经为我们整理好了各种各样的.gitignore,我们只要根据自己的需求稍微修改一下就好了。

地址:github/gitignore

随便据几个例子,比如:

  • JetBrains.gitignore中,.idea/是JetBrains工具生成的用于管理工程和生成一些临时文件的文件夹
  • Node.gitignore中,node_modules/是NPM项目用于存储第三方依赖库的文件夹,每次接手一个新的Node项目,只需要npm install即可
  • VisualStudio.gitignore中,coverageor*.coverage是一些项目在执行测试用例时自动生成的测试覆盖率报表**(多数的大型项目都会在持续集成系统(Continuous Intergration System)中执行相关测试,并输入测试覆盖率报表,因此即使我们在本地执行测试,也不需要将相关测试覆盖率报表push到Git中)**

忽略原则

  1. 忽略操作系统自动生成的文件,比如缩略图等;
  2. 忽略编译生成的中间文件、可执行文件等,**也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
  3. 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。

忽略规则定义

虽然,github/gitignore中已经为各种类型的项目定义了.gitignore模板,但是我们仍然需要了解在.gitignore中对文件或文件夹定义忽略规则的方法:

首先,我们需要明确关于文件和文件夹的命名:

  • 文件即可以命名为"*.*"(即以.*为后缀,比如abc.jpg1.a),也可以命名为"*"(比如abcaaa
  • 文件夹即可以命名为"*"(比如abcaaa),也可以命名为" *.*"(即存在后缀,比如abc.a1.b,只是我们一般不这样起名罢了)

之所以强调上述的细节,是因为在网上的有些Blog中,并没有考虑到文件夹可以以.*为后缀的方式命名,故认为abc.a规则只是忽略命名为abc.a的文件,不包括忽略命名为abc.a的文件夹,这是错误的!!!!

还需要明确:

忽略文件夹意味着这个文件夹中的所有文件和文件夹(当然也包括其中的子文件和子文件夹)都会被忽略,除非添加了额外的非过滤规则

定义过滤规则

不指定绝对路径

忽略所有名为某个指定名称的文件或文件夹,无论它位于根目录(root directory)or 子目录(subdirectory):

# ignore all files or folders named "foo.txt" wherever they are located
foo.txt

忽略所有以.o.a结尾的文件或文件夹,无论它位于根目录(root directory)or 子目录(subdirectory):

 # ignore all files or folders which name ends up with ".o" or ".a" wherever they are located
 *.[oa]

忽略所有以.zip结尾的文件或文件夹,无论它位于根目录(root directory)or 子目录(subdirectory):

 # ignore all files or folders which name ends up with "zip" wherever they are located
 *.zip

忽略所有以a结尾的文件夹(不忽略以a结尾的文件),无论它位于根目录(root directory)or 子目录(subdirectory):

 # ignore all folders which name ends up with "a" wherever they are located
 *a/

指定绝对路径

只忽略根目录下名为abc的文件夹或文件,子目录中名为abc文件或文件夹不在忽略范围内:

# ignore a specified folder or file which name is "abc" and is located in root directory
/abc

需要注意的是,忽略根目录下名为abc的文件夹意味着,其中包含的子文件夹中的文件和文件夹都会被忽略,如/abc/a/1.exe/abc/a/b/2.exe


只忽略根目录下名为abc的文件夹(不忽略根目录下名为abc的文件),子目录中名为abc文件夹不在忽略范围内:

# ignore a specified folder which name is "abc" and is located in root directory
/abc/

忽略根目录下,abc文件夹中某一个子文件夹下的a.exe

# ignore all files which is located in /abc
/abc/*/a.exe

/abc/a/a.exe/abc/b/a.exe,但不包括/abc/b/c/a.exe/abc/b/c/d/a.exe


忽略根目录下,abc文件夹中处于任意位置下的a.exe

# ignore all files which is located in /abc
/abc/**/a.exe

/abc/a/a.exe/abc/b/a.exe/abc/b/c/a.exe/abc/b/c/d/a.exe

注:以上两个例子想说明“*” 与 “**”的区别。一句话概括就是:\*只能匹配一级文件夹,而\*\*可以匹配一级或多级文件夹。


忽略根目录下,abc文件夹中的所有文件(包括其子文件夹中的文件或文件夹):

# ignore all files which is located in /abc
/abc/*

只忽略根目录下/abc/a.java这个文件:

# # ignore a specified folder which name is "a.java" and is located in /abc
/abc/a.java

定义非过滤规则

与过滤规则完全类似,但是只需要在上述规则前面增加!,即定义为非过滤规则。

比如:

忽略所有以.a结尾的文件或文件夹:

 # ignore all files or folders which name ends up with ".a" wherever they are located
 *.a

那么,不忽略所有以.a结尾的文件或文件夹:

 # do not ignore all files or folders which name ends up with ".a" wherever they are located
 !*.a

想象一个场景:我们只需要跟踪根目录下的abc文件夹中的one.java文件,这个文件夹中的其他文件都不需要被跟踪。那么我们可以这样定义:

/abc/
!/abc/one.java

假设我们只有过滤规则没有非过滤规则,那么我们就需要把/abc/文件夹下除了one.java以外的所有文件都列出来!

通配符匹配语法

  • 斜杠/开头表示根目录;
  • 星号*通配多个字符(不包括"/");
  • 双星号**通配多个字符(包括"/");
  • 问号?通配单个字符;
  • 方括号[]表示匹配其中的某单个字符;

检查文件是否被忽略

我们可以使用以下命令检查某个文件或文件夹是否被忽略,如果输出了输入的pathname,则表明这个文件或文件夹会被Git忽略。

git check-ignore pathname

通过这个命令,对于某些存在复杂忽略匹配规则的项目,在需要判断某个文件是否被忽略时,我们就不需要根据这个文件的路径和名称特征在.gitignore中一条一条地检查了。

比如,我们希望判断ddd\1.txt文件是否在忽略列表中:

git check-ignore ddd\1.txt
-> "ddd\\1.txt"

因为输出了"ddd\\1.txt",则说明Git会忽略ddd\1.txt这个文件**(事实上,我在.gitignore中增加了/ddd/这一规则)**。

.gitignore类型

.gitignore可以分为Global gitignore 和 Project gitignore。

  • **Global gitignore:**即将某个.gitignore文件设置为全局,那么这个.gitignore文件中的忽略规则对本机中所有Git项目都有效
  • **Project gitignore:**即在某个仓库(repository)中添加的.gitignore文件,这个文件中的忽略规则仅仅在这个项目中生效

添加Global gitignore

Windows平台为例,添加Global级别的 gitignore:

  1. C:\Users\{User Name}中增加一个.gitignore_global文件,在这个文件中添加全局过滤规则
  2. 在控制台中输入 git config --global core.excludesfile ~/.gitignore_global,当然这里我默认你已经将’git添加到了path`环境变量中。

添加Project gitignore

添加Project级别的 gitignore很简单,只需要在一个Git repository的任何一个位置下添加一个.gitignore文件即可。

这意味着,你可以在一个Git repository的不同位置下添加.gitignore那么如果不同的.gitignore中包含了相互矛盾的过滤规则,就存在优先级的问题:

事实上,git会在这个repository中构建一个文件结构树,子节点的.gitignore会重写父节点的.gitignore的过滤规则。


举个例子来说,在一个repository中,文件是这样的:

- .gitignore
- a-folder
 - .gitignore
 - file.txt

其中,在根目录下的.gitignore中定义file.txt(即忽略file.txt),在a-folder文件夹的.gitignore中定义!file.txt(即不忽略file.txt)。

通过git status,我们发现该file.txt是会被git跟踪的,其实是因为a-folder文件夹的.gitignore中定义的!file.txt重写了根目录下的.gitignore中定义的file.txt忽略规则。

注意

尽量在Project创立之初,就定义好.gitignore

最后需要强调的一点是,如果你在将对应某个文件或文件夹的过滤规则添加到.gitignore之前,就将这个文件或文件夹 git push到了远端 repository,那么即使你在.gitignore中添加这些过滤规则,这些规则也不会起作用Git仍然会对这些文件或者文件夹进行版本管理。

因此,我们尽量在Project创立之初,就定义好.gitignore。如果在之后的开发过程中,因为新增加了某些文件,而需要增加了新的过滤规则,要保证这些文件在创建之初,就在.gitignore中增加对应的过滤规则。而不是在git push这些文件后,才想起来要修改.gitignore

已经被tracked的文件设置.gitignore无效

.gitignore规则仅对未被跟踪(tracked)的文件有效,跟踪(tracked)文件包括被暂存(staged)的文件(即该文件已经被git add了,但没有git commit),和被git commit的文件。

参考