Merge branch 'jc/revision-range-unpeel'
[git/mjg.git] / t / t0008-ignores.sh
blob181513ab4fba47750b3e6b25eb105f2c8a4a011f
1 #!/bin/sh
3 test_description=check-ignore
5 . ./test-lib.sh
7 init_vars () {
8 global_excludes="$(pwd)/global-excludes"
11 enable_global_excludes () {
12 init_vars &&
13 git config core.excludesfile "$global_excludes"
16 expect_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"
26 expect () {
27 expect_in stdout "$1"
30 expect_from_stdin () {
31 cat >"$HOME/expected-stdout"
34 test_stderr () {
35 expected="$1"
36 expect_in stderr "$1" &&
37 test_cmp "$HOME/expected-stderr" "$HOME/stderr"
40 stderr_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
52 stderr_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
64 test_check_ignore () {
65 args="$1" expect_code="${2:-0}" global_args="$3"
67 init_vars &&
68 rm -f "$HOME/stdout" "$HOME/stderr" "$HOME/cmd" &&
69 echo git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $no_index_opt $args \
70 >"$HOME/cmd" &&
71 echo "$expect_code" >"$HOME/expected-exit-code" &&
72 test_expect_code "$expect_code" \
73 git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $no_index_opt $args \
74 >"$HOME/stdout" 2>"$HOME/stderr" &&
75 test_cmp "$HOME/expected-stdout" "$HOME/stdout" &&
76 stderr_empty_on_success "$expect_code"
79 # Runs the same code with 4 different levels of output verbosity:
81 # 1. with -q / --quiet
82 # 2. with default verbosity
83 # 3. with -v / --verbose
84 # 4. with -v / --verbose, *and* -n / --non-matching
86 # expecting success each time. Takes advantage of the fact that
87 # check-ignore --verbose output is the same as normal output except
88 # for the extra first column.
90 # A parameter is used to determine if the tests are run with the
91 # normal case (using the index), or with the --no-index option.
93 # Arguments:
94 # - (optional) prereqs for this test, e.g. 'SYMLINKS'
95 # - test name
96 # - output to expect from the fourth verbosity mode (the output
97 # from the other verbosity modes is automatically inferred
98 # from this value)
99 # - code to run (should invoke test_check_ignore)
100 # - index option: --index or --no-index
101 test_expect_success_multiple () {
102 prereq=
103 if test $# -eq 5
104 then
105 prereq=$1
106 shift
108 if test "$4" = "--index"
109 then
110 no_index_opt=
111 else
112 no_index_opt=$4
114 testname="$1" expect_all="$2" code="$3"
116 expect_verbose=$( echo "$expect_all" | grep -v '^:: ' )
117 expect=$( echo "$expect_verbose" | sed -e 's/.* //' )
119 test_expect_success $prereq "$testname${no_index_opt:+ with $no_index_opt}" '
120 expect "$expect" &&
121 eval "$code"
124 # --quiet is only valid when a single pattern is passed
125 if test $( echo "$expect_all" | wc -l ) = 1
126 then
127 for quiet_opt in '-q' '--quiet'
129 opts="${no_index_opt:+$no_index_opt }$quiet_opt"
130 test_expect_success $prereq "$testname${opts:+ with $opts}" "
131 expect '' &&
132 $code
134 done
135 quiet_opt=
138 for verbose_opt in '-v' '--verbose'
140 for non_matching_opt in '' '-n' '--non-matching'
142 if test -n "$non_matching_opt"
143 then
144 my_expect="$expect_all"
145 else
146 my_expect="$expect_verbose"
149 test_code="
150 expect '$my_expect' &&
151 $code
153 opts="${no_index_opt:+$no_index_opt }$verbose_opt${non_matching_opt:+ $non_matching_opt}"
154 test_expect_success $prereq "$testname${opts:+ with $opts}" "$test_code"
155 done
156 done
157 verbose_opt=
158 non_matching_opt=
159 no_index_opt=
162 test_expect_success_multi () {
163 test_expect_success_multiple "$@" "--index"
166 test_expect_success_no_index_multi () {
167 test_expect_success_multiple "$@" "--no-index"
170 test_expect_success 'setup' '
171 init_vars &&
172 mkdir -p a/b/ignored-dir a/submodule b &&
173 if test_have_prereq SYMLINKS
174 then
175 ln -s b a/symlink
176 fi &&
178 cd a/submodule &&
179 git init &&
180 echo a >a &&
181 git add a &&
182 git commit -m"commit in submodule"
183 ) &&
184 git add a/submodule &&
185 cat <<-\EOF >.gitignore &&
187 ignored-*
188 top-level-dir/
190 for dir in . a
192 : >$dir/not-ignored &&
193 : >$dir/ignored-and-untracked &&
194 : >$dir/ignored-but-in-index
195 done &&
196 git add -f ignored-but-in-index a/ignored-but-in-index &&
197 cat <<-\EOF >a/.gitignore &&
198 two*
199 *three
201 cat <<-\EOF >a/b/.gitignore &&
202 four
203 five
204 # this comment should affect the line numbers
206 ignored-dir/
207 # and so should this blank line:
209 !on*
210 !two
212 echo "seven" >a/b/ignored-dir/.gitignore &&
213 test -n "$HOME" &&
214 cat <<-\EOF >"$global_excludes" &&
215 globalone
216 !globaltwo
217 globalthree
219 cat <<-\EOF >>.git/info/exclude
220 per-repo
224 ############################################################################
226 # test invalid inputs
228 test_expect_success_multi '. corner-case' ':: .' '
229 test_check_ignore . 1
232 test_expect_success_multi 'empty command line' '' '
233 test_check_ignore "" 128 &&
234 stderr_contains "fatal: no path specified"
237 test_expect_success_multi '--stdin with empty STDIN' '' '
238 test_check_ignore "--stdin" 1 </dev/null &&
239 test_stderr ""
242 test_expect_success '-q with multiple args' '
243 expect "" &&
244 test_check_ignore "-q one two" 128 &&
245 stderr_contains "fatal: --quiet is only valid with a single pathname"
248 test_expect_success '--quiet with multiple args' '
249 expect "" &&
250 test_check_ignore "--quiet one two" 128 &&
251 stderr_contains "fatal: --quiet is only valid with a single pathname"
254 for verbose_opt in '-v' '--verbose'
256 for quiet_opt in '-q' '--quiet'
258 test_expect_success "$quiet_opt $verbose_opt" "
259 expect '' &&
260 test_check_ignore '$quiet_opt $verbose_opt foo' 128 &&
261 stderr_contains 'fatal: cannot have both --quiet and --verbose'
263 done
264 done
266 test_expect_success '--quiet with multiple args' '
267 expect "" &&
268 test_check_ignore "--quiet one two" 128 &&
269 stderr_contains "fatal: --quiet is only valid with a single pathname"
272 test_expect_success_multi 'erroneous use of --' '' '
273 test_check_ignore "--" 128 &&
274 stderr_contains "fatal: no path specified"
277 test_expect_success_multi '--stdin with superfluous arg' '' '
278 test_check_ignore "--stdin foo" 128 &&
279 stderr_contains "fatal: cannot specify pathnames with --stdin"
282 test_expect_success_multi '--stdin -z with superfluous arg' '' '
283 test_check_ignore "--stdin -z foo" 128 &&
284 stderr_contains "fatal: cannot specify pathnames with --stdin"
287 test_expect_success_multi '-z without --stdin' '' '
288 test_check_ignore "-z" 128 &&
289 stderr_contains "fatal: -z only makes sense with --stdin"
292 test_expect_success_multi '-z without --stdin and superfluous arg' '' '
293 test_check_ignore "-z foo" 128 &&
294 stderr_contains "fatal: -z only makes sense with --stdin"
297 test_expect_success_multi 'needs work tree' '' '
299 cd .git &&
300 test_check_ignore "foo" 128
301 ) &&
302 stderr_contains "fatal: This operation must be run in a work tree"
305 ############################################################################
307 # test standard ignores
309 # First make sure that the presence of a file in the working tree
310 # does not impact results, but that the presence of a file in the
311 # index does unless the --no-index option is used.
313 for subdir in '' 'a/'
315 if test -z "$subdir"
316 then
317 where="at top-level"
318 else
319 where="in subdir $subdir"
322 test_expect_success_multi "non-existent file $where not ignored" \
323 ":: ${subdir}non-existent" \
324 "test_check_ignore '${subdir}non-existent' 1"
326 test_expect_success_no_index_multi "non-existent file $where not ignored" \
327 ":: ${subdir}non-existent" \
328 "test_check_ignore '${subdir}non-existent' 1"
330 test_expect_success_multi "non-existent file $where ignored" \
331 ".gitignore:1:one ${subdir}one" \
332 "test_check_ignore '${subdir}one'"
334 test_expect_success_no_index_multi "non-existent file $where ignored" \
335 ".gitignore:1:one ${subdir}one" \
336 "test_check_ignore '${subdir}one'"
338 test_expect_success_multi "existing untracked file $where not ignored" \
339 ":: ${subdir}not-ignored" \
340 "test_check_ignore '${subdir}not-ignored' 1"
342 test_expect_success_no_index_multi "existing untracked file $where not ignored" \
343 ":: ${subdir}not-ignored" \
344 "test_check_ignore '${subdir}not-ignored' 1"
346 test_expect_success_multi "existing tracked file $where not ignored" \
347 ":: ${subdir}ignored-but-in-index" \
348 "test_check_ignore '${subdir}ignored-but-in-index' 1"
350 test_expect_success_no_index_multi "existing tracked file $where shown as ignored" \
351 ".gitignore:2:ignored-* ${subdir}ignored-but-in-index" \
352 "test_check_ignore '${subdir}ignored-but-in-index'"
354 test_expect_success_multi "existing untracked file $where ignored" \
355 ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
356 "test_check_ignore '${subdir}ignored-and-untracked'"
358 test_expect_success_no_index_multi "existing untracked file $where ignored" \
359 ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
360 "test_check_ignore '${subdir}ignored-and-untracked'"
362 test_expect_success_multi "mix of file types $where" \
363 ":: ${subdir}non-existent
364 .gitignore:1:one ${subdir}one
365 :: ${subdir}not-ignored
366 :: ${subdir}ignored-but-in-index
367 .gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
368 "test_check_ignore '
369 ${subdir}non-existent
370 ${subdir}one
371 ${subdir}not-ignored
372 ${subdir}ignored-but-in-index
373 ${subdir}ignored-and-untracked'
376 test_expect_success_no_index_multi "mix of file types $where" \
377 ":: ${subdir}non-existent
378 .gitignore:1:one ${subdir}one
379 :: ${subdir}not-ignored
380 .gitignore:2:ignored-* ${subdir}ignored-but-in-index
381 .gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
382 "test_check_ignore '
383 ${subdir}non-existent
384 ${subdir}one
385 ${subdir}not-ignored
386 ${subdir}ignored-but-in-index
387 ${subdir}ignored-and-untracked'
389 done
391 # Having established the above, from now on we mostly test against
392 # files which do not exist in the working tree or index.
394 test_expect_success 'sub-directory local ignore' '
395 expect "a/3-three" &&
396 test_check_ignore "a/3-three a/three-not-this-one"
399 test_expect_success 'sub-directory local ignore with --verbose' '
400 expect "a/.gitignore:2:*three a/3-three" &&
401 test_check_ignore "--verbose a/3-three a/three-not-this-one"
404 test_expect_success 'local ignore inside a sub-directory' '
405 expect "3-three" &&
407 cd a &&
408 test_check_ignore "3-three three-not-this-one"
411 test_expect_success 'local ignore inside a sub-directory with --verbose' '
412 expect "a/.gitignore:2:*three 3-three" &&
414 cd a &&
415 test_check_ignore "--verbose 3-three three-not-this-one"
419 test_expect_success_multi 'nested include' \
420 'a/b/.gitignore:8:!on* a/b/one' '
421 test_check_ignore "a/b/one"
424 ############################################################################
426 # test ignored sub-directories
428 test_expect_success_multi 'ignored sub-directory' \
429 'a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir' '
430 test_check_ignore "a/b/ignored-dir"
433 test_expect_success 'multiple files inside ignored sub-directory' '
434 expect_from_stdin <<-\EOF &&
435 a/b/ignored-dir/foo
436 a/b/ignored-dir/twoooo
437 a/b/ignored-dir/seven
439 test_check_ignore "a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven"
442 test_expect_success 'multiple files inside ignored sub-directory with -v' '
443 expect_from_stdin <<-\EOF &&
444 a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/foo
445 a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/twoooo
446 a/b/.gitignore:5:ignored-dir/ a/b/ignored-dir/seven
448 test_check_ignore "-v a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven"
451 test_expect_success 'cd to ignored sub-directory' '
452 expect_from_stdin <<-\EOF &&
454 twoooo
455 ../one
456 seven
457 ../../one
460 cd a/b/ignored-dir &&
461 test_check_ignore "foo twoooo ../one seven ../../one"
465 test_expect_success 'cd to ignored sub-directory with -v' '
466 expect_from_stdin <<-\EOF &&
467 a/b/.gitignore:5:ignored-dir/ foo
468 a/b/.gitignore:5:ignored-dir/ twoooo
469 a/b/.gitignore:8:!on* ../one
470 a/b/.gitignore:5:ignored-dir/ seven
471 .gitignore:1:one ../../one
474 cd a/b/ignored-dir &&
475 test_check_ignore "-v foo twoooo ../one seven ../../one"
479 ############################################################################
481 # test handling of symlinks
483 test_expect_success_multi SYMLINKS 'symlink' ':: a/symlink' '
484 test_check_ignore "a/symlink" 1
487 test_expect_success_multi SYMLINKS 'beyond a symlink' '' '
488 test_check_ignore "a/symlink/foo" 128 &&
489 test_stderr "fatal: pathspec '\''a/symlink/foo'\'' is beyond a symbolic link"
492 test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' '
494 cd a &&
495 test_check_ignore "symlink/foo" 128
496 ) &&
497 test_stderr "fatal: pathspec '\''symlink/foo'\'' is beyond a symbolic link"
500 ############################################################################
502 # test handling of submodules
504 test_expect_success_multi 'submodule' '' '
505 test_check_ignore "a/submodule/one" 128 &&
506 test_stderr "fatal: Pathspec '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
509 test_expect_success_multi 'submodule from subdirectory' '' '
511 cd a &&
512 test_check_ignore "submodule/one" 128
513 ) &&
514 test_stderr "fatal: Pathspec '\''submodule/one'\'' is in submodule '\''a/submodule'\''"
517 ############################################################################
519 # test handling of global ignore files
521 test_expect_success 'global ignore not yet enabled' '
522 expect_from_stdin <<-\EOF &&
523 .git/info/exclude:7:per-repo per-repo
524 a/.gitignore:2:*three a/globalthree
525 .git/info/exclude:7:per-repo a/per-repo
527 test_check_ignore "-v globalone per-repo a/globalthree a/per-repo not-ignored a/globaltwo"
530 test_expect_success 'global ignore' '
531 enable_global_excludes &&
532 expect_from_stdin <<-\EOF &&
533 globalone
534 per-repo
535 globalthree
536 a/globalthree
537 a/per-repo
538 globaltwo
540 test_check_ignore "globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo"
543 test_expect_success 'global ignore with -v' '
544 enable_global_excludes &&
545 expect_from_stdin <<-EOF &&
546 $global_excludes:1:globalone globalone
547 .git/info/exclude:7:per-repo per-repo
548 $global_excludes:3:globalthree globalthree
549 a/.gitignore:2:*three a/globalthree
550 .git/info/exclude:7:per-repo a/per-repo
551 $global_excludes:2:!globaltwo globaltwo
553 test_check_ignore "-v globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo"
556 ############################################################################
558 # test --stdin
560 cat <<-\EOF >stdin
562 not-ignored
563 a/one
564 a/not-ignored
565 a/b/on
566 a/b/one
567 a/b/one one
568 "a/b/one two"
569 "a/b/one\"three"
570 a/b/not-ignored
571 a/b/two
572 a/b/twooo
573 globaltwo
574 a/globaltwo
575 a/b/globaltwo
576 b/globaltwo
578 cat <<-\EOF >expected-default
580 a/one
581 a/b/on
582 a/b/one
583 a/b/one one
584 a/b/one two
585 "a/b/one\"three"
586 a/b/two
587 a/b/twooo
588 globaltwo
589 a/globaltwo
590 a/b/globaltwo
591 b/globaltwo
593 cat <<-EOF >expected-verbose
594 .gitignore:1:one one
595 .gitignore:1:one a/one
596 a/b/.gitignore:8:!on* a/b/on
597 a/b/.gitignore:8:!on* a/b/one
598 a/b/.gitignore:8:!on* a/b/one one
599 a/b/.gitignore:8:!on* a/b/one two
600 a/b/.gitignore:8:!on* "a/b/one\"three"
601 a/b/.gitignore:9:!two a/b/two
602 a/.gitignore:1:two* a/b/twooo
603 $global_excludes:2:!globaltwo globaltwo
604 $global_excludes:2:!globaltwo a/globaltwo
605 $global_excludes:2:!globaltwo a/b/globaltwo
606 $global_excludes:2:!globaltwo b/globaltwo
609 sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
610 tr "\n" "\0" >stdin0
611 sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \
612 tr "\n" "\0" >expected-default0
613 sed -e 's/ "/ /' -e 's/\\//' -e 's/"$//' expected-verbose | \
614 tr ":\t\n" "\0" >expected-verbose0
616 test_expect_success '--stdin' '
617 expect_from_stdin <expected-default &&
618 test_check_ignore "--stdin" <stdin
621 test_expect_success '--stdin -q' '
622 expect "" &&
623 test_check_ignore "-q --stdin" <stdin
626 test_expect_success '--stdin -v' '
627 expect_from_stdin <expected-verbose &&
628 test_check_ignore "-v --stdin" <stdin
631 for opts in '--stdin -z' '-z --stdin'
633 test_expect_success "$opts" "
634 expect_from_stdin <expected-default0 &&
635 test_check_ignore '$opts' <stdin0
638 test_expect_success "$opts -q" "
639 expect "" &&
640 test_check_ignore '-q $opts' <stdin0
643 test_expect_success "$opts -v" "
644 expect_from_stdin <expected-verbose0 &&
645 test_check_ignore '-v $opts' <stdin0
647 done
649 cat <<-\EOF >stdin
650 ../one
651 ../not-ignored
653 not-ignored
654 b/on
655 b/one
656 b/one one
657 "b/one two"
658 "b/one\"three"
659 b/two
660 b/not-ignored
661 b/twooo
662 ../globaltwo
663 globaltwo
664 b/globaltwo
665 ../b/globaltwo
666 c/not-ignored
668 # N.B. we deliberately end STDIN with a non-matching pattern in order
669 # to test that the exit code indicates that one or more of the
670 # provided paths is ignored - in other words, that it represents an
671 # aggregation of all the results, not just the final result.
673 cat <<-EOF >expected-all
674 .gitignore:1:one ../one
675 :: ../not-ignored
676 .gitignore:1:one one
677 :: not-ignored
678 a/b/.gitignore:8:!on* b/on
679 a/b/.gitignore:8:!on* b/one
680 a/b/.gitignore:8:!on* b/one one
681 a/b/.gitignore:8:!on* b/one two
682 a/b/.gitignore:8:!on* "b/one\"three"
683 a/b/.gitignore:9:!two b/two
684 :: b/not-ignored
685 a/.gitignore:1:two* b/twooo
686 $global_excludes:2:!globaltwo ../globaltwo
687 $global_excludes:2:!globaltwo globaltwo
688 $global_excludes:2:!globaltwo b/globaltwo
689 $global_excludes:2:!globaltwo ../b/globaltwo
690 :: c/not-ignored
692 grep -v '^:: ' expected-all >expected-verbose
693 sed -e 's/.* //' expected-verbose >expected-default
695 sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
696 tr "\n" "\0" >stdin0
697 sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \
698 tr "\n" "\0" >expected-default0
699 sed -e 's/ "/ /' -e 's/\\//' -e 's/"$//' expected-verbose | \
700 tr ":\t\n" "\0" >expected-verbose0
702 test_expect_success '--stdin from subdirectory' '
703 expect_from_stdin <expected-default &&
705 cd a &&
706 test_check_ignore "--stdin" <../stdin
710 test_expect_success '--stdin from subdirectory with -v' '
711 expect_from_stdin <expected-verbose &&
713 cd a &&
714 test_check_ignore "--stdin -v" <../stdin
718 test_expect_success '--stdin from subdirectory with -v -n' '
719 expect_from_stdin <expected-all &&
721 cd a &&
722 test_check_ignore "--stdin -v -n" <../stdin
726 for opts in '--stdin -z' '-z --stdin'
728 test_expect_success "$opts from subdirectory" '
729 expect_from_stdin <expected-default0 &&
731 cd a &&
732 test_check_ignore "'"$opts"'" <../stdin0
736 test_expect_success "$opts from subdirectory with -v" '
737 expect_from_stdin <expected-verbose0 &&
739 cd a &&
740 test_check_ignore "'"$opts"' -v" <../stdin0
743 done
745 test_expect_success PIPE 'streaming support for --stdin' '
746 mkfifo in out &&
747 (git check-ignore -n -v --stdin <in >out &) &&
749 # We cannot just "echo >in" because check-ignore would get EOF
750 # after echo exited; instead we open the descriptor in our
751 # shell, and then echo to the fd. We make sure to close it at
752 # the end, so that the subprocess does get EOF and dies
753 # properly.
755 # Similarly, we must keep "out" open so that check-ignore does
756 # not ever get SIGPIPE trying to write to us. Not only would that
757 # produce incorrect results, but then there would be no writer on the
758 # other end of the pipe, and we would potentially block forever trying
759 # to open it.
760 exec 9>in &&
761 exec 8<out &&
762 test_when_finished "exec 9>&-" &&
763 test_when_finished "exec 8<&-" &&
764 echo >&9 one &&
765 read response <&8 &&
766 echo "$response" | grep "^\.gitignore:1:one one" &&
767 echo >&9 two &&
768 read response <&8 &&
769 echo "$response" | grep "^:: two"
772 test_done