diff options
-rw-r--r-- | Documentation/git-grep.txt | 17 | ||||
-rw-r--r-- | builtin/grep.c | 30 | ||||
-rwxr-xr-x | t/t7810-grep.sh | 34 |
3 files changed, 68 insertions, 13 deletions
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index e44a4988b7..15d6711d46 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -23,7 +23,7 @@ SYNOPSIS [-A <post-context>] [-B <pre-context>] [-C <context>] [-f <file>] [-e] <pattern> [--and|--or|--not|(|)|-e <pattern>...] - [--cached | --no-index | <tree>...] + [ [--exclude-standard] [--cached | --no-index | --untracked] | <tree>...] [--] [<pathspec>...] DESCRIPTION @@ -49,7 +49,20 @@ OPTIONS blobs registered in the index file. --no-index:: - Search files in the current directory, not just those tracked by git. + Search files in the current directory that is not managed by git. + +--untracked:: + In addition to searching in the tracked files in the working + tree, search also in untracked files. + +--no-exclude-standard:: + Also search in ignored files by not honoring the `.gitignore` + mechanism. Only useful with `--untracked`. + +--exclude-standard:: + Do not pay attention to ignored files specified via the `.gitignore` + mechanism. Only useful when searching files in the current directory + with `--no-index`. -a:: --text:: diff --git a/builtin/grep.c b/builtin/grep.c index 1c359c2671..5e6d3c3352 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -637,13 +637,15 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, return hit; } -static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec) +static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec, + int exc_std) { struct dir_struct dir; int i, hit = 0; memset(&dir, 0, sizeof(dir)); - setup_standard_excludes(&dir); + if (exc_std) + setup_standard_excludes(&dir); fill_directory(&dir, pathspec->raw); for (i = 0; i < dir.nr; i++) { @@ -750,7 +752,7 @@ static int help_callback(const struct option *opt, const char *arg, int unset) int cmd_grep(int argc, const char **argv, const char *prefix) { int hit = 0; - int cached = 0; + int cached = 0, untracked = 0, opt_exclude = -1; int seen_dashdash = 0; int external_grep_allowed__ignored; const char *show_in_pager = NULL, *default_pager = "dummy"; @@ -774,8 +776,13 @@ int cmd_grep(int argc, const char **argv, const char *prefix) struct option options[] = { OPT_BOOLEAN(0, "cached", &cached, "search in index instead of in the work tree"), - OPT_BOOLEAN(0, "index", &use_index, - "--no-index finds in contents not managed by git"), + { OPTION_BOOLEAN, 0, "index", &use_index, NULL, + "finds in contents not managed by git", + PARSE_OPT_NOARG | PARSE_OPT_NEGHELP }, + OPT_BOOLEAN(0, "untracked", &untracked, + "search in both tracked and untracked files"), + OPT_SET_INT(0, "exclude-standard", &opt_exclude, + "search also in ignored files", 1), OPT_GROUP(""), OPT_BOOLEAN('v', "invert-match", &opt.invert, "show non-matching lines"), @@ -1045,13 +1052,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (!show_in_pager) setup_pager(); + if (!use_index && (untracked || cached)) + die(_("--cached or --untracked cannot be used with --no-index.")); - if (!use_index) { - if (cached) - die(_("--cached cannot be used with --no-index.")); + if (!use_index || untracked) { + int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude; if (list.nr) - die(_("--no-index cannot be used with revs.")); - hit = grep_directory(&opt, &pathspec); + die(_("--no-index or --untracked cannot be used with revs.")); + hit = grep_directory(&opt, &pathspec, use_exclude); + } else if (0 <= opt_exclude) { + die(_("--exclude or --no-exclude cannot be used for tracked contents.")); } else if (!list.nr) { if (!cached) setup_work_tree(); diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 0d600163c8..81263b7851 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -554,7 +554,6 @@ test_expect_success 'outside of git repository' ' mkdir -p non/git/sub && echo hello >non/git/file1 && echo world >non/git/sub/file2 && - echo ".*o*" >non/git/.gitignore && { echo file1:hello && echo sub/file2:world @@ -571,6 +570,23 @@ test_expect_success 'outside of git repository' ' test_must_fail git grep o && git grep --no-index o >../../actual.sub && test_cmp ../../expect.sub ../../actual.sub + ) && + + echo ".*o*" >non/git/.gitignore && + ( + GIT_CEILING_DIRECTORIES="$(pwd)/non/git" && + export GIT_CEILING_DIRECTORIES && + cd non/git && + test_must_fail git grep o && + git grep --no-index --exclude-standard o >../actual.full && + test_cmp ../expect.full ../actual.full && + + { + echo ".gitignore:.*o*" + cat ../expect.full + } >../expect.with.ignored && + git grep --no-index --no-exclude o >../actual.full && + test_cmp ../expect.with.ignored ../actual.full ) ' @@ -583,6 +599,10 @@ test_expect_success 'inside git repository but with --no-index' ' { echo file1:hello && echo sub/file2:world + } >is/expect.unignored && + { + echo ".gitignore:.*o*" && + cat is/expect.unignored } >is/expect.full && : >is/expect.empty && echo file2:world >is/expect.sub && @@ -591,12 +611,24 @@ test_expect_success 'inside git repository but with --no-index' ' git init && test_must_fail git grep o >../actual.full && test_cmp ../expect.empty ../actual.full && + + git grep --untracked o >../actual.unignored && + test_cmp ../expect.unignored ../actual.unignored && + git grep --no-index o >../actual.full && test_cmp ../expect.full ../actual.full && + + git grep --no-index --exclude-standard o >../actual.unignored && + test_cmp ../expect.unignored ../actual.unignored && + cd sub && test_must_fail git grep o >../../actual.sub && test_cmp ../../expect.empty ../../actual.sub && + git grep --no-index o >../../actual.sub && + test_cmp ../../expect.sub ../../actual.sub && + + git grep --untracked o >../../actual.sub && test_cmp ../../expect.sub ../../actual.sub ) ' |