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

Re: git diff: support "-U" and "--unified" options properly

From
Linus Torvalds <torvalds@osdl.org>
Date
May 15, 2006, 03:49 UTC
Message-ID
<Pine.LNX.4.64.0605142044550.3866@g5.osdl.org>
In-Reply-To
<Pine.LNX.4.64.0605141745410.3866@g5.osdl.org>
On Sun, 14 May 2006, Linus Torvalds wrote:
Show 13 quoted lines
> 
> So I would actually assume that the solution is to simply make 
> grep_cache() have a simple
> 
> 	#ifdef __unix__
> 		if (!cached) {
> 			hit = external_grep(opt, paths, cached);
> 			if (hit >= 0)
> 				return hit;
> 		}
> 	#endif
> 
> at the top, so that we'd have the best of both worlds.

Ok. Here's a slightly tested version, my out-lined thing from the email was pretty close to working already.

It's not perfect, but it gets the "git grep some-random-string" down to the good old half-a-second range for the kernel.

It should convert more of the argument flags for "grep", that should be trivial to expand (I did a few just as an example). It should also bother to try to return the right "hit" value (which it doesn't, right now - the code is kind of there, but I didn't actually bother to do it _right_).

Also, right now it _just_ limits by number of arguments, but it should also strictly speaking limit by total argument size (ie add up the length of the filenames, and do the "exec_grep()" flush call if it's bigger than some random value like 32kB).

But I think that it's _conceptually_ doing all the right things, and it seems to work. So maybe somebody else can do some of the final polish.

		Linus
----
diff --git a/builtin-grep.c b/builtin-grep.c
index fead356..14471db 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -12,6 +12,7 @@ #include "tree-walk.h"
 #include "builtin.h"
 #include <regex.h>
 #include <fnmatch.h>
+#include <sys/wait.h>
 
 /*
  * git grep pathspecs are somewhat different from diff-tree pathspecs;
@@ -409,12 +410,90 @@ static int grep_file(struct grep_opt *op
 	return i;
 }
 
+static int exec_grep(int argc, const char **argv)
+{
+	pid_t pid;
+	int status;
+
+	argv[argc] = NULL;
+	pid = fork();
+	if (pid < 0)
+		return pid;
+	if (!pid) {
+		execvp("grep", (char **) argv);
+		exit(255);
+	}
+	while (waitpid(pid, &status, 0) < 0) {
+		if (errno == EINTR)
+			continue;
+		return -1;
+	}
+	if (WIFEXITED(status)) {
+		if (!WEXITSTATUS(status))
+			return 1;
+		return 0;
+	}
+	return -1;
+}
+
+#define MAXARGS 1000
+
+static int external_grep(struct grep_opt *opt, const char **paths, int cached)
+{
+	int i, nr, argc, hit;
+	const char *argv[MAXARGS+1];
+	struct grep_pat *p;
+
+	nr = 0;
+	argv[nr++] = "grep";
+	if (opt->word_regexp)
+		argv[nr++] = "-w";
+	if (opt->name_only)
+		argv[nr++] = "-l";
+	for (p = opt->pattern_list; p; p = p->next) {
+		argv[nr++] = "-e";
+		argv[nr++] = p->pattern;
+	}
+	argv[nr++] = "--";
+
+	hit = 0;
+	argc = nr;
+	for (i = 0; i < active_nr; i++) {
+		struct cache_entry *ce = active_cache[i];
+		if (ce_stage(ce) || !S_ISREG(ntohl(ce->ce_mode)))
+			continue;
+		if (!pathspec_matches(paths, ce->name))
+			continue;
+		argv[argc++] = ce->name;
+		if (argc < MAXARGS)
+			continue;
+		hit += exec_grep(argc, argv);
+		argc = nr;
+	}
+	if (argc > nr)
+		hit += exec_grep(argc, argv);
+	return 0;
+}
+
 static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
 {
 	int hit = 0;
 	int nr;
 	read_cache();
 
+#ifdef __unix__
+	/*
+	 * Use the external "grep" command for the case where
+	 * we grep through the checked-out files. It tends to
+	 * be a lot more optimized
+	 */
+	if (!cached) {
+		hit = external_grep(opt, paths, cached);
+		if (hit >= 0)
+			return hit;
+	}
+#endif
+
 	for (nr = 0; nr < active_nr; nr++) {
 		struct cache_entry *ce = active_cache[nr];
 		if (ce_stage(ce) || !S_ISREG(ntohl(ce->ce_mode)))
Previous: Junio C HamanoNext: Martin Langhoff
Message 10 of 21 in “git diff: support "-U" and "--unified" options properly”
  1. Linus TorvaldsMay 13, 2006
  2. Junio C HamanoMay 13, 2006
  3. Junio C HamanoMay 13, 2006
  4. Linus TorvaldsMay 13, 2006
  5. Junio C HamanoMay 13, 2006
  6. Linus TorvaldsMay 13, 2006
  7. Junio C HamanoMay 15, 2006
  8. Linus TorvaldsMay 15, 2006
  9. Junio C HamanoMay 15, 2006
  10. Linus TorvaldsMay 15, 2006
  11. Martin LanghoffMay 14, 2006
  12. Josef WeidendorferMay 14, 2006
  13. Junio C HamanoMay 14, 2006
  14. Branch relationships (was:Re: git diff: support "-U" and "--unified" options properly)Josef Weidendorfer, May 14, 2006
  15. Junio C HamanoMay 14, 2006
  16. Josef WeidendorferMay 14, 2006
  17. Junio C HamanoMay 14, 2006
  18. Josef WeidendorferMay 14, 2006
  19. Junio C HamanoMay 14, 2006
  20. Josef WeidendorferMay 15, 2006
  21. Junio C HamanoMay 15, 2006

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.