Raw
1 #!/bin/sh
2 #
3 # Copyright (c) 2006 Junio C Hamano
4 #
5
6 test_description='git grep various.
7 '
8
9 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
10 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
11
12 . ./test-lib.sh
13
14 test_invalid_grep_expression() {
15 params="$@" &&
16 test_expect_success "invalid expression: grep $params" '
17 test_must_fail git grep $params -- nonexisting
18 '
19 }
20
21 test_lazy_prereq MB_REGEX '
22 LC_ALL=en_US.UTF-8 test-tool regex "^.$" "¿"
23 '
24
25 cat >hello.c <<EOF
26 #include <assert.h>
27 #include <stdio.h>
28
29 int main(int argc, const char **argv)
30 {
31 printf("Hello world.\n");
32 return 0;
33 /* char ?? */
34 }
35
36 EOF
37
38 test_expect_success setup '
39 cat >file <<-\EOF &&
40 foo mmap bar
41 foo_mmap bar
42 foo_mmap bar mmap
43 foo mmap bar_mmap
44 foo_mmap bar mmap baz
45 EOF
46 cat >hello_world <<-\EOF &&
47 Hello world
48 HeLLo world
49 Hello_world
50 HeLLo_world
51 EOF
52 cat >ab <<-\EOF &&
53 a+b*c
54 a+bc
55 abc
56 EOF
57 cat >d0 <<-\EOF &&
58 d
59 0
60 EOF
61 echo vvv >v &&
62 echo ww w >w &&
63 echo x x xx x >x &&
64 echo y yy >y &&
65 echo zzz > z &&
66 mkdir t &&
67 echo test >t/t &&
68 echo vvv >t/v &&
69 mkdir t/a &&
70 echo vvv >t/a/v &&
71 qz_to_tab_space >space <<-\EOF &&
72 line without leading space1
73 Zline with leading space1
74 Zline with leading space2
75 Zline with leading space3
76 line without leading space2
77 EOF
78 cat >hello.ps1 <<-\EOF &&
79 # No-op.
80 function dummy() {}
81
82 # Say hello.
83 function hello() {
84 echo "Hello world."
85 echo "Hello again."
86 } # hello
87
88 # Still a no-op.
89 function dummy() {}
90 EOF
91 printf "\200\nASCII\n" >invalid-utf8 &&
92 if test_have_prereq FUNNYNAMES
93 then
94 echo unusual >"\"unusual\" pathname" &&
95 echo unusual >"t/nested \"unusual\" pathname"
96 fi &&
97 if test_have_prereq MB_REGEX
98 then
99 echo "¿" >reverse-question-mark
100 fi &&
101 git add . &&
102 test_tick &&
103 git commit -m initial
104 '
105
106 test_expect_success 'grep should not segfault with a bad input' '
107 test_must_fail git grep "("
108 '
109
110 test_invalid_grep_expression --and -e A
111
112 test_pattern_type () {
113 H=$1 &&
114 HC=$2 &&
115 L=$3 &&
116 type=$4 &&
117 shift 4 &&
118
119 expected_str= &&
120 case "$type" in
121 BRE)
122 expected_str="${HC}ab:a+bc"
123 ;;
124 ERE)
125 expected_str="${HC}ab:abc"
126 ;;
127 FIX)
128 expected_str="${HC}ab:a+b*c"
129 ;;
130 *)
131 BUG "unknown pattern type '$type'"
132 ;;
133 esac &&
134 config_str="$@" &&
135
136 test_expect_success "grep $L with '$config_str' interpreted as $type" '
137 echo $expected_str >expected &&
138 git $config_str grep "a+b*c" $H ab >actual &&
139 test_cmp expected actual
140 '
141 }
142
143 for H in HEAD ''
144 do
145 case "$H" in
146 HEAD) HC='HEAD:' L='HEAD' ;;
147 '') HC= L='in working tree' ;;
148 esac
149
150 test_expect_success "grep -w $L" '
151 cat >expected <<-EOF &&
152 ${HC}file:1:foo mmap bar
153 ${HC}file:3:foo_mmap bar mmap
154 ${HC}file:4:foo mmap bar_mmap
155 ${HC}file:5:foo_mmap bar mmap baz
156 EOF
157 git -c grep.linenumber=false grep -n -w -e mmap $H >actual &&
158 test_cmp expected actual
159 '
160
161 test_expect_success "grep -w $L (with --column)" '
162 cat >expected <<-EOF &&
163 ${HC}file:5:foo mmap bar
164 ${HC}file:14:foo_mmap bar mmap
165 ${HC}file:5:foo mmap bar_mmap
166 ${HC}file:14:foo_mmap bar mmap baz
167 EOF
168 git grep --column -w -e mmap $H >actual &&
169 test_cmp expected actual
170 '
171
172 test_expect_success "grep -w $L (with --column, extended OR)" '
173 cat >expected <<-EOF &&
174 ${HC}file:14:foo_mmap bar mmap
175 ${HC}file:19:foo_mmap bar mmap baz
176 EOF
177 git grep --column -w -e mmap$ --or -e baz $H >actual &&
178 test_cmp expected actual
179 '
180
181 test_expect_success "grep -w $L (with --column, --invert-match)" '
182 cat >expected <<-EOF &&
183 ${HC}file:1:foo mmap bar
184 ${HC}file:1:foo_mmap bar
185 ${HC}file:1:foo_mmap bar mmap
186 ${HC}file:1:foo mmap bar_mmap
187 EOF
188 git grep --column --invert-match -w -e baz $H -- file >actual &&
189 test_cmp expected actual
190 '
191
192 test_expect_success "grep $L (with --column, --invert-match, extended OR)" '
193 cat >expected <<-EOF &&
194 ${HC}hello_world:6:HeLLo_world
195 EOF
196 git grep --column --invert-match -e ll --or --not -e _ $H -- hello_world \
197 >actual &&
198 test_cmp expected actual
199 '
200
201 test_expect_success "grep $L (with --column, --invert-match, extended AND)" '
202 cat >expected <<-EOF &&
203 ${HC}hello_world:3:Hello world
204 ${HC}hello_world:3:Hello_world
205 ${HC}hello_world:6:HeLLo_world
206 EOF
207 git grep --column --invert-match --not -e _ --and --not -e ll $H -- hello_world \
208 >actual &&
209 test_cmp expected actual
210 '
211
212 test_expect_success "grep $L (with --column, double-negation)" '
213 cat >expected <<-EOF &&
214 ${HC}file:1:foo_mmap bar mmap baz
215 EOF
216 git grep --column --not \( --not -e foo --or --not -e baz \) $H -- file \
217 >actual &&
218 test_cmp expected actual
219 '
220
221 test_expect_success "grep -w $L (with --column, -C)" '
222 cat >expected <<-EOF &&
223 ${HC}file:5:foo mmap bar
224 ${HC}file-foo_mmap bar
225 ${HC}file:14:foo_mmap bar mmap
226 ${HC}file:5:foo mmap bar_mmap
227 ${HC}file:14:foo_mmap bar mmap baz
228 EOF
229 git grep --column -w -C1 -e mmap $H >actual &&
230 test_cmp expected actual
231 '
232
233 test_expect_success "grep -w $L (with --line-number, --column)" '
234 cat >expected <<-EOF &&
235 ${HC}file:1:5:foo mmap bar
236 ${HC}file:3:14:foo_mmap bar mmap
237 ${HC}file:4:5:foo mmap bar_mmap
238 ${HC}file:5:14:foo_mmap bar mmap baz
239 EOF
240 git grep -n --column -w -e mmap $H >actual &&
241 test_cmp expected actual
242 '
243
244 test_expect_success "grep -w $L (with non-extended patterns, --column)" '
245 cat >expected <<-EOF &&
246 ${HC}file:5:foo mmap bar
247 ${HC}file:10:foo_mmap bar
248 ${HC}file:10:foo_mmap bar mmap
249 ${HC}file:5:foo mmap bar_mmap
250 ${HC}file:10:foo_mmap bar mmap baz
251 EOF
252 git grep --column -w -e bar -e mmap $H >actual &&
253 test_cmp expected actual
254 '
255
256 test_expect_success "grep -w $L" '
257 cat >expected <<-EOF &&
258 ${HC}file:1:foo mmap bar
259 ${HC}file:3:foo_mmap bar mmap
260 ${HC}file:4:foo mmap bar_mmap
261 ${HC}file:5:foo_mmap bar mmap baz
262 EOF
263 git -c grep.linenumber=true grep -w -e mmap $H >actual &&
264 test_cmp expected actual
265 '
266
267 test_expect_success "grep -w $L" '
268 cat >expected <<-EOF &&
269 ${HC}file:foo mmap bar
270 ${HC}file:foo_mmap bar mmap
271 ${HC}file:foo mmap bar_mmap
272 ${HC}file:foo_mmap bar mmap baz
273 EOF
274 git -c grep.linenumber=true grep --no-line-number -w -e mmap $H >actual &&
275 test_cmp expected actual
276 '
277
278 test_expect_success "grep -w $L (w)" '
279 test_must_fail git grep -n -w -e "^w" $H >actual &&
280 test_must_be_empty actual
281 '
282
283 test_expect_success "grep -w $L (x)" '
284 cat >expected <<-EOF &&
285 ${HC}x:1:x x xx x
286 EOF
287 git grep -n -w -e "x xx* x" $H >actual &&
288 test_cmp expected actual
289 '
290
291 test_expect_success "grep -w $L (y-1)" '
292 cat >expected <<-EOF &&
293 ${HC}y:1:y yy
294 EOF
295 git grep -n -w -e "^y" $H >actual &&
296 test_cmp expected actual
297 '
298
299 test_expect_success "grep -w $L (y-2)" '
300 if git grep -n -w -e "^y y" $H >actual
301 then
302 echo should not have matched
303 cat actual
304 false
305 else
306 test_must_be_empty actual
307 fi
308 '
309
310 test_expect_success "grep -w $L (z)" '
311 if git grep -n -w -e "^z" $H >actual
312 then
313 echo should not have matched
314 cat actual
315 false
316 else
317 test_must_be_empty actual
318 fi
319 '
320
321 test_expect_success "grep $L (with --column, --only-matching)" '
322 cat >expected <<-EOF &&
323 ${HC}file:1:5:mmap
324 ${HC}file:2:5:mmap
325 ${HC}file:3:5:mmap
326 ${HC}file:3:14:mmap
327 ${HC}file:4:5:mmap
328 ${HC}file:4:14:mmap
329 ${HC}file:5:5:mmap
330 ${HC}file:5:14:mmap
331 EOF
332 git grep --column -n -o -e mmap $H >actual &&
333 test_cmp expected actual
334 '
335
336 test_expect_success "grep $L (t-1)" '
337 echo "${HC}t/t:1:test" >expected &&
338 git grep -n -e test $H >actual &&
339 test_cmp expected actual
340 '
341
342 test_expect_success "grep $L (t-2)" '
343 echo "${HC}t:1:test" >expected &&
344 (
345 cd t &&
346 git grep -n -e test $H
347 ) >actual &&
348 test_cmp expected actual
349 '
350
351 test_expect_success "grep $L (t-3)" '
352 echo "${HC}t/t:1:test" >expected &&
353 (
354 cd t &&
355 git grep --full-name -n -e test $H
356 ) >actual &&
357 test_cmp expected actual
358 '
359
360 test_expect_success "grep -c $L (no /dev/null)" '
361 ! git grep -c test $H | grep /dev/null
362 '
363
364 test_expect_success "grep --max-depth -1 $L" '
365 cat >expected <<-EOF &&
366 ${HC}t/a/v:1:vvv
367 ${HC}t/v:1:vvv
368 ${HC}v:1:vvv
369 EOF
370 git grep --max-depth -1 -n -e vvv $H >actual &&
371 test_cmp expected actual &&
372 git grep --recursive -n -e vvv $H >actual &&
373 test_cmp expected actual
374 '
375
376 test_expect_success "grep --max-depth 0 $L" '
377 cat >expected <<-EOF &&
378 ${HC}v:1:vvv
379 EOF
380 git grep --max-depth 0 -n -e vvv $H >actual &&
381 test_cmp expected actual &&
382 git grep --no-recursive -n -e vvv $H >actual &&
383 test_cmp expected actual
384 '
385
386 test_expect_success "grep --max-depth 0 -- '*' $L" '
387 cat >expected <<-EOF &&
388 ${HC}t/a/v:1:vvv
389 ${HC}t/v:1:vvv
390 ${HC}v:1:vvv
391 EOF
392 git grep --max-depth 0 -n -e vvv $H -- "*" >actual &&
393 test_cmp expected actual &&
394 git grep --no-recursive -n -e vvv $H -- "*" >actual &&
395 test_cmp expected actual
396 '
397
398 test_expect_success "grep --max-depth 1 $L" '
399 cat >expected <<-EOF &&
400 ${HC}t/v:1:vvv
401 ${HC}v:1:vvv
402 EOF
403 git grep --max-depth 1 -n -e vvv $H >actual &&
404 test_cmp expected actual
405 '
406
407 test_expect_success "grep --max-depth 0 -- t $L" '
408 cat >expected <<-EOF &&
409 ${HC}t/v:1:vvv
410 EOF
411 git grep --max-depth 0 -n -e vvv $H -- t >actual &&
412 test_cmp expected actual &&
413 git grep --no-recursive -n -e vvv $H -- t >actual &&
414 test_cmp expected actual
415 '
416
417 test_expect_success "grep --max-depth 0 -- . t $L" '
418 cat >expected <<-EOF &&
419 ${HC}t/v:1:vvv
420 ${HC}v:1:vvv
421 EOF
422 git grep --max-depth 0 -n -e vvv $H -- . t >actual &&
423 test_cmp expected actual &&
424 git grep --no-recursive -n -e vvv $H -- . t >actual &&
425 test_cmp expected actual
426 '
427
428 test_expect_success "grep --max-depth 0 -- t . $L" '
429 cat >expected <<-EOF &&
430 ${HC}t/v:1:vvv
431 ${HC}v:1:vvv
432 EOF
433 git grep --max-depth 0 -n -e vvv $H -- t . >actual &&
434 test_cmp expected actual &&
435 git grep --no-recursive -n -e vvv $H -- t . >actual &&
436 test_cmp expected actual
437 '
438
439
440 test_pattern_type "$H" "$HC" "$L" BRE -c grep.extendedRegexp=false
441 test_pattern_type "$H" "$HC" "$L" ERE -c grep.extendedRegexp=true
442 test_pattern_type "$H" "$HC" "$L" BRE -c grep.patternType=basic
443 test_pattern_type "$H" "$HC" "$L" ERE -c grep.patternType=extended
444 test_pattern_type "$H" "$HC" "$L" FIX -c grep.patternType=fixed
445
446 test_expect_success PCRE "grep $L with grep.patterntype=perl" '
447 echo "${HC}ab:a+b*c" >expected &&
448 git -c grep.patterntype=perl grep "a\x{2b}b\x{2a}c" $H ab >actual &&
449 test_cmp expected actual
450 '
451
452 test_expect_success !FAIL_PREREQS,!PCRE "grep $L with grep.patterntype=perl errors without PCRE" '
453 test_must_fail git -c grep.patterntype=perl grep "foo.*bar"
454 '
455
456 test_pattern_type "$H" "$HC" "$L" ERE \
457 -c grep.patternType=default \
458 -c grep.extendedRegexp=true
459 test_pattern_type "$H" "$HC" "$L" ERE \
460 -c grep.extendedRegexp=true \
461 -c grep.patternType=default
462 test_pattern_type "$H" "$HC" "$L" ERE \
463 -c grep.patternType=extended \
464 -c grep.extendedRegexp=false
465 test_pattern_type "$H" "$HC" "$L" BRE \
466 -c grep.patternType=basic \
467 -c grep.extendedRegexp=true
468 test_pattern_type "$H" "$HC" "$L" ERE \
469 -c grep.extendedRegexp=false \
470 -c grep.patternType=extended
471 test_pattern_type "$H" "$HC" "$L" BRE \
472 -c grep.extendedRegexp=true \
473 -c grep.patternType=basic
474
475 # grep.extendedRegexp is last-one-wins
476 test_pattern_type "$H" "$HC" "$L" BRE \
477 -c grep.extendedRegexp=true \
478 -c grep.extendedRegexp=false
479
480 # grep.patternType=basic pays no attention to grep.extendedRegexp
481 test_pattern_type "$H" "$HC" "$L" BRE \
482 -c grep.extendedRegexp=true \
483 -c grep.patternType=basic \
484 -c grep.extendedRegexp=false
485
486 # grep.patternType=extended pays no attention to grep.extendedRegexp
487 test_pattern_type "$H" "$HC" "$L" ERE \
488 -c grep.extendedRegexp=true \
489 -c grep.patternType=extended \
490 -c grep.extendedRegexp=false
491
492 # grep.extendedRegexp is used with a last-one-wins grep.patternType=default
493 test_pattern_type "$H" "$HC" "$L" ERE \
494 -c grep.patternType=fixed \
495 -c grep.extendedRegexp=true \
496 -c grep.patternType=default
497
498 # grep.extendedRegexp is used with earlier grep.patternType=default
499 test_pattern_type "$H" "$HC" "$L" ERE \
500 -c grep.extendedRegexp=false \
501 -c grep.patternType=default \
502 -c grep.extendedRegexp=true
503
504 # grep.extendedRegexp is used with a last-one-loses grep.patternType=default
505 test_pattern_type "$H" "$HC" "$L" ERE \
506 -c grep.extendedRegexp=false \
507 -c grep.extendedRegexp=true \
508 -c grep.patternType=default
509
510 # grep.extendedRegexp and grep.patternType are both last-one-wins independently
511 test_pattern_type "$H" "$HC" "$L" BRE \
512 -c grep.patternType=default \
513 -c grep.extendedRegexp=true \
514 -c grep.patternType=basic
515
516 # grep.patternType=extended and grep.patternType=default
517 test_pattern_type "$H" "$HC" "$L" BRE \
518 -c grep.patternType=extended \
519 -c grep.patternType=default
520
521 # grep.patternType=[extended -> default -> fixed] (BRE)" '
522 test_pattern_type "$H" "$HC" "$L" FIX \
523 -c grep.patternType=extended \
524 -c grep.patternType=default \
525 -c grep.patternType=fixed
526
527 test_expect_success "grep --count $L" '
528 echo ${HC}ab:3 >expected &&
529 git grep --count -e b $H -- ab >actual &&
530 test_cmp expected actual
531 '
532
533 test_expect_success "grep --count -h $L" '
534 echo 3 >expected &&
535 git grep --count -h -e b $H -- ab >actual &&
536 test_cmp expected actual
537 '
538
539 test_expect_success "grep $L searches past invalid lines on UTF-8 locale" '
540 LC_ALL=en_US.UTF-8 git grep A. invalid-utf8 >actual &&
541 cat >expected <<-EOF &&
542 invalid-utf8:ASCII
543 EOF
544 test_cmp expected actual
545 '
546
547 test_expect_success FUNNYNAMES "grep $L should quote unusual pathnames" '
548 cat >expected <<-EOF &&
549 ${HC}"\"unusual\" pathname":unusual
550 ${HC}"t/nested \"unusual\" pathname":unusual
551 EOF
552 git grep unusual $H >actual &&
553 test_cmp expected actual
554 '
555
556 test_expect_success FUNNYNAMES "grep $L in subdir should quote unusual relative pathnames" '
557 cat >expected <<-EOF &&
558 ${HC}"nested \"unusual\" pathname":unusual
559 EOF
560 (
561 cd t &&
562 git grep unusual $H
563 ) >actual &&
564 test_cmp expected actual
565 '
566
567 test_expect_success FUNNYNAMES "grep -z $L with unusual pathnames" '
568 cat >expected <<-EOF &&
569 ${HC}"unusual" pathname:unusual
570 ${HC}t/nested "unusual" pathname:unusual
571 EOF
572 git grep -z unusual $H >actual &&
573 tr "\0" ":" <actual >actual-replace-null &&
574 test_cmp expected actual-replace-null
575 '
576
577 test_expect_success FUNNYNAMES "grep -z $L in subdir with unusual relative pathnames" '
578 cat >expected <<-EOF &&
579 ${HC}nested "unusual" pathname:unusual
580 EOF
581 (
582 cd t &&
583 git grep -z unusual $H
584 ) >actual &&
585 tr "\0" ":" <actual >actual-replace-null &&
586 test_cmp expected actual-replace-null
587 '
588 done
589
590 test_expect_success MB_REGEX 'grep exactly one char in single-char multibyte file' '
591 LC_ALL=en_US.UTF-8 git grep "^.$" reverse-question-mark
592 '
593
594 test_expect_success MB_REGEX 'grep two chars in single-char multibyte file' '
595 LC_ALL=en_US.UTF-8 test_expect_code 1 git grep ".." reverse-question-mark
596 '
597
598 cat >expected <<EOF
599 file
600 EOF
601 test_expect_success 'grep -l -C' '
602 git grep -l -C1 foo >actual &&
603 test_cmp expected actual
604 '
605
606 cat >expected <<EOF
607 file:5
608 EOF
609 test_expect_success 'grep -c -C' '
610 git grep -c -C1 foo >actual &&
611 test_cmp expected actual
612 '
613
614 test_expect_success 'grep -L -C' '
615 git ls-files >expected &&
616 git grep -L -C1 nonexistent_string >actual &&
617 test_cmp expected actual
618 '
619
620 test_expect_success 'grep --files-without-match --quiet' '
621 git grep --files-without-match --quiet nonexistent_string >actual &&
622 test_must_be_empty actual
623 '
624
625 test_expect_success 'grep --max-count 0 (must exit with non-zero)' '
626 test_must_fail git grep --max-count 0 foo >actual &&
627 test_must_be_empty actual
628 '
629
630 test_expect_success 'grep --max-count 3' '
631 cat >expected <<-EOF &&
632 file:foo mmap bar
633 file:foo_mmap bar
634 file:foo_mmap bar mmap
635 EOF
636 git grep --max-count 3 foo >actual &&
637 test_cmp expected actual
638 '
639
640 test_expect_success 'grep --max-count -1 (no limit)' '
641 cat >expected <<-EOF &&
642 file:foo mmap bar
643 file:foo_mmap bar
644 file:foo_mmap bar mmap
645 file:foo mmap bar_mmap
646 file:foo_mmap bar mmap baz
647 EOF
648 git grep --max-count -1 foo >actual &&
649 test_cmp expected actual
650 '
651
652 test_expect_success 'grep --max-count 1 --context 2' '
653 cat >expected <<-EOF &&
654 file-foo mmap bar
655 file:foo_mmap bar
656 file-foo_mmap bar mmap
657 EOF
658 git grep --max-count 1 --context 1 foo_mmap >actual &&
659 test_cmp expected actual
660 '
661
662 test_expect_success 'grep --max-count 1 --show-function' '
663 cat >expected <<-EOF &&
664 hello.ps1=function hello() {
665 hello.ps1: echo "Hello world."
666 EOF
667 git grep --max-count 1 --show-function Hello hello.ps1 >actual &&
668 test_cmp expected actual
669 '
670
671 test_expect_success 'grep --max-count 2 --show-function' '
672 cat >expected <<-EOF &&
673 hello.ps1=function hello() {
674 hello.ps1: echo "Hello world."
675 hello.ps1: echo "Hello again."
676 EOF
677 git grep --max-count 2 --show-function Hello hello.ps1 >actual &&
678 test_cmp expected actual
679 '
680
681 test_expect_success 'grep --max-count 1 --count' '
682 cat >expected <<-EOF &&
683 hello.ps1:1
684 EOF
685 git grep --max-count 1 --count Hello hello.ps1 >actual &&
686 test_cmp expected actual
687 '
688
689 test_expect_success 'grep --max-count 1 (multiple files)' '
690 cat >expected <<-EOF &&
691 hello.c:#include <stdio.h>
692 hello.ps1:# No-op.
693 EOF
694 git grep --max-count 1 -e o -- hello.\* >actual &&
695 test_cmp expected actual
696 '
697
698 test_expect_success 'grep --max-count 1 --context 1 (multiple files)' '
699 cat >expected <<-EOF &&
700 hello.c-#include <assert.h>
701 hello.c:#include <stdio.h>
702 hello.c-
703 --
704 hello.ps1:# No-op.
705 hello.ps1-function dummy() {}
706 EOF
707 git grep --max-count 1 --context 1 -e o -- hello.\* >actual &&
708 test_cmp expected actual
709 '
710
711 cat >expected <<EOF
712 file:foo mmap bar_mmap
713 EOF
714
715 test_expect_success 'grep -e A --and -e B' '
716 git grep -e "foo mmap" --and -e bar_mmap >actual &&
717 test_cmp expected actual
718 '
719
720 cat >expected <<EOF
721 file:foo_mmap bar mmap
722 file:foo_mmap bar mmap baz
723 EOF
724
725
726 test_expect_success 'grep ( -e A --or -e B ) --and -e B' '
727 git grep \( -e foo_ --or -e baz \) \
728 --and -e " mmap" >actual &&
729 test_cmp expected actual
730 '
731
732 cat >expected <<EOF
733 file:foo mmap bar
734 EOF
735
736 test_expect_success 'grep -e A --and --not -e B' '
737 git grep -e "foo mmap" --and --not -e bar_mmap >actual &&
738 test_cmp expected actual
739 '
740
741 test_expect_success 'grep should ignore GREP_OPTIONS' '
742 GREP_OPTIONS=-v git grep " mmap bar\$" >actual &&
743 test_cmp expected actual
744 '
745
746 test_expect_success 'grep -f, non-existent file' '
747 test_must_fail git grep -f patterns
748 '
749
750 cat >expected <<EOF
751 file:foo mmap bar
752 file:foo_mmap bar
753 file:foo_mmap bar mmap
754 file:foo mmap bar_mmap
755 file:foo_mmap bar mmap baz
756 EOF
757
758 cat >pattern <<EOF
759 mmap
760 EOF
761
762 test_expect_success 'grep -f, one pattern' '
763 git grep -f pattern >actual &&
764 test_cmp expected actual
765 '
766
767 cat >expected <<EOF
768 file:foo mmap bar
769 file:foo_mmap bar
770 file:foo_mmap bar mmap
771 file:foo mmap bar_mmap
772 file:foo_mmap bar mmap baz
773 t/a/v:vvv
774 t/v:vvv
775 v:vvv
776 EOF
777
778 cat >patterns <<EOF
779 mmap
780 vvv
781 EOF
782
783 test_expect_success 'grep -f, multiple patterns' '
784 git grep -f patterns >actual &&
785 test_cmp expected actual
786 '
787
788 test_expect_success 'grep, multiple patterns' '
789 git grep "$(cat patterns)" >actual &&
790 test_cmp expected actual
791 '
792
793 cat >expected <<EOF
794 file:foo mmap bar
795 file:foo_mmap bar
796 file:foo_mmap bar mmap
797 file:foo mmap bar_mmap
798 file:foo_mmap bar mmap baz
799 t/a/v:vvv
800 t/v:vvv
801 v:vvv
802 EOF
803
804 cat >patterns <<EOF
805
806 mmap
807
808 vvv
809
810 EOF
811
812 test_expect_success 'grep -f, ignore empty lines' '
813 git grep -f patterns >actual &&
814 test_cmp expected actual
815 '
816
817 test_expect_success 'grep -f, ignore empty lines, read patterns from stdin' '
818 git grep -f - <patterns >actual &&
819 test_cmp expected actual
820 '
821
822 test_expect_success 'grep -f, use cwd relative file' '
823 test_when_finished "git rm -f sub/dir/file" &&
824 mkdir -p sub/dir &&
825 echo hit >sub/dir/file &&
826 git add sub/dir/file &&
827 echo hit >sub/dir/pattern &&
828 echo miss >pattern &&
829 (
830 cd sub/dir && git grep -f pattern file
831 ) &&
832 git -C sub/dir grep -f pattern file
833 '
834
835 cat >expected <<EOF
836 y:y yy
837 --
838 z:zzz
839 EOF
840
841 test_expect_success 'grep -q, silently report matches' '
842 git grep -q mmap >actual &&
843 test_must_be_empty actual &&
844 test_must_fail git grep -q qfwfq >actual &&
845 test_must_be_empty actual
846 '
847
848 test_expect_success 'grep -C1 hunk mark between files' '
849 git grep -C1 "^[yz]" >actual &&
850 test_cmp expected actual
851 '
852
853 test_expect_success 'log grep setup' '
854 test_commit --append --author "With * Asterisk <xyzzy@frotz.com>" second file a &&
855 test_commit --append third file a &&
856 test_commit --append --author "Night Fall <nitfol@frobozz.com>" fourth file a
857 '
858
859 test_expect_success 'log grep (1)' '
860 git log --author=author --pretty=tformat:%s >actual &&
861 {
862 echo third && echo initial
863 } >expect &&
864 test_cmp expect actual
865 '
866
867 test_expect_success 'log grep (2)' '
868 git log --author=" * " -F --pretty=tformat:%s >actual &&
869 {
870 echo second
871 } >expect &&
872 test_cmp expect actual
873 '
874
875 test_expect_success 'log grep (3)' '
876 git log --author="^A U" --pretty=tformat:%s >actual &&
877 {
878 echo third && echo initial
879 } >expect &&
880 test_cmp expect actual
881 '
882
883 test_expect_success 'log grep (4)' '
884 git log --author="frotz\.com>$" --pretty=tformat:%s >actual &&
885 {
886 echo second
887 } >expect &&
888 test_cmp expect actual
889 '
890
891 test_expect_success 'log grep (5)' '
892 git log --author=Thor -F --pretty=tformat:%s >actual &&
893 {
894 echo third && echo initial
895 } >expect &&
896 test_cmp expect actual
897 '
898
899 test_expect_success 'log grep (6)' '
900 git log --author=-0700 --pretty=tformat:%s >actual &&
901 test_must_be_empty actual
902 '
903
904 test_expect_success 'log grep (7)' '
905 git log -g --grep-reflog="commit: third" --pretty=tformat:%s >actual &&
906 echo third >expect &&
907 test_cmp expect actual
908 '
909
910 test_expect_success 'log grep (8)' '
911 git log -g --grep-reflog="commit: third" --grep-reflog="commit: second" --pretty=tformat:%s >actual &&
912 {
913 echo third && echo second
914 } >expect &&
915 test_cmp expect actual
916 '
917
918 test_expect_success 'log grep (9)' '
919 git log -g --grep-reflog="commit: third" --author="Thor" --pretty=tformat:%s >actual &&
920 echo third >expect &&
921 test_cmp expect actual
922 '
923
924 test_expect_success 'log grep (9)' '
925 git log -g --grep-reflog="commit: third" --author="non-existent" --pretty=tformat:%s >actual &&
926 test_must_be_empty actual
927 '
928
929 test_expect_success 'log --grep-reflog can only be used under -g' '
930 test_must_fail git log --grep-reflog="commit: third"
931 '
932
933 test_expect_success 'log with multiple --grep uses union' '
934 git log --grep=i --grep=r --format=%s >actual &&
935 {
936 echo fourth && echo third && echo initial
937 } >expect &&
938 test_cmp expect actual
939 '
940
941 test_expect_success 'log --all-match with multiple --grep uses intersection' '
942 git log --all-match --grep=i --grep=r --format=%s >actual &&
943 {
944 echo third
945 } >expect &&
946 test_cmp expect actual
947 '
948
949 test_expect_success 'log with multiple --author uses union' '
950 git log --author="Thor" --author="Aster" --format=%s >actual &&
951 {
952 echo third && echo second && echo initial
953 } >expect &&
954 test_cmp expect actual
955 '
956
957 test_expect_success 'log --all-match with multiple --author still uses union' '
958 git log --all-match --author="Thor" --author="Aster" --format=%s >actual &&
959 {
960 echo third && echo second && echo initial
961 } >expect &&
962 test_cmp expect actual
963 '
964
965 test_expect_success 'log --grep --author uses intersection' '
966 # grep matches only third and fourth
967 # author matches only initial and third
968 git log --author="A U Thor" --grep=r --format=%s >actual &&
969 {
970 echo third
971 } >expect &&
972 test_cmp expect actual
973 '
974
975 test_expect_success 'log --grep --grep --author takes union of greps and intersects with author' '
976 # grep matches initial and second but not third
977 # author matches only initial and third
978 git log --author="A U Thor" --grep=s --grep=l --format=%s >actual &&
979 {
980 echo initial
981 } >expect &&
982 test_cmp expect actual
983 '
984
985 test_expect_success 'log ---all-match -grep --author --author still takes union of authors and intersects with grep' '
986 # grep matches only initial and third
987 # author matches all but second
988 git log --all-match --author="Thor" --author="Night" --grep=i --format=%s >actual &&
989 {
990 echo third && echo initial
991 } >expect &&
992 test_cmp expect actual
993 '
994
995 test_expect_success 'log --grep --author --author takes union of authors and intersects with grep' '
996 # grep matches only initial and third
997 # author matches all but second
998 git log --author="Thor" --author="Night" --grep=i --format=%s >actual &&
999 {
1000 echo third && echo initial
1001 } >expect &&
1002 test_cmp expect actual
1003 '
1004
1005 test_expect_success 'log --all-match --grep --grep --author takes intersection' '
1006 # grep matches only third
1007 # author matches only initial and third
1008 git log --all-match --author="A U Thor" --grep=i --grep=r --format=%s >actual &&
1009 {
1010 echo third
1011 } >expect &&
1012 test_cmp expect actual
1013 '
1014
1015 test_expect_success 'log --author does not search in timestamp' '
1016 git log --author="$GIT_AUTHOR_DATE" >actual &&
1017 test_must_be_empty actual
1018 '
1019
1020 test_expect_success 'log --committer does not search in timestamp' '
1021 git log --committer="$GIT_COMMITTER_DATE" >actual &&
1022 test_must_be_empty actual
1023 '
1024
1025 test_expect_success 'grep with CE_VALID file' '
1026 git update-index --assume-unchanged t/t &&
1027 rm t/t &&
1028 echo "t/t:test" >expect &&
1029 git grep test >actual &&
1030 test_cmp expect actual &&
1031 git update-index --no-assume-unchanged t/t &&
1032 git checkout t/t
1033 '
1034
1035 cat >expected <<EOF
1036 hello.c=#include <stdio.h>
1037 hello.c: return 0;
1038 EOF
1039
1040 test_expect_success 'grep -p with userdiff' '
1041 git config diff.custom.funcname "^#" &&
1042 echo "hello.c diff=custom" >.gitattributes &&
1043 git grep -p return >actual &&
1044 test_cmp expected actual
1045 '
1046
1047 cat >expected <<EOF
1048 hello.c=int main(int argc, const char **argv)
1049 hello.c: return 0;
1050 EOF
1051
1052 test_expect_success 'grep -p' '
1053 rm -f .gitattributes &&
1054 git grep -p return >actual &&
1055 test_cmp expected actual
1056 '
1057
1058 cat >expected <<EOF
1059 hello.c-#include <stdio.h>
1060 hello.c-
1061 hello.c=int main(int argc, const char **argv)
1062 hello.c-{
1063 hello.c- printf("Hello world.\n");
1064 hello.c: return 0;
1065 EOF
1066
1067 test_expect_success 'grep -p -B5' '
1068 git grep -p -B5 return >actual &&
1069 test_cmp expected actual
1070 '
1071
1072 cat >expected <<EOF
1073 hello.c=int main(int argc, const char **argv)
1074 hello.c-{
1075 hello.c- printf("Hello world.\n");
1076 hello.c: return 0;
1077 hello.c- /* char ?? */
1078 hello.c-}
1079 EOF
1080
1081 test_expect_success 'grep -W' '
1082 git grep -W return >actual &&
1083 test_cmp expected actual
1084 '
1085
1086 cat >expected <<EOF
1087 hello.c-#include <assert.h>
1088 hello.c:#include <stdio.h>
1089 EOF
1090
1091 test_expect_success 'grep -W shows no trailing empty lines' '
1092 git grep -W stdio >actual &&
1093 test_cmp expected actual
1094 '
1095
1096 test_expect_success 'grep -W with userdiff' '
1097 test_when_finished "rm -f .gitattributes" &&
1098 git config diff.custom.xfuncname "^function .*$" &&
1099 echo "hello.ps1 diff=custom" >.gitattributes &&
1100 git grep -W echo >function-context-userdiff-actual
1101 '
1102
1103 test_expect_success ' includes preceding comment' '
1104 test_grep "# Say hello" function-context-userdiff-actual
1105 '
1106
1107 test_expect_success ' includes function line' '
1108 test_grep "=function hello" function-context-userdiff-actual
1109 '
1110
1111 test_expect_success ' includes matching line' '
1112 test_grep ": echo" function-context-userdiff-actual
1113 '
1114
1115 test_expect_success ' includes last line of the function' '
1116 test_grep "} # hello" function-context-userdiff-actual
1117 '
1118
1119 for threads in $(test_seq 0 10)
1120 do
1121 test_expect_success "grep --threads=$threads & -c grep.threads=$threads" "
1122 git grep --threads=$threads . >actual.$threads &&
1123 if test $threads -ge 1
1124 then
1125 test_cmp actual.\$(($threads - 1)) actual.$threads
1126 fi &&
1127 git -c grep.threads=$threads grep . >actual.$threads &&
1128 if test $threads -ge 1
1129 then
1130 test_cmp actual.\$(($threads - 1)) actual.$threads
1131 fi
1132 "
1133 done
1134
1135 test_expect_success !PTHREADS,!FAIL_PREREQS \
1136 'grep --threads=N or pack.threads=N warns when no pthreads' '
1137 git grep --threads=2 Hello hello_world 2>err &&
1138 grep ^warning: err >warnings &&
1139 test_line_count = 1 warnings &&
1140 test_grep -F "no threads support, ignoring --threads" err &&
1141 git -c grep.threads=2 grep Hello hello_world 2>err &&
1142 grep ^warning: err >warnings &&
1143 test_line_count = 1 warnings &&
1144 test_grep -F "no threads support, ignoring grep.threads" err &&
1145 git -c grep.threads=2 grep --threads=4 Hello hello_world 2>err &&
1146 grep ^warning: err >warnings &&
1147 test_line_count = 2 warnings &&
1148 test_grep -F "no threads support, ignoring --threads" err &&
1149 test_grep -F "no threads support, ignoring grep.threads" err &&
1150 git -c grep.threads=0 grep --threads=0 Hello hello_world 2>err &&
1151 test_line_count = 0 err
1152 '
1153
1154 test_expect_success 'grep from a subdirectory to search wider area (1)' '
1155 mkdir -p s &&
1156 (
1157 cd s && git grep "x x x" ..
1158 )
1159 '
1160
1161 test_expect_success 'grep from a subdirectory to search wider area (2)' '
1162 mkdir -p s &&
1163 (
1164 cd s &&
1165 test_expect_code 1 git grep xxyyzz .. >out &&
1166 test_must_be_empty out
1167 )
1168 '
1169
1170 cat >expected <<EOF
1171 hello.c:int main(int argc, const char **argv)
1172 EOF
1173
1174 test_expect_success 'grep -Fi' '
1175 git grep -Fi "CHAR *" >actual &&
1176 test_cmp expected actual
1177 '
1178
1179 test_expect_success 'outside of git repository' '
1180 rm -fr non &&
1181 mkdir -p non/git/sub &&
1182 echo hello >non/git/file1 &&
1183 echo world >non/git/sub/file2 &&
1184 {
1185 echo file1:hello &&
1186 echo sub/file2:world
1187 } >non/expect.full &&
1188 echo file2:world >non/expect.sub &&
1189 (
1190 GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
1191 export GIT_CEILING_DIRECTORIES &&
1192 cd non/git &&
1193 test_must_fail git grep o &&
1194 git grep --no-index o >../actual.full &&
1195 test_cmp ../expect.full ../actual.full &&
1196 cd sub &&
1197 test_must_fail git grep o &&
1198 git grep --no-index o >../../actual.sub &&
1199 test_cmp ../../expect.sub ../../actual.sub
1200 ) &&
1201
1202 echo ".*o*" >non/git/.gitignore &&
1203 (
1204 GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
1205 export GIT_CEILING_DIRECTORIES &&
1206 cd non/git &&
1207 test_must_fail git grep o &&
1208 git grep --no-index --exclude-standard o >../actual.full &&
1209 test_cmp ../expect.full ../actual.full &&
1210
1211 {
1212 echo ".gitignore:.*o*" &&
1213 cat ../expect.full
1214 } >../expect.with.ignored &&
1215 git grep --no-index --no-exclude-standard o >../actual.full &&
1216 test_cmp ../expect.with.ignored ../actual.full
1217 )
1218 '
1219
1220 test_expect_success 'outside of git repository with fallbackToNoIndex' '
1221 rm -fr non &&
1222 mkdir -p non/git/sub &&
1223 echo hello >non/git/file1 &&
1224 echo world >non/git/sub/file2 &&
1225 cat <<-\EOF >non/expect.full &&
1226 file1:hello
1227 sub/file2:world
1228 EOF
1229 echo file2:world >non/expect.sub &&
1230 (
1231 GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
1232 export GIT_CEILING_DIRECTORIES &&
1233 cd non/git &&
1234 test_must_fail git -c grep.fallbackToNoIndex=false grep o &&
1235 git -c grep.fallbackToNoIndex=true grep o >../actual.full &&
1236 test_cmp ../expect.full ../actual.full &&
1237 cd sub &&
1238 test_must_fail git -c grep.fallbackToNoIndex=false grep o &&
1239 git -c grep.fallbackToNoIndex=true grep o >../../actual.sub &&
1240 test_cmp ../../expect.sub ../../actual.sub
1241 ) &&
1242
1243 echo ".*o*" >non/git/.gitignore &&
1244 (
1245 GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
1246 export GIT_CEILING_DIRECTORIES &&
1247 cd non/git &&
1248 test_must_fail git -c grep.fallbackToNoIndex=false grep o &&
1249 git -c grep.fallbackToNoIndex=true grep --exclude-standard o >../actual.full &&
1250 test_cmp ../expect.full ../actual.full &&
1251
1252 {
1253 echo ".gitignore:.*o*" &&
1254 cat ../expect.full
1255 } >../expect.with.ignored &&
1256 git -c grep.fallbackToNoIndex grep --no-exclude-standard o >../actual.full &&
1257 test_cmp ../expect.with.ignored ../actual.full
1258 )
1259 '
1260
1261 test_expect_success 'no repository with path outside $cwd' '
1262 test_when_finished rm -fr non &&
1263 rm -fr non &&
1264 mkdir -p non/git/sub non/tig &&
1265 (
1266 GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
1267 export GIT_CEILING_DIRECTORIES &&
1268 cd non/git &&
1269 test_expect_code 128 git grep --no-index search .. 2>error &&
1270 test_grep "is outside the directory tree" error
1271 ) &&
1272 (
1273 GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
1274 export GIT_CEILING_DIRECTORIES &&
1275 cd non/git &&
1276 test_expect_code 128 git grep --no-index search ../tig 2>error &&
1277 test_grep "is outside the directory tree" error
1278 ) &&
1279 (
1280 GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
1281 export GIT_CEILING_DIRECTORIES &&
1282 cd non/git &&
1283 test_expect_code 128 git grep --no-index search ../non 2>error &&
1284 test_grep "no such path in the working tree" error
1285 )
1286 '
1287
1288 test_expect_success 'inside git repository but with --no-index' '
1289 rm -fr is &&
1290 mkdir -p is/git/sub &&
1291 echo hello >is/git/file1 &&
1292 echo world >is/git/sub/file2 &&
1293 echo ".*o*" >is/git/.gitignore &&
1294 {
1295 echo file1:hello &&
1296 echo sub/file2:world
1297 } >is/expect.unignored &&
1298 {
1299 echo ".gitignore:.*o*" &&
1300 cat is/expect.unignored
1301 } >is/expect.full &&
1302 echo file2:world >is/expect.sub &&
1303 (
1304 cd is/git &&
1305 git init &&
1306 test_must_fail git grep o >../actual.full &&
1307 test_must_be_empty ../actual.full &&
1308
1309 git grep --untracked o >../actual.unignored &&
1310 test_cmp ../expect.unignored ../actual.unignored &&
1311
1312 git grep --no-index o >../actual.full &&
1313 test_cmp ../expect.full ../actual.full &&
1314
1315 git grep --no-index --exclude-standard o >../actual.unignored &&
1316 test_cmp ../expect.unignored ../actual.unignored &&
1317
1318 cd sub &&
1319 test_must_fail git grep o >../../actual.sub &&
1320 test_must_be_empty ../../actual.sub &&
1321
1322 git grep --no-index o >../../actual.sub &&
1323 test_cmp ../../expect.sub ../../actual.sub &&
1324
1325 git grep --untracked o >../../actual.sub &&
1326 test_cmp ../../expect.sub ../../actual.sub
1327 )
1328 '
1329
1330 test_expect_success 'grep --no-index descends into repos, but not .git' '
1331 rm -fr non &&
1332 mkdir -p non/git &&
1333 (
1334 GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
1335 export GIT_CEILING_DIRECTORIES &&
1336 cd non/git &&
1337
1338 echo magic >file &&
1339 git init repo &&
1340 (
1341 cd repo &&
1342 echo magic >file &&
1343 git add file &&
1344 git commit -m foo &&
1345 echo magic >.git/file
1346 ) &&
1347
1348 cat >expect <<-\EOF &&
1349 file
1350 repo/file
1351 EOF
1352 git grep -l --no-index magic >actual &&
1353 test_cmp expect actual
1354 )
1355 '
1356
1357 test_expect_success 'setup double-dash tests' '
1358 cat >double-dash <<EOF &&
1359 --
1360 ->
1361 other
1362 EOF
1363 git add double-dash
1364 '
1365
1366 cat >expected <<EOF
1367 double-dash:->
1368 EOF
1369 test_expect_success 'grep -- pattern' '
1370 git grep -- "->" >actual &&
1371 test_cmp expected actual
1372 '
1373 test_expect_success 'grep -- pattern -- pathspec' '
1374 git grep -- "->" -- double-dash >actual &&
1375 test_cmp expected actual
1376 '
1377 test_expect_success 'grep -e pattern -- path' '
1378 git grep -e "->" -- double-dash >actual &&
1379 test_cmp expected actual
1380 '
1381
1382 cat >expected <<EOF
1383 double-dash:--
1384 EOF
1385 test_expect_success 'grep -e -- -- path' '
1386 git grep -e -- -- double-dash >actual &&
1387 test_cmp expected actual
1388 '
1389
1390 test_expect_success 'dashdash disambiguates rev as rev' '
1391 test_when_finished "rm -f main" &&
1392 echo content >main &&
1393 echo main:hello.c >expect &&
1394 git grep -l o main -- hello.c >actual &&
1395 test_cmp expect actual
1396 '
1397
1398 test_expect_success 'dashdash disambiguates pathspec as pathspec' '
1399 test_when_finished "git rm -f main" &&
1400 echo content >main &&
1401 git add main &&
1402 echo main:content >expect &&
1403 git grep o -- main >actual &&
1404 test_cmp expect actual
1405 '
1406
1407 test_expect_success 'report bogus arg without dashdash' '
1408 test_must_fail git grep o does-not-exist
1409 '
1410
1411 test_expect_success 'report bogus rev with dashdash' '
1412 test_must_fail git grep o hello.c --
1413 '
1414
1415 test_expect_success 'allow non-existent path with dashdash' '
1416 # We need a real match so grep exits with success.
1417 tree=$(git ls-tree HEAD |
1418 sed s/hello.c/not-in-working-tree/ |
1419 git mktree) &&
1420 git grep o "$tree" -- not-in-working-tree
1421 '
1422
1423 test_expect_success 'grep --no-index pattern -- path' '
1424 rm -fr non &&
1425 mkdir -p non/git &&
1426 (
1427 GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
1428 export GIT_CEILING_DIRECTORIES &&
1429 cd non/git &&
1430 echo hello >hello &&
1431 echo goodbye >goodbye &&
1432 echo hello:hello >expect &&
1433 git grep --no-index o -- hello >actual &&
1434 test_cmp expect actual
1435 )
1436 '
1437
1438 test_expect_success 'grep --no-index complains of revs' '
1439 test_must_fail git grep --no-index o main -- 2>err &&
1440 test_grep "cannot be used with revs" err
1441 '
1442
1443 test_expect_success 'grep --no-index prefers paths to revs' '
1444 test_when_finished "rm -f main" &&
1445 echo content >main &&
1446 echo main:content >expect &&
1447 git grep --no-index o main >actual &&
1448 test_cmp expect actual
1449 '
1450
1451 test_expect_success 'grep --no-index does not "diagnose" revs' '
1452 test_must_fail git grep --no-index o :1:hello.c 2>err &&
1453 test_grep ! -i "did you mean" err
1454 '
1455
1456 cat >expected <<EOF
1457 hello.c:int main(int argc, const char **argv)
1458 hello.c: printf("Hello world.\n");
1459 EOF
1460
1461 test_expect_success PCRE 'grep --perl-regexp pattern' '
1462 git grep --perl-regexp "\p{Ps}.*?\p{Pe}" hello.c >actual &&
1463 test_cmp expected actual
1464 '
1465
1466 test_expect_success !FAIL_PREREQS,!PCRE 'grep --perl-regexp pattern errors without PCRE' '
1467 test_must_fail git grep --perl-regexp "foo.*bar"
1468 '
1469
1470 test_expect_success PCRE 'grep -P pattern' '
1471 git grep -P "\p{Ps}.*?\p{Pe}" hello.c >actual &&
1472 test_cmp expected actual
1473 '
1474
1475 test_expect_success LIBPCRE2 "grep -P with (*NO_JIT) doesn't error out" '
1476 git grep -P "(*NO_JIT)\p{Ps}.*?\p{Pe}" hello.c >actual &&
1477 test_cmp expected actual
1478
1479 '
1480
1481 test_expect_success !FAIL_PREREQS,!PCRE 'grep -P pattern errors without PCRE' '
1482 test_must_fail git grep -P "foo.*bar"
1483 '
1484
1485 test_expect_success 'grep pattern with grep.extendedRegexp=true' '
1486 test_must_fail git -c grep.extendedregexp=true \
1487 grep "\p{Ps}.*?\p{Pe}" hello.c >actual &&
1488 test_must_be_empty actual
1489 '
1490
1491 test_expect_success PCRE 'grep -P pattern with grep.extendedRegexp=true' '
1492 git -c grep.extendedregexp=true \
1493 grep -P "\p{Ps}.*?\p{Pe}" hello.c >actual &&
1494 test_cmp expected actual
1495 '
1496
1497 test_expect_success PCRE 'grep -P -v pattern' '
1498 cat >expected <<-\EOF &&
1499 ab:a+b*c
1500 ab:a+bc
1501 EOF
1502 git grep -P -v "abc" ab >actual &&
1503 test_cmp expected actual
1504 '
1505
1506 test_expect_success PCRE 'grep -P -i pattern' '
1507 cat >expected <<-EOF &&
1508 hello.c: printf("Hello world.\n");
1509 EOF
1510 git grep -P -i "PRINTF\([^\d]+\)" hello.c >actual &&
1511 test_cmp expected actual
1512 '
1513
1514 test_expect_success PCRE 'grep -P -w pattern' '
1515 cat >expected <<-\EOF &&
1516 hello_world:Hello world
1517 hello_world:HeLLo world
1518 EOF
1519 git grep -P -w "He((?i)ll)o" hello_world >actual &&
1520 test_cmp expected actual
1521 '
1522
1523 test_expect_success PCRE 'grep -P backreferences work (the PCRE NO_AUTO_CAPTURE flag is not set)' '
1524 git grep -P -h "(?P<one>.)(?P=one)" hello_world >actual &&
1525 test_cmp hello_world actual &&
1526 git grep -P -h "(.)\1" hello_world >actual &&
1527 test_cmp hello_world actual
1528 '
1529
1530 test_expect_success 'grep -G invalidpattern properly dies ' '
1531 test_must_fail git grep -G "a["
1532 '
1533
1534 test_expect_success 'grep invalidpattern properly dies with grep.patternType=basic' '
1535 test_must_fail git -c grep.patterntype=basic grep "a["
1536 '
1537
1538 test_expect_success 'grep -E invalidpattern properly dies ' '
1539 test_must_fail git grep -E "a["
1540 '
1541
1542 test_expect_success 'grep invalidpattern properly dies with grep.patternType=extended' '
1543 test_must_fail git -c grep.patterntype=extended grep "a["
1544 '
1545
1546 test_expect_success PCRE 'grep -P invalidpattern properly dies ' '
1547 test_must_fail git grep -P "a["
1548 '
1549
1550 test_expect_success PCRE 'grep invalidpattern properly dies with grep.patternType=perl' '
1551 test_must_fail git -c grep.patterntype=perl grep "a["
1552 '
1553
1554 test_expect_success 'grep -G -E -F pattern' '
1555 echo "ab:a+b*c" >expected &&
1556 git grep -G -E -F "a+b*c" ab >actual &&
1557 test_cmp expected actual
1558 '
1559
1560 test_expect_success 'grep pattern with grep.patternType=basic, =extended, =fixed' '
1561 echo "ab:a+b*c" >expected &&
1562 git \
1563 -c grep.patterntype=basic \
1564 -c grep.patterntype=extended \
1565 -c grep.patterntype=fixed \
1566 grep "a+b*c" ab >actual &&
1567 test_cmp expected actual
1568 '
1569
1570 test_expect_success 'grep -E -F -G pattern' '
1571 echo "ab:a+bc" >expected &&
1572 git grep -E -F -G "a+b*c" ab >actual &&
1573 test_cmp expected actual
1574 '
1575
1576 test_expect_success 'grep pattern with grep.patternType=extended, =fixed, =basic' '
1577 echo "ab:a+bc" >expected &&
1578 git \
1579 -c grep.patterntype=extended \
1580 -c grep.patterntype=fixed \
1581 -c grep.patterntype=basic \
1582 grep "a+b*c" ab >actual &&
1583 test_cmp expected actual
1584 '
1585
1586 test_expect_success 'grep -F -G -E pattern' '
1587 echo "ab:abc" >expected &&
1588 git grep -F -G -E "a+b*c" ab >actual &&
1589 test_cmp expected actual
1590 '
1591
1592 test_expect_success 'grep pattern with grep.patternType=fixed, =basic, =extended' '
1593 echo "ab:abc" >expected &&
1594 git \
1595 -c grep.patterntype=fixed \
1596 -c grep.patterntype=basic \
1597 -c grep.patterntype=extended \
1598 grep "a+b*c" ab >actual &&
1599 test_cmp expected actual
1600 '
1601
1602 test_expect_success 'grep -G -F -P -E pattern' '
1603 echo "d0:d" >expected &&
1604 git grep -G -F -P -E "[\d]" d0 >actual &&
1605 test_cmp expected actual
1606 '
1607
1608 test_expect_success 'grep pattern with grep.patternType=fixed, =basic, =perl, =extended' '
1609 echo "d0:d" >expected &&
1610 git \
1611 -c grep.patterntype=fixed \
1612 -c grep.patterntype=basic \
1613 -c grep.patterntype=perl \
1614 -c grep.patterntype=extended \
1615 grep "[\d]" d0 >actual &&
1616 test_cmp expected actual
1617 '
1618
1619 test_expect_success PCRE 'grep -G -F -E -P pattern' '
1620 echo "d0:0" >expected &&
1621 git grep -G -F -E -P "[\d]" d0 >actual &&
1622 test_cmp expected actual
1623 '
1624
1625 test_expect_success PCRE 'grep pattern with grep.patternType=fixed, =basic, =extended, =perl' '
1626 echo "d0:0" >expected &&
1627 git \
1628 -c grep.patterntype=fixed \
1629 -c grep.patterntype=basic \
1630 -c grep.patterntype=extended \
1631 -c grep.patterntype=perl \
1632 grep "[\d]" d0 >actual &&
1633 test_cmp expected actual
1634 '
1635
1636 test_expect_success PCRE 'grep -P pattern with grep.patternType=fixed' '
1637 echo "ab:a+b*c" >expected &&
1638 git \
1639 -c grep.patterntype=fixed \
1640 grep -P "a\x{2b}b\x{2a}c" ab >actual &&
1641 test_cmp expected actual
1642 '
1643
1644 test_expect_success 'grep -F pattern with grep.patternType=basic' '
1645 echo "ab:a+b*c" >expected &&
1646 git \
1647 -c grep.patterntype=basic \
1648 grep -F "*c" ab >actual &&
1649 test_cmp expected actual
1650 '
1651
1652 test_expect_success 'grep -G pattern with grep.patternType=fixed' '
1653 cat >expected <<-\EOF &&
1654 ab:a+b*c
1655 ab:a+bc
1656 EOF
1657 git \
1658 -c grep.patterntype=fixed \
1659 grep -G "a+b" ab >actual &&
1660 test_cmp expected actual
1661 '
1662
1663 test_expect_success 'grep -E pattern with grep.patternType=fixed' '
1664 cat >expected <<-\EOF &&
1665 ab:a+b*c
1666 ab:a+bc
1667 ab:abc
1668 EOF
1669 git \
1670 -c grep.patterntype=fixed \
1671 grep -E "a+" ab >actual &&
1672 test_cmp expected actual
1673 '
1674
1675 cat >expected <<EOF
1676 hello.c<RED>:<RESET>int main(int argc, const char **argv)
1677 hello.c<RED>-<RESET>{
1678 <RED>--<RESET>
1679 hello.c<RED>:<RESET> /* char ?? */
1680 hello.c<RED>-<RESET>}
1681 <RED>--<RESET>
1682 hello_world<RED>:<RESET>Hello_world
1683 hello_world<RED>-<RESET>HeLLo_world
1684 EOF
1685
1686 test_expect_success 'grep --color, separator' '
1687 test_config color.grep.context normal &&
1688 test_config color.grep.filename normal &&
1689 test_config color.grep.function normal &&
1690 test_config color.grep.linenumber normal &&
1691 test_config color.grep.match normal &&
1692 test_config color.grep.selected normal &&
1693 test_config color.grep.separator red &&
1694
1695 git grep --color=always -A1 -e char -e lo_w hello.c hello_world |
1696 test_decode_color >actual &&
1697 test_cmp expected actual
1698 '
1699
1700 cat >expected <<EOF
1701 hello.c:int main(int argc, const char **argv)
1702 hello.c: /* char ?? */
1703
1704 hello_world:Hello_world
1705 EOF
1706
1707 test_expect_success 'grep --break' '
1708 git grep --break -e char -e lo_w hello.c hello_world >actual &&
1709 test_cmp expected actual
1710 '
1711
1712 cat >expected <<EOF
1713 hello.c:int main(int argc, const char **argv)
1714 hello.c-{
1715 --
1716 hello.c: /* char ?? */
1717 hello.c-}
1718
1719 hello_world:Hello_world
1720 hello_world-HeLLo_world
1721 EOF
1722
1723 test_expect_success 'grep --break with context' '
1724 git grep --break -A1 -e char -e lo_w hello.c hello_world >actual &&
1725 test_cmp expected actual
1726 '
1727
1728 cat >expected <<EOF
1729 hello.c
1730 int main(int argc, const char **argv)
1731 /* char ?? */
1732 hello_world
1733 Hello_world
1734 EOF
1735
1736 test_expect_success 'grep --heading' '
1737 git grep --heading -e char -e lo_w hello.c hello_world >actual &&
1738 test_cmp expected actual
1739 '
1740
1741 cat >expected <<EOF
1742 <BOLD;GREEN>hello.c<RESET>
1743 4:int main(int argc, const <BLACK;BYELLOW>char<RESET> **argv)
1744 8: /* <BLACK;BYELLOW>char<RESET> ?? */
1745
1746 <BOLD;GREEN>hello_world<RESET>
1747 3:Hel<BLACK;BYELLOW>lo_w<RESET>orld
1748 EOF
1749
1750 test_expect_success 'mimic ack-grep --group' '
1751 test_config color.grep.context normal &&
1752 test_config color.grep.filename "bold green" &&
1753 test_config color.grep.function normal &&
1754 test_config color.grep.linenumber normal &&
1755 test_config color.grep.match "black yellow" &&
1756 test_config color.grep.selected normal &&
1757 test_config color.grep.separator normal &&
1758
1759 git grep --break --heading -n --color \
1760 -e char -e lo_w hello.c hello_world |
1761 test_decode_color >actual &&
1762 test_cmp expected actual
1763 '
1764
1765 cat >expected <<EOF
1766 space: line with leading space1
1767 space: line with leading space2
1768 space: line with leading space3
1769 EOF
1770
1771 test_expect_success PCRE 'grep -E "^ "' '
1772 git grep -E "^ " space >actual &&
1773 test_cmp expected actual
1774 '
1775
1776 test_expect_success PCRE 'grep -P "^ "' '
1777 git grep -P "^ " space >actual &&
1778 test_cmp expected actual
1779 '
1780
1781 cat >expected <<EOF
1782 space-line without leading space1
1783 space: line <RED>with <RESET>leading space1
1784 space: line <RED>with <RESET>leading <RED>space2<RESET>
1785 space: line <RED>with <RESET>leading space3
1786 space:line without leading <RED>space2<RESET>
1787 EOF
1788
1789 test_expect_success 'grep --color -e A -e B with context' '
1790 test_config color.grep.context normal &&
1791 test_config color.grep.filename normal &&
1792 test_config color.grep.function normal &&
1793 test_config color.grep.linenumber normal &&
1794 test_config color.grep.matchContext normal &&
1795 test_config color.grep.matchSelected red &&
1796 test_config color.grep.selected normal &&
1797 test_config color.grep.separator normal &&
1798
1799 git grep --color=always -C2 -e "with " -e space2 space |
1800 test_decode_color >actual &&
1801 test_cmp expected actual
1802 '
1803
1804 cat >expected <<EOF
1805 space-line without leading space1
1806 space- line with leading space1
1807 space: line <RED>with <RESET>leading <RED>space2<RESET>
1808 space- line with leading space3
1809 space-line without leading space2
1810 EOF
1811
1812 test_expect_success 'grep --color -e A --and -e B with context' '
1813 test_config color.grep.context normal &&
1814 test_config color.grep.filename normal &&
1815 test_config color.grep.function normal &&
1816 test_config color.grep.linenumber normal &&
1817 test_config color.grep.matchContext normal &&
1818 test_config color.grep.matchSelected red &&
1819 test_config color.grep.selected normal &&
1820 test_config color.grep.separator normal &&
1821
1822 git grep --color=always -C2 -e "with " --and -e space2 space |
1823 test_decode_color >actual &&
1824 test_cmp expected actual
1825 '
1826
1827 cat >expected <<EOF
1828 space-line without leading space1
1829 space: line <RED>with <RESET>leading space1
1830 space- line with leading space2
1831 space: line <RED>with <RESET>leading space3
1832 space-line without leading space2
1833 EOF
1834
1835 test_expect_success 'grep --color -e A --and --not -e B with context' '
1836 test_config color.grep.context normal &&
1837 test_config color.grep.filename normal &&
1838 test_config color.grep.function normal &&
1839 test_config color.grep.linenumber normal &&
1840 test_config color.grep.matchContext normal &&
1841 test_config color.grep.matchSelected red &&
1842 test_config color.grep.selected normal &&
1843 test_config color.grep.separator normal &&
1844
1845 git grep --color=always -C2 -e "with " --and --not -e space2 space |
1846 test_decode_color >actual &&
1847 test_cmp expected actual
1848 '
1849
1850 cat >expected <<EOF
1851 hello.c-
1852 hello.c=int main(int argc, const char **argv)
1853 hello.c-{
1854 hello.c: pr<RED>int<RESET>f("<RED>Hello<RESET> world.\n");
1855 hello.c- return 0;
1856 hello.c- /* char ?? */
1857 hello.c-}
1858 EOF
1859
1860 test_expect_success 'grep --color -e A --and -e B -p with context' '
1861 test_config color.grep.context normal &&
1862 test_config color.grep.filename normal &&
1863 test_config color.grep.function normal &&
1864 test_config color.grep.linenumber normal &&
1865 test_config color.grep.matchContext normal &&
1866 test_config color.grep.matchSelected red &&
1867 test_config color.grep.selected normal &&
1868 test_config color.grep.separator normal &&
1869
1870 git grep --color=always -p -C3 -e int --and -e Hello --no-index hello.c |
1871 test_decode_color >actual &&
1872 test_cmp expected actual
1873 '
1874
1875 test_expect_success 'grep can find things only in the work tree' '
1876 : >work-tree-only &&
1877 git add work-tree-only &&
1878 test_when_finished "git rm -f work-tree-only" &&
1879 echo "find in work tree" >work-tree-only &&
1880 git grep --quiet "find in work tree" &&
1881 test_must_fail git grep --quiet --cached "find in work tree" &&
1882 test_must_fail git grep --quiet "find in work tree" HEAD
1883 '
1884
1885 test_expect_success 'grep can find things only in the work tree (i-t-a)' '
1886 echo "intend to add this" >intend-to-add &&
1887 git add -N intend-to-add &&
1888 test_when_finished "git rm -f intend-to-add" &&
1889 git grep --quiet "intend to add this" &&
1890 test_must_fail git grep --quiet --cached "intend to add this" &&
1891 test_must_fail git grep --quiet "intend to add this" HEAD
1892 '
1893
1894 test_expect_success 'grep does not search work tree with assume unchanged' '
1895 echo "intend to add this" >intend-to-add &&
1896 git add -N intend-to-add &&
1897 git update-index --assume-unchanged intend-to-add &&
1898 test_when_finished "git rm -f intend-to-add" &&
1899 test_must_fail git grep --quiet "intend to add this" &&
1900 test_must_fail git grep --quiet --cached "intend to add this" &&
1901 test_must_fail git grep --quiet "intend to add this" HEAD
1902 '
1903
1904 test_expect_success 'grep can find things only in the index' '
1905 echo "only in the index" >cache-this &&
1906 git add cache-this &&
1907 rm cache-this &&
1908 test_when_finished "git rm --cached cache-this" &&
1909 test_must_fail git grep --quiet "only in the index" &&
1910 git grep --quiet --cached "only in the index" &&
1911 test_must_fail git grep --quiet "only in the index" HEAD
1912 '
1913
1914 test_expect_success 'grep does not report i-t-a with -L --cached' '
1915 echo "intend to add this" >intend-to-add &&
1916 git add -N intend-to-add &&
1917 test_when_finished "git rm -f intend-to-add" &&
1918 git ls-files | grep -v "^intend-to-add\$" >expected &&
1919 git grep -L --cached "nonexistent_string" >actual &&
1920 test_cmp expected actual
1921 '
1922
1923 test_expect_success 'grep does not report i-t-a and assume unchanged with -L' '
1924 echo "intend to add this" >intend-to-add-assume-unchanged &&
1925 git add -N intend-to-add-assume-unchanged &&
1926 test_when_finished "git rm -f intend-to-add-assume-unchanged" &&
1927 git update-index --assume-unchanged intend-to-add-assume-unchanged &&
1928 git ls-files | grep -v "^intend-to-add-assume-unchanged\$" >expected &&
1929 git grep -L "nonexistent_string" >actual &&
1930 test_cmp expected actual
1931 '
1932
1933 test_expect_success 'grep of revision in partial clone batches prefetch and honors pathspec' '
1934 test_when_finished "rm -rf grep-partial-src grep-partial" &&
1935
1936 git init grep-partial-src &&
1937 (
1938 cd grep-partial-src &&
1939 git config uploadpack.allowfilter 1 &&
1940 git config uploadpack.allowanysha1inwant 1 &&
1941 mkdir a b &&
1942 echo "needle in haystack" >a/matches.txt &&
1943 echo "nothing to see here" >a/nomatch.txt &&
1944 echo "needle again" >b/matches.md &&
1945 git add . &&
1946 git commit -m "initial"
1947 ) &&
1948
1949 git clone --no-checkout --filter=blob:none \
1950 "file://$(pwd)/grep-partial-src" grep-partial &&
1951
1952 # All three blobs are missing immediately after a blobless clone.
1953 git -C grep-partial rev-list --quiet --objects \
1954 --missing=print HEAD >missing &&
1955 test_line_count = 3 missing &&
1956
1957 # A pathspec-limited grep should prefetch only the two blobs
1958 # in a/. It should fetch both blobs in one batched request.
1959 GIT_TRACE2_EVENT="$(pwd)/grep-trace-pathspec" \
1960 git -C grep-partial grep -c "needle" HEAD -- "a/*.txt" >result &&
1961
1962 # Only a/matches.txt contains "needle" among the matched paths.
1963 test_line_count = 1 result &&
1964
1965 # Exactly the two a/*.txt blobs should have been requested, and
1966 # the server packed those two objects in the response.
1967 test_trace2_data promisor fetch_count 2 <grep-trace-pathspec &&
1968 test_trace2_data pack-objects written 2 <grep-trace-pathspec &&
1969
1970 # b/matches.md should still be missing locally.
1971 git -C grep-partial rev-list --quiet --objects \
1972 --missing=print HEAD >missing &&
1973 test_line_count = 1 missing &&
1974
1975 # A second grep without a pathspec must recurse into both
1976 # subdirectories, but should request only the still-missing blob
1977 # from the promisor.
1978 GIT_TRACE2_EVENT="$(pwd)/grep-trace-all" \
1979 git -C grep-partial grep -c "needle" HEAD >result &&
1980
1981 test_line_count = 2 result &&
1982 test_trace2_data promisor fetch_count 1 <grep-trace-all &&
1983 test_trace2_data pack-objects written 1 <grep-trace-all &&
1984
1985 # Everything is local now.
1986 git -C grep-partial rev-list --quiet --objects \
1987 --missing=print HEAD >missing &&
1988 test_line_count = 0 missing
1989 '
1990
1991 test_done