Git includes a grep command to search through commits to a repo as well as the local files in the repo directory: git grep. Sometimes it is useful to search for a string throughout an entire repo, e.g. to find where an error message is produced.
The question "How to grep (search) committed code in the git history?" recommends:
git grep <regexp> $(git rev-list --all)
That searches through all the commits, which should include all the branches.
Another form would be:
git rev-list --all | (
while read revision; do
git grep -F 'yourWord' $revision
done
)
You can find even more example in this article:
I tried the above on one project large enough that git complained about the argument size, so if you run into this problem, do something like:
git rev-list --all | (while read rev; do git grep -e <regexp> $rev; done)
(see an alternative in the last section of this answer, below)
Don't forget those settings, if you want them:
# Allow Extended Regular Expressions
git config --global grep.extendRegexp true
# Always Include Line Numbers
git config --global grep.lineNumber true
This alias can help too:
git config --global alias.g "grep --break --heading --line-number"
Update August 2016: R.M. recommends in the comments
I got a "
fatal: bad flag '->' used after filename
" when trying thegit branch
version. The error was associated with aHEAD
aliasing notation.
I solved it by adding a
sed '/->/d'
in the pipe, between thetr
and thexargs
commands.
git branch -a | tr -d \* | sed '/->/d' | xargs git grep <regexp>
That is:
alias grep_all="git branch -a | tr -d \* | sed '/->/d' | xargs git grep"
grep_all <regexp>
This is an improvement over the solution chernjie had suggested, since git rev-list --all
is an overkill.
A more refined command can be:
# Don't use this, see above
git branch -a | tr -d \* | xargs git grep <regexp>
Which will allow you to search only branches (including remote branches)
You can even create a bash/zsh alias for it:
# Don't use this, see above
alias grep_all="git branch -a | tr -d \* | xargs git grep"
grep_all <regexp>
git log
can be a more effective way of searching for text across all branches, especially if there are many matches, and you want to see more recent (relevant) changes first.
git log -p --all -S 'search string'
git log -p --all -G 'match regular expression'
These log commands list commits that add or remove the given search string/regex, (generally) more recent first. The -p
option causes the relevant diff to be shown where the pattern was added or removed, so you can see it in context.
Having found a relevant commit that adds the text you were looking for (eg. 8beeff00d), find the branches that contain the commit:
git branch -a --contains 8beeff00d
I found this most useful:
git grep -i foo `git for-each-ref --format='%(refname)' refs/`
You'd need to adjust the last arguments depending on whether you want to only look at remote vs. local branches, i.e.:
git grep -i foo $(git for-each-ref --format='%(refname)' refs/remotes)
git grep -i foo $(git for-each-ref --format='%(refname)' refs/heads)
The alias I created looks like this:
grep-refs = !sh -c 'git grep "$0" "$@" "$(git for-each-ref --format=\"%(refname)\"" refs/)'
It's possible to do it in two common ways: Bash or Git aliases
Here are three commands:
git grep-branch
- Search in all branches local & remotegit grep-branch-local
- Search in local branches onlygit grep-branch-remote
- Remote branches onlyUsage is the same as git grep
git grep-branch "find my text"
git grep-branch --some-grep-options "find my text"
Commands should be added manually to ~/.gitconfig
file, because git config --global alias
evaluate complex code you add and mess it up.
[alias]
grep-branch = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' | xargs git grep $@; };f "
grep-branch-remote = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' | grep '^remotes' | xargs git grep $@; };f"
grep-branch-local = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' -e '^remotes' | xargs git grep $@; };f "
Note: When you add aliases and they fail to run - check backslashes \
they may require additional escape \\
in compare to bash commands.
git branch -a
- Display all branches;sed -e 's/[ \\*]*//'
- Trim spaces (from branch -a
) and * (active branch name have it);grep -v -e '\\->'
- Ignore complex names likeremotes/origin/HEAD -> origin/master
;grep '^remotes'
- Get all remote branches;grep -v -e '^remotes'
- Get branches except remote branches;git grep-branch-local -n getTastyCookies
-n
Prefix the line number to matching lines.
[user@pc project]$ git grep-branch-local -n getTastyCookies
dev:53:modules/factory/getters.php:function getTastyCookies($user);
master:50:modules/factory/getters.php:function getTastyCookies($user)
The current structure is:
:
- Separator
dev
53
modules/factory/getters.php
function getTastyCookies($user)
As you should know: Bash commands should be stored in .sh
scripts or run in a shell.
git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' -e '^remotes' | xargs git grep "TEXT"
git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' | grep '^remotes' | xargs git grep "TEXT"
git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' | xargs git grep "TEXT"
Here's how I do it:
git for-each-ref --format='%(*refname)' | xargs git grep SEARCHTERM
If you give any commit a SHA-1 hash value to git grep
you have it search in them, instead of the working copy.
To search all branches, you can get all the trees with git rev-list --all
. Put it all with
git grep "regexp" $(git rev-list --all)
... and have patience
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With