Skip to content

Commit c8610a2

Browse files
committed
grep: expose "status-only" feature via -q
Teach "git grep" a new "-q" option to report the presense of a match via its exit status without showing any output, similar to how "grep -q" works. Internally "grep" engine already knew this "status-only" mode of operation because it needed to grep inside log message to filter commits when called from the "git log" machinery, and this patch only exposes it to the command line tool. A somewhat unfair benchmark in the Linux kernel directory shows a dramatic improvement: (with patch) $ time ../git.git/git grep -q linux HEAD ; echo $? real 0m0.030s user 0m0.004s sys 0m0.004s 0 (without patch) $ time git grep linux HEAD >/dev/null; echo $? real 0m4.432s user 0m4.272s sys 0m0.076s 0 This is "somewhat unfair" because I knew a file with such a string comes very early in the tree traversal (namely, ".gitignore"). Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 2d7f98b commit c8610a2

File tree

1 file changed

+14
-2
lines changed

1 file changed

+14
-2
lines changed

builtin-grep.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
236236
!strcmp(ce->name, active_cache[nr]->name));
237237
nr--; /* compensate for loop control */
238238
}
239+
if (hit && opt->status_only)
240+
break;
239241
}
240242
free_grep_patterns(opt);
241243
return hit;
@@ -293,6 +295,8 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
293295
hit |= grep_tree(opt, paths, &sub, tree_name, down);
294296
free(data);
295297
}
298+
if (hit && opt->status_only)
299+
break;
296300
}
297301
strbuf_release(&pathbuf);
298302
return hit;
@@ -329,8 +333,11 @@ static int grep_directory(struct grep_opt *opt, const char **paths)
329333
setup_standard_excludes(&dir);
330334

331335
fill_directory(&dir, paths);
332-
for (i = 0; i < dir.nr; i++)
336+
for (i = 0; i < dir.nr; i++) {
333337
hit |= grep_file(opt, dir.entries[i]->name);
338+
if (hit && opt->status_only)
339+
break;
340+
}
334341
free_grep_patterns(opt);
335342
return hit;
336343
}
@@ -505,6 +512,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
505512
{ OPTION_CALLBACK, ')', NULL, &opt, NULL, "",
506513
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
507514
close_callback },
515+
OPT_BOOLEAN('q', "quick", &opt.status_only,
516+
"indicate hit with exit status without output"),
508517
OPT_BOOLEAN(0, "all-match", &opt.all_match,
509518
"show only matches from files that match all patterns"),
510519
OPT_GROUP(""),
@@ -628,8 +637,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
628637
for (i = 0; i < list.nr; i++) {
629638
struct object *real_obj;
630639
real_obj = deref_tag(list.objects[i].item, NULL, 0);
631-
if (grep_object(&opt, paths, real_obj, list.objects[i].name))
640+
if (grep_object(&opt, paths, real_obj, list.objects[i].name)) {
632641
hit = 1;
642+
if (opt.status_only)
643+
break;
644+
}
633645
}
634646
free_grep_patterns(&opt);
635647
return !hit;

0 commit comments

Comments
 (0)