git 笔记之 ignore

在 push 到远程仓库中,往往要忽略中间文件和开发环境配置文件等文件的提交,这时就要设置相应的忽略规则,来自动忽略这些文件。

原则

Git 忽略文件的原则

  • 忽略操作系统自动生成的文件,例如 macOS 中的.DS_Store
  • 忽略编译生成的中间文件、可执行文件等,如果一个文件是通过另一个文件自动生成的,那么就没必要放进版本库,比如 Java 编译产生的 .class 文件
  • 忽略带有敏感信息的配置文件,比如存放口令的配置文件

方式

有三种方法可以实现忽略 Git 中不想提交的文件

  1. 在项目中定义.gitignore 文件
    在项目根目录下定义.gitignore 文件,它往往要提交到公有仓库中,为该项目下的所有开发者都预设定义好的忽略规则。.gitingore 文件每一行指定一个忽略规则。如:
*.log
*.temp
/vendor
  1. 在项目的设置中临时指定排除文件
    这种方式只是临时指定该项目的行为,需要编辑当前项目下的 .git/info/exclude文件,然后将需要忽略提交的文件写入其中。这种方式指定的忽略文件的根目录是项目根目录。

  2. 定义全局的 .gitignore 文件
    除了可以在项目中定义 .gitignore 文件外,还可以设置全局的 git .gitignore文件来管理所有由 git 版本控制项目的行为。这种方式是定义个人开发机的全局环境,不在项目成员中共享。这种方式也需要创建相应的 .gitignore 文件,可以放在任意位置。然后在使用以下命令配置:

$ git config --global core.excludesfile ~/.gitignore

语法

匹配语法

  1. 空格不匹配任意文件,可作为分隔符,可用反斜杠转义
  2. #开头的行代表注释,git 忽略,可以使用反斜杠进行转义
  3. .gitignore使用标准的 glob 模式匹配。glob 模式 ) 往往用于在类 UNIX 系统中匹配文件路径。
  4. 斜杠 / 开头表示目录,/结束的模式只匹配文件夹和该文件夹路径下的内容,/开始的模式匹配项目根目录
  5. 星号 * 通配多个字符,问号 ? 通配单个字符, 使用两个星号 ** 表示匹配任意中间目录
  6. 方括号 [] 包含单个字符的匹配列表,即匹配任何一个列在方括号中的字符。
  7. 感叹号 ! 表示不忽略 (跟踪) 匹配到的文件或目录,即要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号 (!) 取反。如果文件的父目录已经被前面的规则排除掉了,那么对这个文件用”!”规则是不起作用的。也就是说”!”开头的模式表示否定,该文件将会再次被包含,如果排除了该文件的父级目录,则使用”!”也不会再次被包含。可以使用反斜杠进行转义。
  8. .git 对于.ignore 配置文件是按行从上到下进行规则匹配的,意味着如果前面的规则匹配的范围更大,则后面的规则将不会生效!

优先级

在 .gitingore 文件中,每一行指定一个忽略规则,Git 检查忽略规则的时候有多个来源,它的优先级如下(由高到低):

  1. 从命令行中读取可用的忽略规则
  2. 当前目录定义的规则
  3. 父级目录定义的规则,依次递推
  4. $GIT_DIR/info/exclude 文件中定义的规则
  5. core.excludesfile 中定义的全局规则

例:

*.a             #忽略所有目录中所有 .a 结尾的文件
/*.b            #忽略根目录中所有 .b 结尾的文件
**/*.c          #忽略所有目录中子目录中的 .c 结尾的文件
!/1.b           #不忽略根目录下的 1.b 文件
bin/            #忽略当前路径下的 bin 文件夹,该文件夹下的所有内容都会被忽略,不忽略 bin 文件
/bin            #表示忽略根目录下的 bin 文件
a/**/b          #表示忽略 a 目录下所有目录及其子目录中的 b 文件,例如 a/b, a/c/b , a/c/d/b

⚠️
如果如果在版本库中写 .gitignore 文件之前就已经提交了要忽略的文件,那么 Git 仍然会对这些文件进行版本管理。例如已经 commit 了 1.a 这个文件到版本库,再写入 1.a 这条忽略规则到 .gitignore 文件,那么这条规则就失效了。对 1.a 文件的修改仍然会被版本控制。这种情况的解决方式可以参看git rm 删除版本控制

查看规则

我们可以用 git check-ignore 命令检查忽略规则:

$ git check-ignore -v ./bin/root-bin.a
.gitignore:2:/bin	./bin/root-bin.a

可以看到 ./bin/root-bin.a 匹配到了我们的第二行 /bin 的忽略规则,所以文件被忽略了。

删除本地缓存

有的时候已经在.gitignore 中标明忽略的文件,但 git status 中该文件依旧处于 tracted 状态,这是因为在 git 忽略目录中,新建的文件会有缓存,如果某文件已经被纳入版本管理,那么再在.gitignore 中声明也是无效的,此时需要删除本地缓存,这样不会直接删除文件。如果去掉 --cached 选项则是直接删除对应文件。

$ git rm -r --cached .
$ git add .
$ git commit -m ".gitignore updated"

远程仓库中删除版本控制

有的时候想移除远程仓库中的某些文件的版本控制,但依旧在本地保留该文件。这时候不可以直接使用 git rm directory,这样会删除本地仓库的文件。可以使用git rm -r –cached directory 来删除本地缓存,然后进行 commit 和 push,这样会发现远程仓库中的不必要文件就被删除了,以后可以直接使用 git add -A 来添加修改的内容,上传的文件就会受到.gitignore 文件的内容约束。

$ git rm -r --cached 1.a
$ git add -A
$ git commit -m "update .gitignore"
$ git push origin