今天分享一下Git
中一个非常重要的文件.gitignore
,这个文件用来定义哪些文件或文件夹,Git不需要跟踪,从而也不需要将这些文件添加到版本管理中。
文件意义
在实际项目中,可能存在一些文件或文件夹是不需要做版本跟踪的,也不需要做版本管理,但是又必须将其放到本地的Git
的工作目录中,比如,编译过程中生成的一些临时文件(Java字节码文件.class)、数据库密码的配置文件等等。
当然,他们仍然存在于本地 repostitory,但是在执行git push
时不会上传到远端 repository ,因此远端 repository 中自然也不会存在这些文件。
对于这些文件或文件夹,每次git status
时,都会出现Untracked files ...
,感觉非常的蛋疼!
好在Git
在设计之初,就考虑到了这个问题。在一个以Git
做为版本管理工具的项目中,可以在.gitignore
文件中定义,哪些文件或文件夹不需要被Git
跟踪。定义之后,Git
就会自动忽略这些文件了。
文件模板
当然,对于各个技术栈或编程语言,在GitHub中,大神们已经为我们整理好了各种各样的.gitignore
,我们只要根据自己的需求稍微修改一下就好了。
随便据几个例子,比如:
- 在JetBrains.gitignore中,
.idea/
是JetBrains工具生成的用于管理工程和生成一些临时文件的文件夹 - 在Node.gitignore中,
node_modules/
是NPM项目用于存储第三方依赖库的文件夹,每次接手一个新的Node项目,只需要npm install即可 - 在VisualStudio.gitignore中,
coverage
or*.coverage
是一些项目在执行测试用例时自动生成的测试覆盖率报表**(多数的大型项目都会在持续集成系统(Continuous Intergration System)中执行相关测试,并输入测试覆盖率报表,因此即使我们在本地执行测试,也不需要将相关测试覆盖率报表push到Git中)**
忽略原则
- 忽略操作系统自动生成的文件,比如缩略图等;
- 忽略编译生成的中间文件、可执行文件等,**也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的
.class
文件; - 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。
忽略规则定义
虽然,github/gitignore中已经为各种类型的项目定义了.gitignore
模板,但是我们仍然需要了解在.gitignore
中对文件或文件夹定义忽略规则的方法:
首先,我们需要明确关于文件和文件夹的命名:
- 文件即可以命名为"*.*"(即以.*为后缀,比如
abc.jpg
、1.a
),也可以命名为"*"(比如abc
、aaa
) - 文件夹即可以命名为"*"(比如
abc
、aaa
),也可以命名为" *.*"(即存在后缀,比如abc.a
、1.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:
- 在
C:\Users\{User Name}
中增加一个.gitignore_global
文件,在这个文件中添加全局过滤规则 - 在控制台中输入
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
的文件。
参考
- gitignore last updated in 2.12.2
- GitHub Help - Ignoring files
- -https://www.atlassian.com/git/tutorials/gitignore