Learn git-grep to boost your command line search!
Tags: git, grep, gitgrep, commandline
Published: 2019-09-05 12:46:12

---
title: Learn git-grep to boost your command line search!
published: true
description: Learn git-grep and become more powerful than you can possibly imagine
tags: git, grep, gitgrep, commandline
canonical_url: https://irian.to/blogs/learn-git-grep-to-boost-your-command-line-search
---

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

- [git grep](https://remarkablemark.org/blog/2017/05/07/git-grep/)
- [git-grep doc](https://git-scm.com/docs/git-grep)
- [Search git repo like a ninja](http://travisjeffery.com/b/2012/02/search-a-git-repo-like-a-ninja/)
- [fun with git grep](https://gitster.livejournal.com/27674.html)

Happy hacking!