diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index 6a8b1e3..7c74165 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -242,6 +242,13 @@ OPTIONS
If given, limit the search to paths matching at least one pattern.
Both leading paths match and glob(7) patterns are supported.
+ATTRIBUTES
+----------
+
+grep::
+ If the grep attribute is unset on a file using the linkgit:gitattributes[1]
+ mechanism, then that file will not be searched.
+
Examples
--------
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index a85b187..3ffcec7 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -869,6 +869,15 @@ If this attribute is not set or has an invalid value, the value of the
`gui.encoding` configuration variable is used instead
(See linkgit:git-config[1]).
+Configuring files to search
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`grep`
+^^^^^^
+
+If the attribute `grep` is unset for a file then linkgit:git-grep[1]
+will ignore that file while searching for matches.
+
USING MACRO ATTRIBUTES
----------------------
diff --git a/builtin/grep.c b/builtin/grep.c
index 9ce064a..9f8dfc0 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -398,6 +398,10 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
struct strbuf pathbuf = STRBUF_INIT;
char *name;
+ if (!should_grep_path(opt, filename + tree_name_len)) {
+ return 0;
+ }
+
if (opt->relative && opt->prefix_length) {
quote_path_relative(filename + tree_name_len, -1, &pathbuf,
opt->prefix);@@ -464,6 +468,10 @@ static int grep_file(struct grep_opt *opt, const char *filename)
struct strbuf buf = STRBUF_INIT;
char *name;
+ if (!should_grep_path(opt, filename)) {
+ return 0;
+ }
+
if (opt->relative && opt->prefix_length)
quote_path_relative(filename, -1, &buf, opt->prefix);
elsediff --git a/grep.c b/grep.c
index 486230b..e948576 100644
--- a/grep.c
+++ b/grep.c
@@ -1,5 +1,6 @@
#include "cache.h"
#include "grep.h"
+#include "attr.h"
#include "userdiff.h"
#include "xdiff-interface.h"
@@ -829,6 +830,26 @@ static inline void grep_attr_unlock(struct grep_opt *opt)
#define grep_attr_unlock(opt)
#endif
+static struct git_attr_check attr_check[1];
+static void setup_attr_check(void)
+{
+ if (attr_check[0].attr)
+ return; /* already done */
+ attr_check[0].attr = git_attr("grep");
+}
+int should_grep_path(struct grep_opt *opt, const char *name) {
+ int ret = 1;
+
+ grep_attr_lock(opt);
+ setup_attr_check();
+ git_check_attr(name, 1, attr_check);
+ if (ATTR_FALSE(attr_check[0].value))
+ ret = 0;
+ grep_attr_unlock(opt);
+
+ return ret;
+}
+
static int match_funcname(struct grep_opt *opt, const char *name, char *bol, char *eol)
{
xdemitconf_t *xecfg = opt->priv;diff --git a/grep.h b/grep.h
index fb205f3..266002d 100644
--- a/grep.h
+++ b/grep.h
@@ -129,6 +129,7 @@ extern void append_header_grep_pattern(struct grep_opt *, enum grep_header_field
extern void compile_grep_patterns(struct grep_opt *opt);
extern void free_grep_patterns(struct grep_opt *opt);
extern int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long size);
+extern int should_grep_path(struct grep_opt *opt, const char *name);
extern struct grep_opt *grep_opt_dup(const struct grep_opt *opt);
extern int grep_threads_ok(const struct grep_opt *opt);
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 7ba5b16..c991518 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -871,4 +871,34 @@ test_expect_success 'mimic ack-grep --group' '
test_cmp expected actual
'
+test_expect_success 'with -grep attribute' '
+ echo "hello.c -grep" >.gitattributes &&
+ test_must_fail git grep printf &&
+ rm .gitattributes
+'
+
+test_expect_success 'with -grep attribute on specific file' '
+ echo "hello.c -grep" >.gitattributes &&
+ test_must_fail git grep printf hello.c &&
+ rm .gitattributes
+'
+
+test_expect_success 'with -grep attribute on specific revision' '
+ echo "hello.c -grep" >.gitattributes &&
+ test_must_fail git grep printf HEAD &&
+ rm .gitattributes
+'
+
+test_expect_success 'with -grep attribute on specific file/revision' '
+ echo "hello.c -grep" >.gitattributes &&
+ test_must_fail git grep printf HEAD hello.c &&
+ rm .gitattributes
+'
+
+test_expect_failure 'with -grep attribute on specific tree' '
+ echo "hello.c -grep" >.gitattributes &&
+ test_must_fail git grep printf HEAD:hello.c &&
+ rm .gitattributes
+'
+
test_done
--
1.7.9.rc2.1.g1fdd3