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 $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"
77}
78
79# Runs the same code with 4 different levels of output verbosity:
80#
81# 1. with -q / --quiet
82# 2. with default verbosity
83# 3. with -v / --verbose
84# 4. with -v / --verbose, *and* -n / --non-matching
85#
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.
89#
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.
92#
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
101test_expect_success_multiple () {
102 prereq=
103 if test $# -eq 5
104 then
105 prereq=$1
106 shift
107 fi
108 if test "$4" = "--index"
109 then
110 no_index_opt=
111 else
112 no_index_opt=$4
113 fi
114 testname="$1" expect_all="$2" code="$3"
115
116 expect_verbose=$( echo "$expect_all" | grep -v '^:: ' )
117 expect=$( echo "$expect_verbose" | sed -e 's/.* //' )
118
119 test_expect_success $prereq "$testname${no_index_opt:+ with $no_index_opt}" '
120 expect "$expect" &&
121 eval "$code"
122 '
123
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'
128 do
129 opts="${no_index_opt:+$no_index_opt }$quiet_opt"
130 test_expect_success $prereq "$testname${opts:+ with $opts}" "
131 expect '' &&
132 $code
133 "
134 done
135 quiet_opt=
136 fi
137
138 for verbose_opt in '-v' '--verbose'
139 do
140 for non_matching_opt in '' '-n' '--non-matching'
141 do
142 if test -n "$non_matching_opt"
143 then
144 my_expect="$expect_all"
145 else
146 my_expect="$expect_verbose"
147 fi
148
149 test_code="
150 expect '$my_expect' &&
151 $code
152 "
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=
160}
161
162test_expect_success_multi () {
163 test_expect_success_multiple "$@" "--index"
164}
165
166test_expect_success_no_index_multi () {
167 test_expect_success_multiple "$@" "--no-index"
168}
169
170test_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 &&
177 (
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 &&
186 one
187 ignored-*
188 top-level-dir/
189 EOF
190 for dir in . a
191 do
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
200 EOF
201 cat <<-\EOF >a/b/.gitignore &&
202 four
203 five
204 # this comment should affect the line numbers
205 six
206 ignored-dir/
207 # and so should this blank line:
208
209 !on*
210 !two
211 EOF
212 echo "seven" >a/b/ignored-dir/.gitignore &&
213 test -n "$HOME" &&
214 cat <<-\EOF >"$global_excludes" &&
215 globalone
216 !globaltwo
217 globalthree
218 EOF
219 cat <<-\EOF >>.git/info/exclude
220 per-repo
221 EOF
222'
223
224############################################################################
225#
226# test invalid inputs
227
228test_expect_success_multi '. corner-case' ':: .' '
229 test_check_ignore . 1
230'
231
232test_expect_success_multi 'empty command line' '' '
233 test_check_ignore "" 128 &&
234 stderr_contains "fatal: no path specified"
235'
236
237test_expect_success_multi '--stdin with empty STDIN' '' '
238 test_check_ignore "--stdin" 1 </dev/null &&
239 test_stderr ""
240'
241
242test_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"
246'
247
248test_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"
252'
253
254for verbose_opt in '-v' '--verbose'
255do
256 for quiet_opt in '-q' '--quiet'
257 do
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'
262 "
263 done
264done
265
266test_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"
270'
271
272test_expect_success_multi 'erroneous use of --' '' '
273 test_check_ignore "--" 128 &&
274 stderr_contains "fatal: no path specified"
275'
276
277test_expect_success_multi '--stdin with superfluous arg' '' '
278 test_check_ignore "--stdin foo" 128 &&
279 stderr_contains "fatal: cannot specify pathnames with --stdin"
280'
281
282test_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"
285'
286
287test_expect_success_multi '-z without --stdin' '' '
288 test_check_ignore "-z" 128 &&
289 stderr_contains "fatal: -z only makes sense with --stdin"
290'
291
292test_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"
295'
296
297test_expect_success_multi 'needs work tree' '' '
298 (
299 cd .git &&
300 test_check_ignore "foo" 128
301 ) &&
302 stderr_contains "fatal: This operation must be run in a work tree"
303'
304
305############################################################################
306#
307# test standard ignores
308
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.
312
313for subdir in '' 'a/'
314do
315 if test -z "$subdir"
316 then
317 where="at top-level"
318 else
319 where="in subdir $subdir"
320 fi
321
322 test_expect_success_multi "non-existent file $where not ignored" \
323 ":: ${subdir}non-existent" \
324 "test_check_ignore '${subdir}non-existent' 1"
325
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"
329
330 test_expect_success_multi "non-existent file $where ignored" \
331 ".gitignore:1:one ${subdir}one" \
332 "test_check_ignore '${subdir}one'"
333
334 test_expect_success_no_index_multi "non-existent file $where ignored" \
335 ".gitignore:1:one ${subdir}one" \
336 "test_check_ignore '${subdir}one'"
337
338 test_expect_success_multi "existing untracked file $where not ignored" \
339 ":: ${subdir}not-ignored" \
340 "test_check_ignore '${subdir}not-ignored' 1"
341
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"
345
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"
349
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'"
353
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'"
357
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'"
361
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'
374 "
375
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'
388 "
389done
390
391# Having established the above, from now on we mostly test against
392# files which do not exist in the working tree or index.
393
394test_expect_success 'sub-directory local ignore' '
395 expect "a/3-three" &&
396 test_check_ignore "a/3-three a/three-not-this-one"
397'
398
399test_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"
402'
403
404test_expect_success 'local ignore inside a sub-directory' '
405 expect "3-three" &&
406 (
407 cd a &&
408 test_check_ignore "3-three three-not-this-one"
409 )
410'
411test_expect_success 'local ignore inside a sub-directory with --verbose' '
412 expect "a/.gitignore:2:*three 3-three" &&
413 (
414 cd a &&
415 test_check_ignore "--verbose 3-three three-not-this-one"
416 )
417'
418
419test_expect_success_multi 'nested include' \
420 'a/b/.gitignore:8:!on* a/b/one' '
421 test_check_ignore "a/b/one"
422'
423
424############################################################################
425#
426# test ignored sub-directories
427
428test_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"
431'
432
433test_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
438 EOF
439 test_check_ignore "a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven"
440'
441
442test_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
447 EOF
448 test_check_ignore "-v a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven"
449'
450
451test_expect_success 'cd to ignored sub-directory' '
452 expect_from_stdin <<-\EOF &&
453 foo
454 twoooo
455 ../one
456 seven
457 ../../one
458 EOF
459 (
460 cd a/b/ignored-dir &&
461 test_check_ignore "foo twoooo ../one seven ../../one"
462 )
463'
464
465test_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
472 EOF
473 (
474 cd a/b/ignored-dir &&
475 test_check_ignore "-v foo twoooo ../one seven ../../one"
476 )
477'
478
479############################################################################
480#
481# test handling of symlinks
482
483test_expect_success_multi SYMLINKS 'symlink' ':: a/symlink' '
484 test_check_ignore "a/symlink" 1
485'
486
487test_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"
490'
491
492test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' '
493 (
494 cd a &&
495 test_check_ignore "symlink/foo" 128
496 ) &&
497 test_stderr "fatal: pathspec '\''symlink/foo'\'' is beyond a symbolic link"
498'
499
500############################################################################
501#
502# test handling of submodules
503
504test_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'\''"
507'
508
509test_expect_success_multi 'submodule from subdirectory' '' '
510 (
511 cd a &&
512 test_check_ignore "submodule/one" 128
513 ) &&
514 test_stderr "fatal: Pathspec '\''submodule/one'\'' is in submodule '\''a/submodule'\''"
515'
516
517############################################################################
518#
519# test handling of global ignore files
520
521test_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
526 EOF
527 test_check_ignore "-v globalone per-repo a/globalthree a/per-repo not-ignored a/globaltwo"
528'
529
530test_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
539 EOF
540 test_check_ignore "globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo"
541'
542
543test_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
552 EOF
553 test_check_ignore "-v globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo"
554'
555
556############################################################################
557#
558# test --stdin
559
560cat <<-\EOF >stdin
561 one
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
577EOF
578cat <<-\EOF >expected-default
579 one
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
592EOF
593cat <<-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
607EOF
608
609sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
610 tr "\n" "\0" >stdin0
611sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \
612 tr "\n" "\0" >expected-default0
613sed -e 's/ "/ /' -e 's/\\//' -e 's/"$//' expected-verbose | \
614 tr ":\t\n" "\0" >expected-verbose0
615
616test_expect_success '--stdin' '
617 expect_from_stdin <expected-default &&
618 test_check_ignore "--stdin" <stdin
619'
620
621test_expect_success '--stdin -q' '
622 expect "" &&
623 test_check_ignore "-q --stdin" <stdin
624'
625
626test_expect_success '--stdin -v' '
627 expect_from_stdin <expected-verbose &&
628 test_check_ignore "-v --stdin" <stdin
629'
630
631for opts in '--stdin -z' '-z --stdin'
632do
633 test_expect_success "$opts" "
634 expect_from_stdin <expected-default0 &&
635 test_check_ignore '$opts' <stdin0
636 "
637
638 test_expect_success "$opts -q" "
639 expect "" &&
640 test_check_ignore '-q $opts' <stdin0
641 "
642
643 test_expect_success "$opts -v" "
644 expect_from_stdin <expected-verbose0 &&
645 test_check_ignore '-v $opts' <stdin0
646 "
647done
648
649cat <<-\EOF >stdin
650 ../one
651 ../not-ignored
652 one
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
667EOF
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.
672
673cat <<-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
691EOF
692grep -v '^:: ' expected-all >expected-verbose
693sed -e 's/.* //' expected-verbose >expected-default
694
695sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
696 tr "\n" "\0" >stdin0
697sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \
698 tr "\n" "\0" >expected-default0
699sed -e 's/ "/ /' -e 's/\\//' -e 's/"$//' expected-verbose | \
700 tr ":\t\n" "\0" >expected-verbose0
701
702test_expect_success '--stdin from subdirectory' '
703 expect_from_stdin <expected-default &&
704 (
705 cd a &&
706 test_check_ignore "--stdin" <../stdin
707 )
708'
709
710test_expect_success '--stdin from subdirectory with -v' '
711 expect_from_stdin <expected-verbose &&
712 (
713 cd a &&
714 test_check_ignore "--stdin -v" <../stdin
715 )
716'
717
718test_expect_success '--stdin from subdirectory with -v -n' '
719 expect_from_stdin <expected-all &&
720 (
721 cd a &&
722 test_check_ignore "--stdin -v -n" <../stdin
723 )
724'
725
726for opts in '--stdin -z' '-z --stdin'
727do
728 test_expect_success "$opts from subdirectory" '
729 expect_from_stdin <expected-default0 &&
730 (
731 cd a &&
732 test_check_ignore "'"$opts"'" <../stdin0
733 )
734 '
735
736 test_expect_success "$opts from subdirectory with -v" '
737 expect_from_stdin <expected-verbose0 &&
738 (
739 cd a &&
740 test_check_ignore "'"$opts"' -v" <../stdin0
741 )
742 '
743done
744
745test_expect_success PIPE 'streaming support for --stdin' '
746 mkfifo in out &&
747 (git check-ignore -n -v --stdin <in >out &) &&
748
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.
754 #
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"
770'
771
772test_done