你不知道的.gitignore

你不知道的.gitignore

0. 几个概念

  • 被gitignore规则命中,即被gitignore规则匹配到的文件或目录,不会被Git追踪,即不会被Git给track

1. 简介

  • .gitignore,是用来显式指定哪些文件或文件夹应该被Git忽略的一个文件
  • $HOME/.gitignore_global, $HOME/.config/git/ignore, $GIT_DIR/info/exclude, .gitignore这些地方指定的ignore规则都会在Git仓库中生效

2. 描述

一个.gitignore文件显式地指定了哪些文件不该被Git追踪,即被Git忽略掉。在被gitignore以前已经被Git追踪的文件不受gitignore规则的影响。关于gitignore规则的详情请继续往下看。html

.gitignore文件中的每一行都指定了一种匹配模式。一般来讲,Git会从多个可能的规则源获取gitignore规则来决定Git是否要忽略某一个具体的路径path,以下按照优先级列出了各类规则源,越靠前的规则优先级越高(在一个规则源内部,若是有多个gitignore匹配,以最后匹配的为准)linux

  • 从命令行输入的规则
  • 该路径下的.gitignore文件,或者父级目录的.gitignore中定义的规则。其中,越靠近具体路径的.gitignore文件的优先级越高,同目录下的.gitignore文件优先级最高。项目仓库中一般都有.gitignore文件,里面会包含忽略项目build自动生成的文件的规则
  • $GIT_DIR/info/exclude中定义的规则
  • Git配置变量core.excludeFile指定的规则

具体讲gitignore规则定义在哪一个文件中取决于该规则的做用(域):git

  • 若是一个gitignore规则应该被Git追踪,别人clone仓库后规则也生效,那么它就应该被定义在.gitignore文件中
  • 若是某个规则只想在某一个特定的仓库中生效,就把它定义在$GIT_DIR/info/exclude中吧
  • 若是你的gitignore规则要在任何状况下都生效,这种规则最好放在core.excludesFile这一变量中,这个变量定义在用户目录下-~/.gitconfig,该变量的默认值是$XDG_CONFIG_HOME/git/ignore,若是$XDG_CONFIG_HOME是空的,Git会使用$HOME/.config/git/ignore

Git的底层管道工具,好比git ls-filesgit read-tree,只从命令行参数||命令行参数指定的文件中读取gitignore规则。上层的Git工具,好比git statusgit add,会从上述规则源中读取gitignore规则shell

3. gitignore规则

  • 空行不匹配任何文件,因此能够用空行来加强gitignore规则的可读性
  • 注释行以#开头。能够在#前加一个反斜杠转义之,使之可以匹配包含#字符的文件夹或文件
  • 若是每一行最后尾随的空格没有用反斜杠转义,那么这些空格是无效的,不会做为规则的一部分
  • 使用!前缀来否认以前的规则。若是一个文件被前面的gitignore规则给匹配到了,那么该文件不会被Git追踪,可是若是后面的规则使用!匹配到了该文件,那么该文件又会被Git追踪。固然,若是一个文件的父目录都被Git忽略了,那么不管如何,这个文件都不会被Git追踪。出于性能考虑,Git不会遍历被忽略的目录,所以,定义在被忽略目录下的gitignore规则都是无效的。有时候,咱们真的是想忽略以感叹号!开头的一个文件或者目录,这时,能够在感叹号!前面加一个反斜杠转义之,好比:\!important.txt会匹配文件!important.txt
  • 若是一个规则以斜杠结尾,在实际匹配的时候,最后的斜杠会被移除掉,可是这个规则只会匹配目录,而不会匹配文件。换句话说,foo/会匹配到目录foofoo下的子目录,但不会匹配到文件foo或者软连接foo
  • 若是规则中不包含斜杠/,Git就会就会把该规则当成通配符规则来进行处理,从该规则所在.gitignore文件所在路径开始匹配。固然,若是这个规则不是放在.gitignore文件中的,就会从work tree的顶部开始匹配
  • 若是规则不符合以上的状况,那么Git就会把这个规则当成shell通配符规则来进行解析,是以带FNM_PATHNAME标记的fnmatch(3)规则进行解析。可是,规则中的通配符不会匹配路径名中的斜杠/。举个栗子,Documentation/*.html匹配Documentation/git.html,但不会匹配Documentation/ppc/ppc.html或者tools/perf/Documentation/perf.html
  • 以斜杠开头的通配符规则从路径开头开始匹配。好比,/*.c匹配cat-file.c,但不匹配mozilla-sha1/sha1.c

两个连续的星号**在匹配全路径名的时候可能有特殊含义:bash

  • 规则以两个星号**开头,后接一个斜杠,这样的规则会在全部路径或子路径中尝试进行匹配。好比,**/foo会匹配到文件foo或者目录foo,不管它在哪一个目录;foo这条规则一样会尝试匹配全部路径中的文件foo或者目录foo**/foo/bar规则会匹配任意文件或目录foo下直接跟的文件bar或目录bar
  • 若是规则中间有连续的两个星号**,那这条规则会匹配下面的全部东西。好比abc/**会匹配目录abc下的全部文件或目录,固然,这里的目录abc是相对于.gitignore文件位置而言的,无限递归
  • 若是规则是斜杠/后跟两个星号,而后再跟一个斜杠的形式,这里的两个星号就会匹配0+个目录,这里的0+是指能够没有,也能够是多个。再举个例子,好比a/**/b会匹配a/ba/x/ba/x/y/b这些
  • 其余形式的连续星号都认为是非法的

4. 笔记

gitignore文件的目的是确保某些不该该被Git追踪的文件确实没有被track。若是要中止track一个已经被Git追踪的文件,请使用git rm --cached Xxx命令工具

5. 示例

$ git status
[...]
# 暂未被Git追踪的文件:
[...]
# Documentation/foo.html
# Documentation/gitignore.html
# file.o
# lib.a
# src/internal.o
[...]
$ cat .git/info/exclude
# 忽略,即再也不追踪仓库中全部的objects和压缩文件.
*.[oa]
$ cat Documentation/.gitignore
# 忽略自动生成的html文件,
*.html
# 排除手动维护的foo.html,即不忽略foo.html,即Git会追踪foo.html
!foo.html
$ git status
[...]
# 暂未被Git追踪的文件:
[...]
# Documentation/foo.html
[...]
复制代码

一个例子不够,再来一个:性能

$ cat .gitignore
vmlinux*
$ ls arch/foo/kernel/vm*
arch/foo/kernel/vmlinux.lds.S
$ echo '!/vmlinux*' > arch/foo/kernel/.gitignore
复制代码

在这个例子中,第二个.gitignore文件arch/foo/kernel/.gitignore的优先级更高,它阻止了第一个.gitignore文件试图忽略arch/foo/kernel/vmlinux.lds.S的行为,从而,Git不会忽略arch/foo/kernel/vmlinux.lds.S,会尝试追踪它ui

最后再来一个例子收尾。举个忽略目录下全部文件或目录,除了某个特定的目录foo/bar的例子吧(注意下面的/*,就算没有前面的斜杠,通配符也会匹配包括foo/bar在内的全部文件或目录,因此斜杠/是无关紧要的):spa

$ cat .gitignore
# exclude everything except directory foo/bar
/*
!/foo
/foo/*
!/foo/bar
复制代码

6. 补充示例

译文到此完毕,我再补充几个小例子吧命令行

6.1 示例一

6.2 示例二

6.3 示例三

相关文章
相关标签/搜索