1#!/bin/sh
2
3test_description=check-ignore
4
5. ./test-lib.sh
6
7init_vars () {
8 global_excludes="$(pwd)/global-excludes"
9}
10
11enable_global_excludes () {
12 init_vars &&
13 git config core.excludesfile "$global_excludes"
14}
15
16expect_in () {
17 dest="$HOME/expected-$1" text="$2"
18 if test -z "$text"
19 then
20 >"$dest" # avoid newline
21 else
22 echo "$text" >"$dest"
23 fi
24}
25
26expect () {
27 expect_in stdout "$1"
28}
29
30expect_from_stdin () {
31 cat >"$HOME/expected-stdout"
32}
33
34test_stderr () {
35 expected="$1"
36 expect_in stderr "$1" &&
37 test_cmp "$HOME/expected-stderr" "$HOME/stderr"
38}
39
40stderr_contains () {
41 regexp="$1"
42 if grep "$regexp" "$HOME/stderr"
43 then
44 return 0
45 else
46 echo "didn't find /$regexp/ in $HOME/stderr"
47 cat "$HOME/stderr"
48 return 1
49 fi
50}
51
52stderr_empty_on_success () {
53 expect_code="$1"
54 if test $expect_code = 0
55 then
56 test_stderr ""
57 else
58 # If we expect failure then stderr might or might not be empty
59 # due to --quiet - the caller can check its contents
60 return 0
61 fi
62}
63
64test_check_ignore () {
65 args="$1" expect_code="${2:-0}" global_args="$3"
66
67 init_vars &&
68 rm -f "$HOME/stdout" "$HOME/stderr" "$HOME/cmd" &&
69 echo git $global_args check-ignore $quiet_opt $verbose_opt $args \
70 >"$HOME/cmd" &&
71 test_expect_code "$expect_code" \
72 git $global_args check-ignore $quiet_opt $verbose_opt $args \
73 >"$HOME/stdout" 2>"$HOME/stderr" &&
74 test_cmp "$HOME/expected-stdout" "$HOME/stdout" &&
75 stderr_empty_on_success "$expect_code"
76}
77
78test_expect_success_multi () {
79 prereq=
80 if test $# -eq 4
81 then
82 prereq=$1
83 shift
84 fi
85 testname="$1" expect_verbose="$2" code="$3"
86
87 expect=$( echo "$expect_verbose" | sed -e 's/.* //' )
88
89 test_expect_success $prereq "$testname" '
90 expect "$expect" &&
91 eval "$code"
92 '
93
94 for quiet_opt in '-q' '--quiet'
95 do
96 test_expect_success $prereq "$testname${quiet_opt:+ with $quiet_opt}" "
97 expect '' &&
98 $code
99 "
100 done
101 quiet_opt=
102
103 for verbose_opt in '-v' '--verbose'
104 do
105 test_expect_success $prereq "$testname${verbose_opt:+ with $verbose_opt}" "
106 expect '$expect_verbose' &&
107 $code
108 "
109 done
110 verbose_opt=
111}
112
113test_expect_success 'setup' '
114 init_vars &&
115 mkdir -p a/b/ignored-dir a/submodule b &&
116 if test_have_prereq SYMLINKS
117 then
118 ln -s b a/symlink
119 fi &&
120 (
121 cd a/submodule &&
122 git init &&
123 echo a >a &&
124 git add a &&
125 git commit -m"commit in submodule"
126 ) &&
127 git add a/submodule &&
128 cat <<-\EOF >.gitignore &&
129 one
130 ignored-*
131 EOF
132 for dir in . a
133 do
134 : >$dir/not-ignored &&
135 : >$dir/ignored-and-untracked &&
136 : >$dir/ignored-but-in-index
137 done &&
138 git add -f ignored-but-in-index a/ignored-but-in-index &&
139 cat <<-\EOF >a/.gitignore &&
140 two*
141 *three
142 EOF
143 cat <<-\EOF >a/b/.gitignore &&
144 four
145 five
146 # this comment should affect the line numbers
147 six
148 ignored-dir/
149 # and so should this blank line:
150
151 !on*
152 !two
153 EOF
154 echo "seven" >a/b/ignored-dir/.gitignore &&
155 test -n "$HOME" &&
156 cat <<-\EOF >"$global_excludes" &&
157 globalone
158 !globaltwo
159 globalthree
160 EOF
161 cat <<-\EOF >>.git/info/exclude
162 per-repo
163 EOF
164'
165
166############################################################################
167#
168# test invalid inputs
169
170test_expect_success_multi 'empty command line' '' '
171 test_check_ignore "" 128 &&
172 stderr_contains "fatal: no path specified"
173'
174
175test_expect_success_multi '--stdin with empty STDIN' '' '
176 test_check_ignore "--stdin" 1 </dev/null &&
177 if test -n "$quiet_opt"; then
178 test_stderr ""
179 else
180 test_stderr "no pathspec given."
181 fi
182'
183
184test_expect_success '-q with multiple args' '
185 expect "" &&
186 test_check_ignore "-q one two" 128 &&
187 stderr_contains "fatal: --quiet is only valid with a single pathname"
188'
189
190test_expect_success '--quiet with multiple args' '
191 expect "" &&
192 test_check_ignore "--quiet one two" 128 &&
193 stderr_contains "fatal: --quiet is only valid with a single pathname"
194'
195
196for verbose_opt in '-v' '--verbose'
197do
198 for quiet_opt in '-q' '--quiet'
199 do
200 test_expect_success "$quiet_opt $verbose_opt" "
201 expect '' &&
202 test_check_ignore '$quiet_opt $verbose_opt foo' 128 &&
203 stderr_contains 'fatal: cannot have both --quiet and --verbose'
204 "
205 done
206done
207
208test_expect_success '--quiet with multiple args' '
209 expect "" &&
210 test_check_ignore "--quiet one two" 128 &&
211 stderr_contains "fatal: --quiet is only valid with a single pathname"
212'
213
214test_expect_success_multi 'erroneous use of --' '' '
215 test_check_ignore "--" 128 &&
216 stderr_contains "fatal: no path specified"
217'
218
219test_expect_success_multi '--stdin with superfluous arg' '' '
220 test_check_ignore "--stdin foo" 128 &&
221 stderr_contains "fatal: cannot specify pathnames with --stdin"
222'
223
224test_expect_success_multi '--stdin -z with superfluous arg' '' '
225 test_check_ignore "--stdin -z foo" 128 &&
226 stderr_contains "fatal: cannot specify pathnames with --stdin"
227'
228
229test_expect_success_multi '-z without --stdin' '' '
230 test_check_ignore "-z" 128 &&
231 stderr_contains "fatal: -z only makes sense with --stdin"
232'
233
234test_expect_success_multi '-z without --stdin and superfluous arg' '' '
235 test_check_ignore "-z foo" 128 &&
236 stderr_contains "fatal: -z only makes sense with --stdin"
237'
238
239test_expect_success_multi 'needs work tree' '' '
240 (
241 cd .git &&
242 test_check_ignore "foo" 128
243 ) &&
244 stderr_contains "fatal: This operation must be run in a work tree"
245'
246
247############################################################################
248#
249# test standard ignores
250
251# First make sure that the presence of a file in the working tree
252# does not impact results, but that the presence of a file in the
253# index does.
254
255for subdir in '' 'a/'
256do
257 if test -z "$subdir"
258 then
259 where="at top-level"
260 else
261 where="in subdir $subdir"
262 fi
263
264 test_expect_success_multi "non-existent file $where not ignored" '' "
265 test_check_ignore '${subdir}non-existent' 1
266 "
267
268 test_expect_success_multi "non-existent file $where ignored" \
269 ".gitignore:1:one ${subdir}one" "
270 test_check_ignore '${subdir}one'
271 "
272
273 test_expect_success_multi "existing untracked file $where not ignored" '' "
274 test_check_ignore '${subdir}not-ignored' 1
275 "
276
277 test_expect_success_multi "existing tracked file $where not ignored" '' "
278 test_check_ignore '${subdir}ignored-but-in-index' 1
279 "
280
281 test_expect_success_multi "existing untracked file $where ignored" \
282 ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" "
283 test_check_ignore '${subdir}ignored-and-untracked'
284 "
285done
286
287# Having established the above, from now on we mostly test against
288# files which do not exist in the working tree or index.
289
290test_expect_success 'sub-directory local ignore' '
291 expect "a/3-three" &&
292 test_check_ignore "a/3-three a/three-not-this-one"
293'
294
295test_expect_success 'sub-directory local ignore with --verbose' '
296 expect "a/.gitignore:2:*three a/3-three" &&
297 test_check_ignore "--verbose a/3-three a/three-not-this-one"
298'
299
300test_expect_success 'local ignore inside a sub-directory' '
301 expect "3-three" &&
302 (
303 cd a &&
304 test_check_ignore "3-three three-not-this-one"
305 )
306'
307test_expect_success 'local ignore inside a sub-directory with --verbose' '
308 expect "a/.gitignore:2:*three 3-three" &&
309 (
310 cd a &&
311 test_check_ignore "--verbose 3-three three-not-this-one"
312 )
313'
314
315test_expect_success_multi 'nested include' \
316 'a/b/.gitignore:8:!on* a/b/one' '
317 test_check_ignore "a/b/one"
318'
319
320############################################################################
321#
322# test ignored sub-directories
323
324test_expect_success_multi 'ignored sub-directory' \
325 'a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir' '
326 test_check_ignore "a/b/ignored-dir"
327'
328
329test_expect_success 'multiple files inside ignored sub-directory' '
330 expect_from_stdin <<-\EOF &&
331 a/b/ignored-dir/foo
332 a/b/ignored-dir/twoooo
333 a/b/ignored-dir/seven
334 EOF
335 test_check_ignore "a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven"
336'
337
338test_expect_success 'multiple files inside ignored sub-directory with -v' '
339 expect_from_stdin <<-\EOF &&
340 a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/foo
341 a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/twoooo
342 a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/seven
343 EOF
344 test_check_ignore "-v a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven"
345'
346
347test_expect_success 'cd to ignored sub-directory' '
348 expect_from_stdin <<-\EOF &&
349 foo
350 twoooo
351 ../one
352 seven
353 ../../one
354 EOF
355 (
356 cd a/b/ignored-dir &&
357 test_check_ignore "foo twoooo ../one seven ../../one"
358 )
359'
360
361test_expect_success 'cd to ignored sub-directory with -v' '
362 expect_from_stdin <<-\EOF &&
363 a/b/.gitignore:5:ignored-dir/ foo
364 a/b/.gitignore:5:ignored-dir/ twoooo
365 a/b/.gitignore:8:!on* ../one
366 a/b/.gitignore:5:ignored-dir/ seven
367 .gitignore:1:one ../../one
368 EOF
369 (
370 cd a/b/ignored-dir &&
371 test_check_ignore "-v foo twoooo ../one seven ../../one"
372 )
373'
374
375############################################################################
376#
377# test handling of symlinks
378
379test_expect_success_multi SYMLINKS 'symlink' '' '
380 test_check_ignore "a/symlink" 1
381'
382
383test_expect_success_multi SYMLINKS 'beyond a symlink' '' '
384 test_check_ignore "a/symlink/foo" 128 &&
385 test_stderr "fatal: '\''a/symlink/foo'\'' is beyond a symbolic link"
386'
387
388test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' '
389 (
390 cd a &&
391 test_check_ignore "symlink/foo" 128
392 ) &&
393 test_stderr "fatal: '\''symlink/foo'\'' is beyond a symbolic link"
394'
395
396############################################################################
397#
398# test handling of submodules
399
400test_expect_success_multi 'submodule' '' '
401 test_check_ignore "a/submodule/one" 128 &&
402 test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
403'
404
405test_expect_success_multi 'submodule from subdirectory' '' '
406 (
407 cd a &&
408 test_check_ignore "submodule/one" 128
409 ) &&
410 test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
411'
412
413############################################################################
414#
415# test handling of global ignore files
416
417test_expect_success 'global ignore not yet enabled' '
418 expect_from_stdin <<-\EOF &&
419 .git/info/exclude:7:per-repo per-repo
420 a/.gitignore:2:*three a/globalthree
421 .git/info/exclude:7:per-repo a/per-repo
422 EOF
423 test_check_ignore "-v globalone per-repo a/globalthree a/per-repo not-ignored a/globaltwo"
424'
425
426test_expect_success 'global ignore' '
427 enable_global_excludes &&
428 expect_from_stdin <<-\EOF &&
429 globalone
430 per-repo
431 globalthree
432 a/globalthree
433 a/per-repo
434 globaltwo
435 EOF
436 test_check_ignore "globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo"
437'
438
439test_expect_success 'global ignore with -v' '
440 enable_global_excludes &&
441 expect_from_stdin <<-EOF &&
442 $global_excludes:1:globalone globalone
443 .git/info/exclude:7:per-repo per-repo
444 $global_excludes:3:globalthree globalthree
445 a/.gitignore:2:*three a/globalthree
446 .git/info/exclude:7:per-repo a/per-repo
447 $global_excludes:2:!globaltwo globaltwo
448 EOF
449 test_check_ignore "-v globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo"
450'
451
452############################################################################
453#
454# test --stdin
455
456cat <<-\EOF >stdin
457 one
458 not-ignored
459 a/one
460 a/not-ignored
461 a/b/on
462 a/b/one
463 a/b/one one
464 "a/b/one two"
465 "a/b/one\"three"
466 a/b/not-ignored
467 a/b/two
468 a/b/twooo
469 globaltwo
470 a/globaltwo
471 a/b/globaltwo
472 b/globaltwo
473EOF
474cat <<-\EOF >expected-default
475 one
476 a/one
477 a/b/on
478 a/b/one
479 a/b/one one
480 a/b/one two
481 "a/b/one\"three"
482 a/b/two
483 a/b/twooo
484 globaltwo
485 a/globaltwo
486 a/b/globaltwo
487 b/globaltwo
488EOF
489cat <<-EOF >expected-verbose
490 .gitignore:1:one one
491 .gitignore:1:one a/one
492 a/b/.gitignore:8:!on* a/b/on
493 a/b/.gitignore:8:!on* a/b/one
494 a/b/.gitignore:8:!on* a/b/one one
495 a/b/.gitignore:8:!on* a/b/one two
496 a/b/.gitignore:8:!on* "a/b/one\"three"
497 a/b/.gitignore:9:!two a/b/two
498 a/.gitignore:1:two* a/b/twooo
499 $global_excludes:2:!globaltwo globaltwo
500 $global_excludes:2:!globaltwo a/globaltwo
501 $global_excludes:2:!globaltwo a/b/globaltwo
502 $global_excludes:2:!globaltwo b/globaltwo
503EOF
504
505sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
506 tr "\n" "\0" >stdin0
507sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \
508 tr "\n" "\0" >expected-default0
509sed -e 's/ "/ /' -e 's/\\//' -e 's/"$//' expected-verbose | \
510 tr ":\t\n" "\0" >expected-verbose0
511
512test_expect_success '--stdin' '
513 expect_from_stdin <expected-default &&
514 test_check_ignore "--stdin" <stdin
515'
516
517test_expect_success '--stdin -q' '
518 expect "" &&
519 test_check_ignore "-q --stdin" <stdin
520'
521
522test_expect_success '--stdin -v' '
523 expect_from_stdin <expected-verbose &&
524 test_check_ignore "-v --stdin" <stdin
525'
526
527for opts in '--stdin -z' '-z --stdin'
528do
529 test_expect_success "$opts" "
530 expect_from_stdin <expected-default0 &&
531 test_check_ignore '$opts' <stdin0
532 "
533
534 test_expect_success "$opts -q" "
535 expect "" &&
536 test_check_ignore '-q $opts' <stdin0
537 "
538
539 test_expect_success "$opts -v" "
540 expect_from_stdin <expected-verbose0 &&
541 test_check_ignore '-v $opts' <stdin0
542 "
543done
544
545cat <<-\EOF >stdin
546 ../one
547 ../not-ignored
548 one
549 not-ignored
550 b/on
551 b/one
552 b/one one
553 "b/one two"
554 "b/one\"three"
555 b/two
556 b/not-ignored
557 b/twooo
558 ../globaltwo
559 globaltwo
560 b/globaltwo
561 ../b/globaltwo
562EOF
563cat <<-\EOF >expected-default
564 ../one
565 one
566 b/on
567 b/one
568 b/one one
569 b/one two
570 "b/one\"three"
571 b/two
572 b/twooo
573 ../globaltwo
574 globaltwo
575 b/globaltwo
576 ../b/globaltwo
577EOF
578cat <<-EOF >expected-verbose
579 .gitignore:1:one ../one
580 .gitignore:1:one one
581 a/b/.gitignore:8:!on* b/on
582 a/b/.gitignore:8:!on* b/one
583 a/b/.gitignore:8:!on* b/one one
584 a/b/.gitignore:8:!on* b/one two
585 a/b/.gitignore:8:!on* "b/one\"three"
586 a/b/.gitignore:9:!two b/two
587 a/.gitignore:1:two* b/twooo
588 $global_excludes:2:!globaltwo ../globaltwo
589 $global_excludes:2:!globaltwo globaltwo
590 $global_excludes:2:!globaltwo b/globaltwo
591 $global_excludes:2:!globaltwo ../b/globaltwo
592EOF
593
594sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
595 tr "\n" "\0" >stdin0
596sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \
597 tr "\n" "\0" >expected-default0
598sed -e 's/ "/ /' -e 's/\\//' -e 's/"$//' expected-verbose | \
599 tr ":\t\n" "\0" >expected-verbose0
600
601test_expect_success '--stdin from subdirectory' '
602 expect_from_stdin <expected-default &&
603 (
604 cd a &&
605 test_check_ignore "--stdin" <../stdin
606 )
607'
608
609test_expect_success '--stdin from subdirectory with -v' '
610 expect_from_stdin <expected-verbose &&
611 (
612 cd a &&
613 test_check_ignore "--stdin -v" <../stdin
614 )
615'
616
617for opts in '--stdin -z' '-z --stdin'
618do
619 test_expect_success "$opts from subdirectory" '
620 expect_from_stdin <expected-default0 &&
621 (
622 cd a &&
623 test_check_ignore "'"$opts"'" <../stdin0
624 )
625 '
626
627 test_expect_success "$opts from subdirectory with -v" '
628 expect_from_stdin <expected-verbose0 &&
629 (
630 cd a &&
631 test_check_ignore "'"$opts"' -v" <../stdin0
632 )
633 '
634done
635
636
637test_done