Support "**" wildcard in .gitignore and .gitattributes
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nguyễn Thái Ngọc Duy committed
Oct 15, 2012 at 13:26 UTC
237ec6e40d4fd1a0190c4ffde6d18278abc5853a
4 files changed
+77
-1
Documentation/gitignore.txt
+19
@@ -96,6 +96,25 @@ PATTERN FORMAT
96
For example, "/{asterisk}.c" matches "cat-file.c" but not
97
"mozilla-sha1/sha1.c".
98
99
+Two consecutive asterisks ("`**`") in patterns matched against
100
+full pathname may have special meaning:
101
+
102
+ - A leading "`**`" followed by a slash means match in all
103
+ directories. For example, "`**/foo`" matches file or directory
104
+ "`foo`" anywhere, the same as pattern "`foo`". "**/foo/bar"
105
+ matches file or directory "`bar`" anywhere that is directly
106
+ under directory "`foo`".
107
+
108
+ - A trailing "/**" matches everything inside. For example,
109
+ "abc/**" matches all files inside directory "abc", relative
110
+ to the location of the `.gitignore` file, with infinite depth.
111
+
112
+ - A slash followed by two consecutive asterisks then a slash
113
+ matches zero or more directories. For example, "`a/**/b`"
114
+ matches "`a/b`", "`a/x/b`", "`a/x/y/b`" and so on.
115
+
116
+ - Other consecutive asterisks are considered invalid.
117
+
118
NOTES
119
-----
120
dir.c
+3
-1
@@ -8,6 +8,7 @@
8
#include "cache.h"
9
#include "dir.h"
10
#include "refs.h"
11
+#include "wildmatch.h"
12
13
struct path_simplify {
14
int len;
@@ -593,7 +594,8 @@ int match_pathname(const char *pathname, int pathlen,
594
namelen -= prefix;
595
}
596
596
- return fnmatch_icase(pattern, name, FNM_PATHNAME) == 0;
597
+ return wildmatch(pattern, name,
598
+ ignore_case ? FNM_CASEFOLD : 0) == 0;
599
}
600
601
/* Scan the list and let the last match determine the fate.
t/t0003-attributes.sh
+37
@@ -216,6 +216,43 @@ test_expect_success 'patterns starting with exclamation' '
216
attr_check "!f" foo
217
'
218
219
+test_expect_success '"**" test' '
220
+ echo "**/f foo=bar" >.gitattributes &&
221
+ cat <<\EOF >expect &&
222
+f: foo: bar
223
+a/f: foo: bar
224
+a/b/f: foo: bar
225
+a/b/c/f: foo: bar
226
+EOF
227
+ git check-attr foo -- "f" >actual 2>err &&
228
+ git check-attr foo -- "a/f" >>actual 2>>err &&
229
+ git check-attr foo -- "a/b/f" >>actual 2>>err &&
230
+ git check-attr foo -- "a/b/c/f" >>actual 2>>err &&
231
+ test_cmp expect actual &&
232
+ test_line_count = 0 err
233
+'
234
+
235
+test_expect_success '"**" with no slashes test' '
236
+ echo "a**f foo=bar" >.gitattributes &&
237
+ git check-attr foo -- "f" >actual &&
238
+ cat <<\EOF >expect &&
239
+f: foo: unspecified
240
+af: foo: bar
241
+axf: foo: bar
242
+a/f: foo: unspecified
243
+a/b/f: foo: unspecified
244
+a/b/c/f: foo: unspecified
245
+EOF
246
+ git check-attr foo -- "f" >actual 2>err &&
247
+ git check-attr foo -- "af" >>actual 2>err &&
248
+ git check-attr foo -- "axf" >>actual 2>err &&
249
+ git check-attr foo -- "a/f" >>actual 2>>err &&
250
+ git check-attr foo -- "a/b/f" >>actual 2>>err &&
251
+ git check-attr foo -- "a/b/c/f" >>actual 2>>err &&
252
+ test_cmp expect actual &&
253
+ test_line_count = 0 err
254
+'
255
+
256
test_expect_success 'setup bare' '
257
git clone --bare . bare.git &&
258
cd bare.git
t/t3001-ls-files-others-exclude.sh
+18
@@ -220,4 +220,22 @@ test_expect_success 'pattern matches prefix completely' '
220
test_cmp expect actual
221
'
222
223
+test_expect_success 'ls-files with "**" patterns' '
224
+ cat <<\EOF >expect &&
225
+a.1
226
+one/a.1
227
+one/two/a.1
228
+three/a.1
229
+EOF
230
+ git ls-files -o -i --exclude "**/a.1" >actual
231
+ test_cmp expect actual
232
+'
233
+
234
+
235
+test_expect_success 'ls-files with "**" patterns and no slashes' '
236
+ : >expect &&
237
+ git ls-files -o -i --exclude "one**a.1" >actual &&
238
+ test_cmp expect actual
239
+'
240
+
241
test_done