git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 3/3] builtin/grep: introduce --use-index argument

From
Thomas Gummerer <t.gummerer@gmail.com>
Date
Jan 11, 2016, 17:00 UTC
Message-ID
<1452531648-16575-4-git-send-email-t.gummerer@gmail.com>
In-Reply-To
<1452531648-16575-1-git-send-email-t.gummerer@gmail.com>

Currently when git grep is used outside of a git repository without the --no-index option git simply dies. Introduce a new --use-index command line argument, which can be set to always, optional, or never. If it is set to always, git grep continues to behave as it currently does. If set to optional, git grep will work normally if executed inside of a git repository, and behave like git grep --no-index if used outside of a git repository. If set to never, git grep will behave like git grep --no-index regardless of whether it is used inside or outside of a git repository.

Helped-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-grep.txt | 13 ++++++++
 builtin/grep.c             | 47 +++++++++++++++++++++++---
 t/t7810-grep.sh            | 82 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 137 insertions(+), 5 deletions(-)
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index 4a44d6d..90ff643 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -25,6 +25,7 @@ SYNOPSIS
 	   [-W | --function-context]
 	   [-f <file>] [-e] <pattern>
 	   [--and|--or|--not|(|)|-e <pattern>...]
+	   [--use-index=<always|optional|never>]
 	   [ [--[no-]exclude-standard] [--cached | --no-index | --untracked] | <tree>...]
 	   [--] [<pathspec>...]
 
@@ -66,6 +67,18 @@ OPTIONS
 --no-index::
 	Search files in the current directory that is not managed by Git.
 
+--use-index::
+	Set the behavior of git grep when used in- or outside of a git
+	repository.  If set to always, the command can only be used
+	inside of a git repository, and will fail if it is used
+	outside of a git repository.  If set to never, it will work
+	both inside and outside of a git repository, but will not use
+	any information in the index if used inside of a repository.
+	If set to optional, it will work both inside and outside of a
+	git repository, using the information available in the index
+	if used inside a repository.  Always and optional can be
+	overridden by `--no-index`.
+
 --untracked::
 	In addition to searching in the tracked files in the working
 	tree, search also in untracked files.
diff --git a/builtin/grep.c b/builtin/grep.c
index 3a27bd5..bb2add9 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -19,6 +19,9 @@
 #include "dir.h"
 #include "pathspec.h"
 
