grep: turn off gitlink detection for --no-index

If we are running "git grep --no-index" outside of a git repository, we behave roughly like "grep -r", examining all files in the current directory and its subdirectories. However, because we use fill_directory() to do the recursion, it will skip over any directories which look like sub-repositories. For a normal git operation (like "git grep" in a repository) this makes sense; we do not want to cross the boundary out of our current repository into a submodule. But for "--no-index" without a repository, we should look at all files, including embedded repositories. There is one exception, though: we probably should _not_ descend into ".git" directories. Doing so is inefficient and unlikely to turn up useful hits. This patch drops our use of dir.c's gitlink-detection, but we do still avoid ".git". That makes us more like tools such as "ack" or "ag", which also know to avoid cruft in .git. As a bonus, this also drops our usage of the ref code when we are outside of a repository, making the transition to pluggable ref backends cleaner. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Mar 7, 2016 at 10:51 UTC 85975c0c7f46aeb5010121959e38c339038758a7
2 files changed +31 -2
builtin/grep.c
+4 -2
@@ -522,12 +522,14 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
522 }
523
524 static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
525 - int exc_std)
525 + int exc_std, int use_index)
526 {
527 struct dir_struct dir;
528 int i, hit = 0;
529
530 memset(&dir, 0, sizeof(dir));
531 + if (!use_index)
532 + dir.flags |= DIR_NO_GITLINKS;
533 if (exc_std)
534 setup_standard_excludes(&dir);
535
@@ -902,7 +904,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
904 int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude;
905 if (list.nr)
906 die(_("--no-index or --untracked cannot be used with revs."));
905 - hit = grep_directory(&opt, &pathspec, use_exclude);
907 + hit = grep_directory(&opt, &pathspec, use_exclude, use_index);
908 } else if (0 <= opt_exclude) {
909 die(_("--[no-]exclude-standard cannot be used for tracked contents."));
910 } else if (!list.nr) {
t/t7810-grep.sh
+27
@@ -905,6 +905,33 @@ test_expect_success 'inside git repository but with --no-index' '
905 )
906 '
907
908 +test_expect_success 'grep --no-index descends into repos, but not .git' '
909 + rm -fr non &&
910 + mkdir -p non/git &&
911 + (
912 + GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
913 + export GIT_CEILING_DIRECTORIES &&
914 + cd non/git &&
915 +
916 + echo magic >file &&
917 + git init repo &&
918 + (
919 + cd repo &&
920 + echo magic >file &&
921 + git add file &&
922 + git commit -m foo &&
923 + echo magic >.git/file
924 + ) &&
925 +
926 + cat >expect <<-\EOF &&
927 + file
928 + repo/file
929 + EOF
930 + git grep -l --no-index magic >actual &&
931 + test_cmp expect actual
932 + )
933 +'
934 +
935 test_expect_success 'setup double-dash tests' '
936 cat >double-dash <<EOF &&
937 --