3 test_description=check-ignore
8 global_excludes="$(pwd)/global-excludes"
11 enable_global_excludes () {
13 git config core.excludesfile "$global_excludes"
17 dest="$HOME/expected-$1" text="$2"
20 >"$dest" # avoid newline
30 expect_from_stdin () {
31 cat >"$HOME/expected-stdout"
36 expect_in stderr "$1" &&
37 test_cmp "$HOME/expected-stderr" "$HOME/stderr"
42 if grep "$regexp" "$HOME/stderr"
46 echo "didn't find /$regexp/ in $HOME/stderr"
52 stderr_empty_on_success () {
54 if test $expect_code = 0
58 # If we expect failure then stderr might or might not be empty
59 # due to --quiet - the caller can check its contents
64 test_check_ignore () {
65 args="$1" expect_code="${2:-0}" global_args="$3"
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 \
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.
94 # - (optional) prereqs for this test, e.g. 'SYMLINKS'
96 # - output to expect from the fourth verbosity mode (the output
97 # from the other verbosity modes is automatically inferred
99 # - code to run (should invoke test_check_ignore)
100 # - index option: --index or --no-index
101 test_expect_success_multiple () {
108 if test "$4" = "--index"
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}" '
124 # --quiet is only valid when a single pattern is passed
125 if test $( echo "$expect_all" | wc -l ) = 1
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}" "
138 for verbose_opt in '-v' '--verbose'
140 for non_matching_opt in '' '-n' '--non-matching'
142 if test -n "$non_matching_opt"
144 my_expect="$expect_all"
146 my_expect="$expect_verbose"
150 expect '$my_expect' &&
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"
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' '
172 mkdir -p a/b/ignored-dir a/submodule b &&
173 if test_have_prereq SYMLINKS
182 git commit -m"commit in submodule"
184 git add a/submodule &&
185 cat <<-\EOF >.gitignore &&
192 : >$dir/not-ignored &&
193 : >$dir/ignored-and-untracked &&
194 : >$dir/ignored-but-in-index
196 git add -f ignored-but-in-index a/ignored-but-in-index &&
197 cat <<-\EOF >a/.gitignore &&
201 cat <<-\EOF >a/b/.gitignore &&
204 # this comment should affect the line numbers
207 # and so should this blank line:
212 echo "seven" >a/b/ignored-dir/.gitignore &&
214 cat <<-\EOF >"$global_excludes" &&
219 cat <<-\EOF >>.git/info/exclude
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 &&
242 test_expect_success '-q with multiple args' '
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' '
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" "
260 test_check_ignore '$quiet_opt $verbose_opt foo' 128 &&
261 stderr_contains 'fatal: cannot have both --quiet and --verbose'
266 test_expect_success '--quiet with multiple args' '
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' '' '
300 test_check_ignore "foo" 128
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/'
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" \
369 ${subdir}non-existent
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" \
383 ${subdir}non-existent
386 ${subdir}ignored-but-in-index
387 ${subdir}ignored-and-untracked'
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' '
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" &&
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 &&
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 &&
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' '' '
495 test_check_ignore "symlink/foo" 128
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' '' '
512 test_check_ignore "submodule/one" 128
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 &&
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 ############################################################################
578 cat <<-\EOF >expected-default
593 cat <<-EOF >expected-verbose
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 | \
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' '
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" "
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
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
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
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
692 grep -v '^:: ' expected-all >expected-verbose
693 sed -e 's/.* //' expected-verbose >expected-default
695 sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
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 &&
706 test_check_ignore "--stdin" <../stdin
710 test_expect_success '--stdin from subdirectory with -v' '
711 expect_from_stdin <expected-verbose &&
714 test_check_ignore "--stdin -v" <../stdin
718 test_expect_success '--stdin from subdirectory with -v -n' '
719 expect_from_stdin <expected-all &&
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 &&
732 test_check_ignore "'"$opts"'" <../stdin0
736 test_expect_success "$opts from subdirectory with -v" '
737 expect_from_stdin <expected-verbose0 &&
740 test_check_ignore "'"$opts"' -v" <../stdin0
745 test_expect_success PIPE 'streaming support for --stdin' '
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
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
762 test_when_finished "exec 9>&-" &&
763 test_when_finished "exec 8<&-" &&
766 echo "$response" | grep "^\.gitignore:1:one one" &&
769 echo "$response" | grep "^:: two"