+#define GREP_NO_INDEX_EXPLICIT 1
+#define GREP_NO_INDEX_IMPLICIT 2
+
 static char const * const grep_usage[] = {
 	N_("git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"),
 	NULL
@@ -626,13 +629,17 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 	int i;
 	int dummy;
 	int no_index = 0;
+	const char *use_index = NULL;
 	int pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;
 
 	struct option options[] = {
 		OPT_BOOL(0, "cached", &cached,
 			N_("search in index instead of in the work tree")),
 		OPT_BIT(0, "no-index", &no_index,
-			N_("find in contents not managed by git"), 1),
+			N_("find in contents not managed by git"),
+			GREP_NO_INDEX_EXPLICIT),
+		OPT_STRING(0, "use-index", &use_index, N_("always|optional|never"),
+			   N_("options for using the index")),
 		OPT_BOOL(0, "untracked", &untracked,
 			N_("search in both tracked and untracked files")),
 		OPT_SET_INT(0, "exclude-standard", &opt_exclude,
@@ -755,6 +762,25 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 			     PARSE_OPT_STOP_AT_NON_OPTION);
 	grep_commit_pattern_type(pattern_type_arg, &opt);
 
+	if (use_index) {
+		if (!strcmp(use_index, "always")) {
+			/* same as git grep without --use-index */
+		} else if (!strcmp(use_index, "optional")) {
+			if (!no_index && !startup_info->have_repository) {
+				int nongit = 0;
+
+				setup_git_directory_gently(&nongit);
+				if (nongit)
+					no_index = GREP_NO_INDEX_IMPLICIT;
+			}
+		} else if (!strcmp(use_index, "never")) {
+			no_index = GREP_NO_INDEX_EXPLICIT;
+		} else {
+			die(_("invalid option \"%s\" for --use-index, expecting"
+			      " always, optional or never"), use_index);
+		}
+	}
+
 	if (!no_index && !startup_info->have_repository)
 		/* die the same way as if we did it at the beginning */
 		setup_git_directory();
@@ -873,13 +899,24 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 	if (!show_in_pager && !opt.status_only)
 		setup_pager();
 
-	if (no_index && (untracked || cached))
-		die(_("--cached or --untracked cannot be used with --no-index."));
+	if (no_index && (untracked || cached)) {
+		if (no_index == GREP_NO_INDEX_IMPLICIT)
+			die(_("--cached or --untracked cannot be used outside "
+			      "of a git repository."));
+		else
+			die(_("--cached or --untracked cannot be used with "
+			      "--no-index or --no-index=never."));
+	}
 
 	if (no_index || untracked) {
 		int use_exclude = (opt_exclude < 0) ? !no_index : !!opt_exclude;
-		if (list.nr)
-			die(_("--no-index or --untracked cannot be used with revs."));
+		if (list.nr) {
+			if (no_index == GREP_NO_INDEX_IMPLICIT)
+				die(_("cannot use revs outside of a git repository."));
+			else
+				die(_("--no-index, --use-index=never or "
+				      "--untracked cannot be used with revs."));
+		}
 		hit = grep_directory(&opt, &pathspec, use_exclude);
 	} else if (0 <= opt_exclude) {
 		die(_("--[no-]exclude-standard cannot be used for tracked contents."));
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index cc4b97d..9776f15 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -821,6 +821,88 @@ test_expect_success 'outside of git repository' '
 	)
 '
 
+test_expect_success 'outside of git repository with --use-index=optional' '
+	rm -fr non &&
+	mkdir -p non/git/sub &&
+	echo hello >non/git/file1 &&
+	echo world >non/git/sub/file2 &&
+	cat <<-\EOF >non/expect.full &&
+	file1:hello
+	sub/file2:world
+	EOF
+	echo file2:world >non/expect.sub &&
+	(
+		GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
+		export GIT_CEILING_DIRECTORIES &&
+		cd non/git &&
+		test_must_fail git grep --use-index=always o &&
+		git grep --use-index=optional o >../actual.full &&
+		test_cmp ../expect.full ../actual.full &&
+		cd sub &&
+		test_must_fail git grep --use-index=always o &&
+		git grep --use-index=optional o >../../actual.sub &&
+		test_cmp ../../expect.sub ../../actual.sub
+	) &&
+
+	echo ".*o*" >non/git/.gitignore &&
+	(
+		GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
+		export GIT_CEILING_DIRECTORIES &&
+		cd non/git &&
+		test_must_fail git grep --use-index=always o &&
+		git grep --use-index=optional --exclude-standard o >../actual.full &&
+		test_cmp ../expect.full ../actual.full &&
+
+		{
+			echo ".gitignore:.*o*" &&
+			cat ../expect.full
+		} >../expect.with.ignored &&
+		git grep --use-index=optional --no-exclude o >../actual.full &&
+		test_cmp ../expect.with.ignored ../actual.full
+	)
+'
+
+test_expect_success 'outside of git repository with --use-index=never' '
+	rm -fr non &&
+	mkdir -p non/git/sub &&
+	echo hello >non/git/file1 &&
+	echo world >non/git/sub/file2 &&
+	cat <<-\EOF >non/expect.full &&
+	file1:hello
+	sub/file2:world
+	EOF
+	echo file2:world >non/expect.sub &&
+	(
+		GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
+		export GIT_CEILING_DIRECTORIES &&
+		cd non/git &&
+		test_must_fail git grep --use-index=always o &&
+		git grep --use-index=never o >../actual.full &&
+		test_cmp ../expect.full ../actual.full &&
+		cd sub &&
+		test_must_fail git grep --use-index=always o &&
+		git grep --use-index=never o >../../actual.sub &&
+		test_cmp ../../expect.sub ../../actual.sub
+	) &&
+
+	echo ".*o*" >non/git/.gitignore &&
+	(
+		GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
+		export GIT_CEILING_DIRECTORIES &&
+		cd non/git &&
+		test_must_fail git grep --use-index=always o &&
+		git grep --use-index=never --exclude-standard o >../actual.full &&
+		test_cmp ../expect.full ../actual.full &&
+
+		{
+			echo ".gitignore:.*o*" &&
+			cat ../expect.full
+		} >../expect.with.ignored &&
+		git grep --use-index=never --no-exclude o >../actual.full &&
+		test_cmp ../expect.with.ignored ../actual.full
+	)
+'
+
 test_expect_success 'inside git repository but with --no-index' '
 	rm -fr is &&
 	mkdir -p is/git/sub &&
-- 
2.7.0.3.g214d8d0.dirty
Previous: Thomas GummererNext: Thomas Gummerer
Message 22 of 32 in “Implicitly use --no-index if git grep is used outside of repo”
  1. 0/3 Implicitly use --no-index if git grep is used outside of repoThomas Gummerer, Jan 10, 2016
  2. 1/3 t7810: correct --no-index testThomas Gummerer, Jan 10, 2016
  3. 2/3 builtin/grep: rename use_index to no_indexThomas Gummerer, Jan 10, 2016
  4. Junio C HamanoJan 11, 2016
  5. 3/3 builtin/grep: allow implicit --no-indexThomas Gummerer, Jan 10, 2016
  6. Duy NguyenJan 11, 2016
  7. Thomas GummererJan 11, 2016
  8. Junio C HamanoJan 11, 2016
  9. Thomas GummererJan 11, 2016
  10. Jeff KingJan 11, 2016
  11. Junio C HamanoJan 11, 2016
  12. Eric SunshineJan 11, 2016
  13. Thomas GummererJan 11, 2016
  14. Junio C HamanoJan 11, 2016
  15. Thomas GummererJan 11, 2016
  16. Junio C HamanoJan 11, 2016
  17. Junio C HamanoJan 11, 2016
  18. Thomas GummererJan 11, 2016
  19. 0/3 Introduce a --use-index command line argument in git grepThomas Gummerer, Jan 11, 2016
  20. 1/3 t7810: correct --no-index testThomas Gummerer, Jan 11, 2016
  21. 2/3 builtin/grep: rename use_index to no_indexThomas Gummerer, Jan 11, 2016
  22. 3/3 builtin/grep: introduce --use-index argumentThomas Gummerer, Jan 11, 2016
  23. 0/2 grep: add fallbackToNoIndex config optionThomas Gummerer, Jan 11, 2016
  24. 1/2 t7810: correct --no-index testThomas Gummerer, Jan 11, 2016
  25. 2/2 builtin/grep: add grep.fallbackToNoIndex configThomas Gummerer, Jan 11, 2016
  26. Jeff KingJan 11, 2016
  27. Thomas GummererJan 11, 2016
  28. 0/2 grep: add fallbackToNoIndex config optionThomas Gummerer, Jan 12, 2016
  29. 1/2 t7810: correct --no-index testThomas Gummerer, Jan 12, 2016
  30. 2/2 builtin/grep: add grep.fallbackToNoIndex configThomas Gummerer, Jan 12, 2016
  31. Jeff KingJan 12, 2016
  32. Thomas GummererJan 12, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.