DEV Community

loading...

Learn git-grep to boost your command line search!

iggredible profile image Igor Irianto Originally published at irian.to Updated on ・3 min read

When searching for contents inside files from command-line, we probably think of find and grep, but how many of us have heard about git grep?

When searching inside your work tree, I found it more convenient than find/ grep. Here is how you can get started with git-grep today!

Things to know

Git grep searches inside project with git. The only requirement is the project need to be tracked (hint: git add .). It will work without having to commit it.

Let's git greppin'

The pattern is very simple. Do git grep {pattern} anywhere inside your project directory.

  • To search for "foo":
git grep foo

Here are other useful variants:

  • Search with line number
git grep -n foo
  • Returning only file name:
git grep -l foo
  • It is regex-compatible.
git grep "f[^\s]*\s"
  • To tell how many match in each file:
git grep -c foo
  • To only look under certain file extension (ignore matches from other files)
git grep foo *.js

and / or

  • To search for "foo" or "bar", we can do:
git grep -e foo -e bar
  • To search for a file containing "foo" and "bar" and they are on the same line:
git grep -e foo --and -e bar

To search for a file containing "foo" and "bar", not necessarily on the same line:

git grep --all-match -e foo -e bar

There are more (check man git-grep, but above are the ones I find useful).

Getting fancy: search within and between commits

The real power of git grep is its ability to search inside ANY commit we want.

Here are the two that I found very useful:

  • Search inside specific commit

There are two ways to do it: reference it relative to HEAD and reference its SHA.

git grep "foo" HEAD~1 // search ONLY in one commit before current head
git grep "foo" a1b2 // search ONLY in commit a1b2
  • Search inside multiple commits

It also accepts multiple commit references.

git grep "foo" HEAD HEAD~1 HEAD~7 // search in current head, previous head, and 7th from head.
git grep "foo" a1b2 HEAD~5 // search inside a1b2 SHA and 5th from head
  • Search everything between 2 commits

This uses git rev-list command. Here are some quick refreshers:

git rev-list HEAD~3..HEAD // Returns all commits between HEAD~3 and HEAD.
git rev-list --all // Returns ALL Commits from the dawn of time to present day.

Combining rev-list with git-grep, we can do:

  • Search for all occurrences of "foo" between HEAD~3 and HEAD
git grep foo $(git rev-list HEAD~3..HEAD)
  • Search for ALL occurrences of "foo" from the very beginning to current.
git grep foo $(git rev-list --all)

Of course, we can put together everything we learned. This returns filename(s) from every single commit we have that contain, in each file, "bar" and anything that matches f[^\s]*\s pattern.

git grep --all-match -l -e "f[^\s]*\s" -e bar $(git rev-list --all)

That's it! I find git grep more convenient than traditional grep or find when I need to search file contents inside working tree. Of course, find/grep have their own usage that git grep can't do, but that's for another time.

Resources

Happy hacking!

Discussion (2)

pic
Editor guide
Collapse
bootcode profile image
Robin Palotai

Good to know about the version search! Thank you.

Recently I learned about ripgrep (rg) which is a super nice substitute for grep.

Collapse
iggredible profile image
Igor Irianto Author

This one? I never heard of this before - and it has >>10k stars!! Wow! Gonna read it today.
Thanks for sharing!!!