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