My company uses multiple git repos that all depend on one another. Often I find myself trying to grep through a few of them at the same time.
Regular grep works, but it takes a long time and displays a lot of noise.
git grep only searches through files that are NOT listed in
.gitignore file, but only works at per-repo level.
Few months ago I wrote a script to walk through my repos and generate a list of things I worked on that week.
I’ve modified that script to do
git grep for all git repos.
git-grep-all "some string" will produce:
repo-1 /some/file: some string /some/other/file: some string 123 repo-2 /yet/another/file: again some string
git-grep-all TODO will produce the following result.
grep-demo$ git-grep-all TODO preact /Users/akras/Desktop/grep-demo/preact/config/codemod-let-name.js:8: // @TODO unsafe, but without it we gain 20b gzipped: https://www.diffchecker.com/bVrOJWTO /Users/akras/Desktop/grep-demo/preact/test/browser/lifecycle.js:504: // @TODO Component mounted into elements (non-components) /Users/akras/Desktop/grep-demo/preact/test/browser/spec.js:97: // @TODO: migrate this to preact-compat rendertron /Users/akras/Desktop/grep-demo/rendertron/src/cache.js:29: // TODO(samli): check info (data) and loop through pages of entities to delete. /Users/akras/Desktop/grep-demo/rendertron/src/cache.js:107:// TODO(samli): Allow for caching options, like freshness options. /Users/akras/Desktop/grep-demo/rendertron/src/renderer.js:56: // TODO(samli): This needs to change to use the non-deprecated API after Chrome 61 vue /Users/akras/Desktop/grep-demo/vue/.gitignore:5:TODOs.md /Users/akras/Desktop/grep-demo/vue/benchmarks/dbmon/lib/memory-stats.js:61: // TODO, add a sanity check to see if values are bucketed. /Users/akras/Desktop/grep-demo/vue/packages/weex-vue-framework/factory.js:6383: // TODO: record before patch positions /Users/akras/Desktop/grep-demo/vue/packages/weex-vue-framework/factory.js:6417: // TODO: finish implementing move animations once /Users/akras/Desktop/grep-demo/vue/src/platforms/weex/runtime/components/transition-group.js:63: // TODO: record before patch positions /Users/akras/Desktop/grep-demo/vue/src/platforms/weex/runtime/components/transition-group.js:97: // TODO: finish implementing move animations once weweChat /Users/akras/Desktop/grep-demo/weweChat/README.MD:45:### TODO
Few notes to get it working
- You need to update the BASE variable. All my git repo are nested under one folder, and it looks as follows:
- I’ve saved this file to ~/bin/git-grep-all, made it executable, and added ~/bin to my PATH.
- Now I can just run
git-grep-all "my search string"to search through all repos that I have cloned.
#!/usr/bin/env python import commands import os import sys BASE = 'path/to/multiple/repos/to/search/' # <----------- Fix base path if len(sys.argv) < 2: print 'used as: grep-all "some string"' exit(1) search = sys.argv repos = os.listdir(BASE) repos = [os.path.join(BASE, repo) for repo in repos] results = "" for dir in repos: command = 'cd ' + dir + ' && git grep --color="always" \'' + search + '\'' results = commands.getstatusoutput(command) if( len(results) > 0 and "Not a directory" not in results and "Not a git repository" not in results ): print "\n" + os.path.relpath(dir, BASE) print results
Note: This method is not perfect. It will only grep repos at the state that you last left them in and it will not pull new changes from
origin. Still, I find that it works really well for 80% of my use cases.
Hope it helps.