关于 gitignore 文件中的语法规则
.gitignore 用来告诉 Git:哪些未被跟踪的文件或目录,不要纳入版本管理。
它的作用对象主要是:
- 临时文件
- 缓存文件
- 构建产物
- 系统自动生成文件
- 本地私有配置
- 不想同步的大文件或目录
但有一个非常关键的前提:
.gitignore 只能影响“未被 Git 跟踪”的文件
如果某个文件以前已经 git add 并提交过,那么后来再把它写进 .gitignore,Git 仍然会继续跟踪它。
1 基本规则¶
.gitignore 文件本质上是一行一条规则。
例如:
node_modules/
*.log
.env
dist/
表示:
- 忽略
node_modules目录 - 忽略所有以
.log结尾的文件 - 忽略全名为
.env的文件,这里面一般是环境变量配置 - 忽略
dist目录
2 最基本的语法元素¶
2.1 空行¶
空行没有任何作用,只是为了分组、增加可读性。
例如:
*.log
node_modules/
dist/
这里的空行只是分隔,不参与匹配。
2.2 注释 #¶
以 # 开头的行表示注释。
例如:
# 忽略日志文件
*.log
# 忽略依赖目录
node_modules/
注释不会生效,只是写给人看的。
如果你真的想匹配以 # 开头的文件名,需要转义:
\#test.txt
2.3 普通文本匹配¶
直接写文件名或目录名,就是按名称匹配。
例如:
test.txt
cache
含义:
- 忽略名字叫
test.txt的文件 - 忽略名字叫
cache的文件或目录
注意,这种写法是 模糊位置匹配,不是只匹配根目录。
也就是说:
test.txt
可能匹配:
test.txt
a/test.txt
foo/bar/test.txt
3 通配符语法¶
.gitignore 最核心的就是通配符。
3.1 * 星号¶
* 表示匹配任意长度的任意字符,但 通常不跨目录分隔符 /
例如:
*.log
匹配:
a.logerror.log
不匹配:
logs/error.log中的整个路径本身并不是单个文件名匹配语义,但如果规则作用在该层级文件名上,里面的error.log会匹配
更直观地理解:
temp*
匹配:
temptemp1temp_file
3.2 ? 问号¶
? 表示匹配任意一个字符。
例如:
file?.txt
匹配:
file1.txtfileA.txt
不匹配:
file10.txtfile.txt
3.3 [abc] 字符集合¶
表示匹配方括号中的任意一个字符。
例如:
file[123].txt
匹配:
file1.txtfile2.txtfile3.txt
不匹配:
file4.txt
3.4 [a-z] 字符范围¶
表示匹配某个范围内的一个字符。
例如:
file[a-z].txt
匹配:
filea.txtfilem.txt
不匹配:
fileA.txtfile10.txt
3.5 ** 双星号¶
这是非常重要的高级写法。
** 表示可以跨目录匹配。
例如:
**/node_modules/
表示忽略任意层级下的 node_modules 目录。
匹配:
node_modules/project/node_modules/a/b/c/node_modules/
再比如:
logs/**/*.log
表示忽略 logs 目录及其任意子目录中的所有 .log 文件。
匹配:
logs/a.loglogs/app/error.loglogs/x/y/z/test.log
这里有必要补充一下星号和双星号的对比分析
| 写法 | 含义 |
|---|---|
* |
匹配任意字符(不包含 /) |
** |
匹配任意目录层级 |
*.log |
当前目录 .log 文件 |
**/*.log |
所有目录 .log 文件 |
temp* |
以 temp 开头的文件 |
logs/** |
logs 目录下所有内容 |
4 斜杠 / 的含义¶
斜杠在 .gitignore 里非常关键,因为它决定了规则是面向根目录,还是面向任意位置,还是明确指定目录。
4.1 前导斜杠 /¶
以 / 开头,表示 从 .gitignore 所在目录开始匹配
例如:
/test.txt
只匹配仓库根目录下的:
/test.txt
不匹配:
a/test.txt
foo/bar/test.txt
再例如:
/cache
只匹配根目录下的 cache
4.2 末尾斜杠 /¶
以 / 结尾,表示这是一个 目录规则
例如:
build/
表示忽略 build 目录,而不是名为 build 的普通文件。
匹配:
build/a/build/是否匹配,取决于是否有前导/。没有前导/时,任意层级同名目录都可能匹配
更准确地说:
build/
会匹配任意位置的 build 目录。
而
/build/
只匹配根目录的 build/
4.3 中间斜杠 /¶
中间出现 /,表示路径关系。
例如:
temp/cache/
表示匹配 temp 下的 cache 目录。
5 否定规则 !¶
! 表示 取消忽略
也就是把前面被忽略的内容重新放出来。
例如:
*.log
!important.log
含义:
- 先忽略所有
.log - 再把
important.log排除出忽略规则,让它重新被 Git 看见
5.1 否定规则的一个关键限制¶
如果父目录已经被忽略,那么子文件往往无法单独救回来,除非父目录本身也被重新放开。
例如:
data/
!data/keep.txt
这通常是不够的。
因为 data/ 整个目录已经被忽略了,Git 不会再深入看它里面的内容。
正确写法一般要这样:
data/
!data/
!data/keep.txt
如果目录里还有更深层级,也可能需要继续逐层放开。
6 匹配优先级与规则顺序¶
.gitignore 的规则是 从上到下依次读取,后面的规则可以覆盖前面的规则。
所以:
最后匹配到的规则生效
例如:
*.txt
!readme.txt
结果:
- 所有
.txt忽略 readme.txt不忽略
如果顺序反过来:
!readme.txt
*.txt
那么最终 readme.txt 还是会被忽略,因为后面的 *.txt 又把它盖掉了。
所以 .gitignore 的书写顺序非常重要。
7 目录与文件匹配的真实理解¶
7.1 foo¶
foo
表示匹配名字叫 foo 的文件或目录,位置不限。
可能匹配:
fooa/foox/y/foo
7.2 foo/¶
foo/
表示匹配名字叫 foo 的目录,位置不限。
匹配:
foo/a/foo/x/y/foo/
不匹配:
- 普通文件
foo
7.3 /foo¶
/foo
表示只匹配根目录的 foo 文件或目录。
7.4 /foo/¶
/foo/
表示只匹配根目录的 foo 目录。
7.5 foo/bar¶
foo/bar
表示匹配某个 foo 目录下的 bar 文件或目录。
如果没有前导 /,一般不是严格限定仓库根目录,而是匹配相对路径模式。