Pre-commit guard
A hook runs git grep -q --cached to block commits whose staged files contain secrets or leftover debug calls.
Git · Command
git grep searches text for patterns inside a Git repository. It can search the tracked files in your working tree, the staged content in the index, or any commit or tree, without checking that tree out.
Last updated
You give it one or more patterns and, optionally, trees and pathspecs. If you pass no tree, Git reads the tracked files in your working tree. --cached makes it read the index blobs instead, and naming a tree such as a tag or commit makes it read the blobs stored there. Several -e patterns are joined with OR by default, and you can build Boolean expressions with --and, --not and parentheses. Matches are printed as filename:line, and flags like -n, -c, -l or -p change the output. By default the patterns are POSIX basic regular expressions. Searches run on several threads, and the grep.* config keys can set your preferred defaults.
git grep [<options>] [-e] <pattern> [--and|--or|--not|(|)|-e <pattern>...] [--cached | --untracked | --no-index | <tree>...] [--] [<pathspec>...]| Name | Type | Description |
|---|---|---|
<pattern> | string | The search expression. Put -e in front of it if it starts with a dash, and use -f <file> to read several patterns from a file. |
<tree>... | tree-ish (commit, tag, tree) | Search the blobs in these trees instead of the tracked files in the working tree. |
<pathspec>... | pathspec | Only search paths that match at least one of these patterns. Leading paths, globs and magic such as :^ for exclusion all work. |
--cached / --untracked / --no-index | flag | Choose what to search: the index, the working tree plus untracked files, or a plain directory that Git doesn't manage. |
-i, -w, -v, -E, -F, -P | flag | Control matching: ignore case, match whole words only, invert the match, or use extended, fixed-string or Perl regex syntax. |
-n, -c, -l/-L, -o, -p, -W, -A/-B/-C | flag | Control output: line numbers, match counts, file names only, only the matched text, the enclosing function, or context lines. |
--threads <num> | integer | How many worker threads to use. This overrides grep.threads. |
Prints the matches to stdout. With -q it prints nothing and returns exit status 0 if there was a match and a non-zero status if there wasn't.
# Search tracked C files for a word, with line numbers
git grep -n -w 'time_t' -- '*.[ch]'
# Count matches per file in the staged (index) content
git grep --cached -c 'TODO'
# Lines with #define AND (MAX_PATH or PATH_MAX) in tag v1.0, grouped by file
git grep --heading --break -n \
-e '#define' --and \( -e MAX_PATH -e PATH_MAX \) v1.0
# Exclude a directory via pathspec magic
git grep 'solution' -- ':^Documentation'
# Use in a script: fail if a debug marker is staged
if git grep -q --cached 'console.log'; then
echo 'Remove debug logging before committing' >&2
exit 1
fiThese commands search the working tree, the index and an old tag, combine patterns with Boolean operators, exclude a directory with a pathspec, and use -q as a check in a script.
A hook runs git grep -q --cached to block commits whose staged files contain secrets or leftover debug calls.
While fixing a bug in a production tag, you search that tag's tree for a symbol without checking it out or touching your current work.
Before renaming a function, git grep -l -w lists every tracked file that uses it, and -p shows which functions call it.
git grep --no-index gives you Git's pathspec filtering and output formatting in a folder that is not a repository.
By default git grep only reads tracked files, so it skips build output, ignored files and the .git directory. It can also search the index (--cached) or any commit or tree directly, without a checkout. It supports pathspec filtering and runs on several threads.
Follow-up: How would you search ignored files too? Use git grep --untracked --no-index-free form: git grep --untracked --no-exclude-standard, because --no-exclude-standard only has an effect together with --untracked.
Run git grep -e '#define' --and \( -e MAX_PATH -e PATH_MAX \). Several -e patterns are joined with OR by default, and --and binds more tightly than --or, so the escaped parentheses are needed to group the two alternatives.
Follow-up: What does --all-match do differently? It works at the file level: it only shows OR-matched lines from files that contain a match for every pattern, while --and requires all patterns on the same line.
Use git grep -q pattern and check the exit status. -q prints nothing and returns 0 when something matches and a non-zero status when nothing does. Put -e before the pattern if it could start with a dash.
Follow-up: How do you check only the staged content in a pre-commit hook? Add --cached, so the search reads the index blobs instead of the working-tree files, which may contain changes that aren't staged.
git loggit diffgit ls-filesgit configgitglossarygitattributes