git的多个命令都需要指定pathspec。本文探讨一下git的pathspec。
git的pathspec概念在gitglossay: pathspec中有说明。主要有两种格式,一种长格式和一种短格式。长格式比如::(glob,exclude)foo/bar.txt
。长格式的某些关键字具有短格式,比如exlcude关键字的短格式是!
,短格式比如:!/foo/bar.txt
。
像:(glob,exclude)foo/bar.txt
这个pathspec中,路径是foo/bar.txt
,git在匹配的时候会把路径一分为二,最后一个/
以及之前的部分被认为是目录部分,/
之后的部分被认为是文件名部分。这两个部分分开匹配。
下面来做一些实验,假设有一个git仓库,在不同的目录存储若干个aa.txt
文件,其git ls-files "*.txt"
输出是
aa.txt
bb/aa.txt
cc/bb/aa.txt
执行git ls-files "*.txt" ":!bb/aa.txt"
命令,输出:
aa.txt
cc/bb/aa.txt
上面的pathspec是:!bb/aa.txt
,!
是exclude的缩写,也就意味着过滤bb/aa.txt
。
执行git ls-files "*.txt" ":!**/bb/aa.txt"
:
aa.txt
bb/aa.txt
:!**/bb/aa.txt
把cc/bb/aa.txt
给过滤掉了。
执行git ls-files "*.txt" ":!/bb/**"
,得到:
aa.txt
cc/bb/aa.txt
bb/aa.txt
被:!/bb/**
过滤掉了。
在上面的例子中都使用了**
作为通配符,其实**
只有在指定了glob选项的时候才有特殊含义,否则和普通的*
没有两样,参考fnmatch。
下面是采用*
的例子:
执行git ls-files "*.txt" ":!*/bb/*"
:
aa.txt
bb/aa.txt
上面的:!*/bb/*
只过滤掉了cc/bb/aa.txt
,却没有过滤掉bb/aa.txt
。因为:!*/bb/*
中的bb前面有一个/
。
去掉bb前面的/
,执行git ls-files "*.txt" ":!*bb/*"
:
aa.txt
也可以开启glob选项,让**
生效。执行git ls-files "*.txt" ":(glob,exclude)**/cc/**"
:
aa.txt
bb/aa.txt
在glob开启的情况下,**
可以跨路径匹配多个目录成分。
下面是另外一个例子,你可以在.git/info/spare-checkout
中书写规则,比如:
Document/*.jpg
fnmatch(3)
:(glob)/Document/**
:!:/Document/**/
然后在gitconfig开启中开启spare-checkout选项,就可以在checkout的时候避免checkout某些文件。
参考
(完)