3 test_description
='Test grep recurse-submodules feature
5 This test verifies the recurse-submodules feature correctly greps across
9 TEST_CREATE_REPO_NO_TEMPLATE
=1
12 GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
=1
13 export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
15 test_expect_success
'setup directory structure and submodule' '
16 echo "(1|2)d(3|4)" >a &&
20 git commit -m "add a and b" &&
23 echo "(1|2)d(3|4)" >submodule/a &&
24 git -C submodule add a &&
25 git -C submodule commit -m "add a" &&
26 git submodule add ./submodule &&
27 git commit -m "added submodule" &&
31 test_expect_success
'grep correctly finds patterns in a submodule' '
32 cat >expect <<-\EOF &&
35 submodule/a:(1|2)d(3|4)
38 git grep -e "(3|4)" --recurse-submodules >actual &&
39 test_cmp expect actual
42 test_expect_success
'grep finds patterns in a submodule via config' '
43 test_config submodule.recurse true &&
44 # expect from previous test
45 git grep -e "(3|4)" >actual &&
46 test_cmp expect actual
49 test_expect_success
'grep --no-recurse-submodules overrides config' '
50 test_config submodule.recurse true &&
51 cat >expect <<-\EOF &&
56 git grep -e "(3|4)" --no-recurse-submodules >actual &&
57 test_cmp expect actual
60 test_expect_success
'grep and basic pathspecs' '
61 cat >expect <<-\EOF &&
62 submodule/a:(1|2)d(3|4)
65 git grep -e. --recurse-submodules -- submodule >actual &&
66 test_cmp expect actual
69 test_expect_success
'grep and nested submodules' '
70 git init submodule/sub &&
71 echo "(1|2)d(3|4)" >submodule/sub/a &&
72 git -C submodule/sub add a &&
73 git -C submodule/sub commit -m "add a" &&
75 git -C submodule submodule add ./sub &&
76 git -C submodule add sub &&
77 git -C submodule commit -m "added sub" &&
80 git commit -m "updated submodule" &&
83 cat >expect <<-\EOF &&
86 submodule/a:(1|2)d(3|4)
87 submodule/sub/a:(1|2)d(3|4)
90 git grep -e "(3|4)" --recurse-submodules >actual &&
91 test_cmp expect actual
94 test_expect_success
'grep and multiple patterns' '
95 cat >expect <<-\EOF &&
97 submodule/a:(1|2)d(3|4)
98 submodule/sub/a:(1|2)d(3|4)
101 git grep -e "(3|4)" --and -e "(1|2)" --recurse-submodules >actual &&
102 test_cmp expect actual
105 test_expect_success
'grep and multiple patterns' '
106 cat >expect <<-\EOF &&
110 git grep -e "(3|4)" --and --not -e "(1|2)" --recurse-submodules >actual &&
111 test_cmp expect actual
114 test_expect_success
'basic grep tree' '
115 cat >expect <<-\EOF &&
118 HEAD:submodule/a:(1|2)d(3|4)
119 HEAD:submodule/sub/a:(1|2)d(3|4)
122 git grep -e "(3|4)" --recurse-submodules HEAD >actual &&
123 test_cmp expect actual
126 test_expect_success
'grep tree HEAD^' '
127 cat >expect <<-\EOF &&
130 HEAD^:submodule/a:(1|2)d(3|4)
133 git grep -e "(3|4)" --recurse-submodules HEAD^ >actual &&
134 test_cmp expect actual
137 test_expect_success
'grep tree HEAD^^' '
138 cat >expect <<-\EOF &&
143 git grep -e "(3|4)" --recurse-submodules HEAD^^ >actual &&
144 test_cmp expect actual
147 test_expect_success
'grep tree and pathspecs' '
148 cat >expect <<-\EOF &&
149 HEAD:submodule/a:(1|2)d(3|4)
150 HEAD:submodule/sub/a:(1|2)d(3|4)
153 git grep -e "(3|4)" --recurse-submodules HEAD -- submodule >actual &&
154 test_cmp expect actual
157 test_expect_success
'grep tree and pathspecs' '
158 cat >expect <<-\EOF &&
159 HEAD:submodule/a:(1|2)d(3|4)
160 HEAD:submodule/sub/a:(1|2)d(3|4)
163 git grep -e "(3|4)" --recurse-submodules HEAD -- "submodule*a" >actual &&
164 test_cmp expect actual
167 test_expect_success
'grep tree and more pathspecs' '
168 cat >expect <<-\EOF &&
169 HEAD:submodule/a:(1|2)d(3|4)
172 git grep -e "(3|4)" --recurse-submodules HEAD -- "submodul?/a" >actual &&
173 test_cmp expect actual
176 test_expect_success
'grep tree and more pathspecs' '
177 cat >expect <<-\EOF &&
178 HEAD:submodule/sub/a:(1|2)d(3|4)
181 git grep -e "(3|4)" --recurse-submodules HEAD -- "submodul*/sub/a" >actual &&
182 test_cmp expect actual
185 test_expect_success
!MINGW
'grep recurse submodule colon in name' '
187 test_when_finished "rm -rf parent" &&
188 echo "(1|2)d(3|4)" >"parent/fi:le" &&
189 git -C parent add "fi:le" &&
190 git -C parent commit -m "add fi:le" &&
194 test_when_finished "rm -rf su:b" &&
195 echo "(1|2)d(3|4)" >"su:b/fi:le" &&
196 git -C "su:b" add "fi:le" &&
197 git -C "su:b" commit -m "add fi:le" &&
200 test_config_global protocol.file.allow always &&
201 git -C parent submodule add "../su:b" "su:b" &&
202 git -C parent commit -m "add submodule" &&
205 cat >expect <<-\EOF &&
207 su:b/fi:le:(1|2)d(3|4)
209 git -C parent grep -e "(1|2)d(3|4)" --recurse-submodules >actual &&
210 test_cmp expect actual &&
212 cat >expect <<-\EOF &&
213 HEAD:fi:le:(1|2)d(3|4)
214 HEAD:su:b/fi:le:(1|2)d(3|4)
216 git -C parent grep -e "(1|2)d(3|4)" --recurse-submodules HEAD >actual &&
217 test_cmp expect actual
220 test_expect_success
'grep history with moved submoules' '
222 test_when_finished "rm -rf parent" &&
223 echo "(1|2)d(3|4)" >parent/file &&
224 git -C parent add file &&
225 git -C parent commit -m "add file" &&
229 test_when_finished "rm -rf sub" &&
230 echo "(1|2)d(3|4)" >sub/file &&
231 git -C sub add file &&
232 git -C sub commit -m "add file" &&
235 test_config_global protocol.file.allow always &&
236 git -C parent submodule add ../sub dir/sub &&
237 git -C parent commit -m "add submodule" &&
240 cat >expect <<-\EOF &&
241 dir/sub/file:(1|2)d(3|4)
244 git -C parent grep -e "(1|2)d(3|4)" --recurse-submodules >actual &&
245 test_cmp expect actual &&
247 git -C parent mv dir/sub sub-moved &&
248 git -C parent commit -m "moved submodule" &&
251 cat >expect <<-\EOF &&
253 sub-moved/file:(1|2)d(3|4)
255 git -C parent grep -e "(1|2)d(3|4)" --recurse-submodules >actual &&
256 test_cmp expect actual &&
258 cat >expect <<-\EOF &&
259 HEAD^:dir/sub/file:(1|2)d(3|4)
260 HEAD^:file:(1|2)d(3|4)
262 git -C parent grep -e "(1|2)d(3|4)" --recurse-submodules HEAD^ >actual &&
263 test_cmp expect actual
266 test_expect_success
'grep using relative path' '
267 test_when_finished "rm -rf parent sub" &&
269 echo "(1|2)d(3|4)" >sub/file &&
270 git -C sub add file &&
271 git -C sub commit -m "add file" &&
275 echo "(1|2)d(3|4)" >parent/file &&
276 git -C parent add file &&
278 echo "(1|2)d(3|4)" >parent/src/file2 &&
279 git -C parent add src/file2 &&
280 test_config_global protocol.file.allow always &&
281 git -C parent submodule add ../sub &&
282 git -C parent commit -m "add files and submodule" &&
286 cat >expect <<-\EOF &&
288 src/file2:(1|2)d(3|4)
291 git -C parent grep --recurse-submodules -e "(1|2)d(3|4)" >actual &&
292 test_cmp expect actual &&
294 # Relative path to top
295 cat >expect <<-\EOF &&
298 ../sub/file:(1|2)d(3|4)
300 git -C parent/src grep --recurse-submodules -e "(1|2)d(3|4)" -- .. >actual &&
301 test_cmp expect actual &&
303 # Relative path to submodule
304 cat >expect <<-\EOF &&
305 ../sub/file:(1|2)d(3|4)
307 git -C parent/src grep --recurse-submodules -e "(1|2)d(3|4)" -- ../sub >actual &&
308 test_cmp expect actual
311 test_expect_success
'grep from a subdir' '
312 test_when_finished "rm -rf parent sub" &&
314 echo "(1|2)d(3|4)" >sub/file &&
315 git -C sub add file &&
316 git -C sub commit -m "add file" &&
321 echo "(1|2)d(3|4)" >parent/src/file &&
322 git -C parent add src/file &&
323 test_config_global protocol.file.allow always &&
324 git -C parent submodule add ../sub src/sub &&
325 git -C parent submodule add ../sub sub &&
326 git -C parent commit -m "add files and submodules" &&
329 # Verify grep from root works
330 cat >expect <<-\EOF &&
332 src/sub/file:(1|2)d(3|4)
335 git -C parent grep --recurse-submodules -e "(1|2)d(3|4)" >actual &&
336 test_cmp expect actual &&
338 # Verify grep from a subdir works
339 cat >expect <<-\EOF &&
343 git -C parent/src grep --recurse-submodules -e "(1|2)d(3|4)" >actual &&
344 test_cmp expect actual
347 test_incompatible_with_recurse_submodules
()
349 test_expect_success
"--recurse-submodules and $1 are incompatible" "
350 test_must_fail git grep -e. --recurse-submodules $1 2>actual &&
351 test_grep 'not supported with --recurse-submodules' actual
355 test_incompatible_with_recurse_submodules
--untracked
357 test_expect_success
'grep --recurse-submodules --no-index ignores --recurse-submodules' '
358 git grep --recurse-submodules --no-index -e "^(.|.)[\d]" >actual &&
359 cat >expect <<-\EOF &&
361 submodule/a:(1|2)d(3|4)
362 submodule/sub/a:(1|2)d(3|4)
364 test_cmp expect actual
367 test_expect_success
'grep --recurse-submodules should pass the pattern type along' '
369 test_must_fail git grep -F --recurse-submodules -e "(.|.)[\d]" &&
370 test_must_fail git -c grep.patternType=fixed grep --recurse-submodules -e "(.|.)[\d]" &&
373 git grep -G --recurse-submodules -e "(.|.)[\d]" >actual &&
374 cat >expect <<-\EOF &&
376 submodule/a:(1|2)d(3|4)
377 submodule/sub/a:(1|2)d(3|4)
379 test_cmp expect actual &&
380 git -c grep.patternType=basic grep --recurse-submodules -e "(.|.)[\d]" >actual &&
381 test_cmp expect actual &&
384 git grep -E --recurse-submodules -e "(.|.)[\d]" >actual &&
385 cat >expect <<-\EOF &&
386 .gitmodules:[submodule "submodule"]
387 .gitmodules: path = submodule
388 .gitmodules: url = ./submodule
390 submodule/.gitmodules:[submodule "sub"]
391 submodule/a:(1|2)d(3|4)
392 submodule/sub/a:(1|2)d(3|4)
394 test_cmp expect actual &&
395 git -c grep.patternType=extended grep --recurse-submodules -e "(.|.)[\d]" >actual &&
396 test_cmp expect actual &&
397 git -c grep.extendedRegexp=true grep --recurse-submodules -e "(.|.)[\d]" >actual &&
398 test_cmp expect actual &&
401 if test_have_prereq PCRE
403 git grep -P --recurse-submodules -e "(.|.)[\d]" >actual &&
404 cat >expect <<-\EOF &&
407 submodule/a:(1|2)d(3|4)
408 submodule/sub/a:(1|2)d(3|4)
410 test_cmp expect actual &&
411 git -c grep.patternType=perl grep --recurse-submodules -e "(.|.)[\d]" >actual &&
412 test_cmp expect actual
416 test_expect_success
'grep --recurse-submodules with submodules without .gitmodules in the working tree' '
417 test_when_finished "git -C submodule checkout .gitmodules" &&
418 rm submodule/.gitmodules &&
419 git grep --recurse-submodules -e "(.|.)[\d]" >actual &&
420 cat >expect <<-\EOF &&
422 submodule/a:(1|2)d(3|4)
423 submodule/sub/a:(1|2)d(3|4)
425 test_cmp expect actual
431 git submodule foreach
--recursive 'git reset --hard' &&
432 git submodule foreach
--recursive 'git clean -fd'
435 test_expect_success
'grep --recurse-submodules without --cached considers worktree modifications' '
437 echo "A modified line in submodule" >>submodule/a &&
438 echo "submodule/a:A modified line in submodule" >expect &&
439 git grep --recurse-submodules "A modified line in submodule" >actual &&
440 test_cmp expect actual
443 test_expect_success
'grep --recurse-submodules with --cached ignores worktree modifications' '
445 echo "A modified line in submodule" >>submodule/a &&
446 test_must_fail git grep --recurse-submodules --cached "A modified line in submodule" >actual 2>&1 &&
447 test_must_be_empty actual
450 test_expect_failure
'grep --textconv: superproject .gitattributes does not affect submodules' '
452 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
453 echo "a diff=d2x" >.gitattributes &&
455 cat >expect <<-\EOF &&
458 git grep --textconv --recurse-submodules x >actual &&
459 test_cmp expect actual
462 test_expect_failure
'grep --textconv: superproject .gitattributes (from index) does not affect submodules' '
464 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
465 echo "a diff=d2x" >.gitattributes &&
466 git add .gitattributes &&
469 cat >expect <<-\EOF &&
472 git grep --textconv --recurse-submodules x >actual &&
473 test_cmp expect actual
476 test_expect_failure
'grep --textconv: superproject .git/info/attributes does not affect submodules' '
478 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
479 super_info="$(git rev-parse --git-path info)" &&
480 super_attr="$super_info/attributes" &&
481 test_when_finished "rm -f \"$super_attr\"" &&
482 mkdir "$super_info" &&
483 echo "a diff=d2x" >"$super_attr" &&
485 cat >expect <<-\EOF &&
488 git grep --textconv --recurse-submodules x >actual &&
489 test_cmp expect actual
492 # Note: what currently prevents this test from passing is not that the
493 # .gitattributes file from "./submodule" is being ignored, but that it is being
494 # propagated to the nested "./submodule/sub" files.
496 test_expect_failure
'grep --textconv correctly reads submodule .gitattributes' '
498 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
499 echo "a diff=d2x" >submodule/.gitattributes &&
501 cat >expect <<-\EOF &&
502 submodule/a:(1|2)x(3|4)
504 git grep --textconv --recurse-submodules x >actual &&
505 test_cmp expect actual
508 test_expect_failure
'grep --textconv correctly reads submodule .gitattributes (from index)' '
510 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
511 echo "a diff=d2x" >submodule/.gitattributes &&
512 git -C submodule add .gitattributes &&
513 rm submodule/.gitattributes &&
515 cat >expect <<-\EOF &&
516 submodule/a:(1|2)x(3|4)
518 git grep --textconv --recurse-submodules x >actual &&
519 test_cmp expect actual
522 test_expect_failure
'grep --textconv correctly reads submodule .git/info/attributes' '
524 test_config_global diff.d2x.textconv "sed -e \"s/d/x/\"" &&
526 submodule_info="$(git -C submodule rev-parse --path-format=absolute --git-path info)" &&
527 submodule_attr="$submodule_info/attributes" &&
528 test_when_finished "rm -f \"$submodule_attr\"" &&
529 echo "a diff=d2x" >"$submodule_attr" &&
531 cat >expect <<-\EOF &&
532 submodule/a:(1|2)x(3|4)
534 git grep --textconv --recurse-submodules x >actual &&
535 test_cmp expect actual
538 test_expect_failure
'grep saves textconv cache in the appropriate repository' '
540 test_config_global diff.d2x_cached.textconv "sed -e \"s/d/x/\"" &&
541 test_config_global diff.d2x_cached.cachetextconv true &&
542 echo "a diff=d2x_cached" >submodule/.gitattributes &&
544 # We only read/write to the textconv cache when grepping from an OID,
545 # as the working tree file might have modifications.
546 git grep --textconv --cached --recurse-submodules x &&
548 super_textconv_cache="$(git rev-parse --git-path refs/notes/textconv/d2x_cached)" &&
549 sub_textconv_cache="$(git -C submodule rev-parse \
550 --path-format=absolute --git-path refs/notes/textconv/d2x_cached)" &&
551 test_path_is_missing "$super_textconv_cache" &&
552 test_path_is_file "$sub_textconv_cache"
555 test_expect_success
'grep partially-cloned submodule' '
556 # Set up clean superproject and submodule for partial cloning.
557 test_config_global protocol.file.allow always &&
559 git init super/sub &&
562 test_commit --no-tag "Add file in superproject" \
563 super-file "Some content for super-file" &&
564 test_commit -C sub --no-tag "Add file in submodule" \
565 sub-file "Some content for sub-file" &&
566 git submodule add ./sub &&
567 git commit -m "Add other as submodule sub" &&
569 test_commit -C sub --no-tag --append "Update file in submodule" \
570 sub-file "Some more content for sub-file" &&
572 git commit -m "Update submodule" &&
574 git config --local uploadpack.allowfilter 1 &&
575 git config --local uploadpack.allowanysha1inwant 1 &&
576 git -C sub config --local uploadpack.allowfilter 1 &&
577 git -C sub config --local uploadpack.allowanysha1inwant 1
579 # Clone the superproject & submodule, then make sure we can lazy-fetch submodule objects.
580 git clone --filter=blob:none --also-filter-submodules \
581 --recurse-submodules "file://$(pwd)/super" partial &&
584 cat >expect <<-\EOF &&
585 HEAD^:sub/sub-file:Some content for sub-file
586 HEAD^:super-file:Some content for super-file
589 GIT_TRACE2_EVENT="$(pwd)/trace2.log" git grep -e content \
590 --recurse-submodules HEAD^ >actual &&
591 test_cmp expect actual &&
592 # Verify that we actually fetched data from the promisor remote:
593 grep \"category\":\"promisor\",\"key\":\"fetch_count\",\"value\":\"1\" trace2.log
597 test_expect_success
'check scope of core.useReplaceRefs' '
603 echo C >base/sub/c &&
604 echo D >base/sub/d &&
606 git -C base/sub add c d &&
607 git -C base/sub commit -m "Add files" &&
609 git -C base submodule add ./sub &&
610 git -C base add a b sub &&
611 git -C base commit -m "Add files and submodule" &&
613 A=$(git -C base rev-parse HEAD:a) &&
614 B=$(git -C base rev-parse HEAD:b) &&
615 C=$(git -C base/sub rev-parse HEAD:c) &&
616 D=$(git -C base/sub rev-parse HEAD:d) &&
618 git -C base replace $A $B &&
619 git -C base/sub replace $C $D &&
621 test_must_fail git -C base grep --cached --recurse-submodules A &&
622 test_must_fail git -C base grep --cached --recurse-submodules C &&
624 git -C base config core.useReplaceRefs false &&
625 git -C base grep --recurse-submodules A &&
626 test_must_fail git -C base grep --cached --recurse-submodules C &&
628 git -C base/sub config core.useReplaceRefs false &&
629 git -C base grep --cached --recurse-submodules A &&
630 git -C base grep --cached --recurse-submodules C &&
632 git -C base config --unset core.useReplaceRefs &&
633 test_must_fail git -C base grep --cached --recurse-submodules A &&
634 git -C base grep --cached --recurse-submodules C