297

Using Git, how could I search within all files in all local branches for a given string?

GitHub specific: is it possible to perform the above search across all GitHub branches? (There are several remote branches on my remote GitHub repository that ideally I wouldn't have to bring down for this search...)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ivar
  • 5,102
  • 2
  • 31
  • 43
  • 1
    [git-grep](http://www.kernel.org/pub/software/scm/git/docs/git-grep.html) might be what you're looking for, but I'm not sure yet which options you'd need... – johnny Aug 22 '11 at 17:51
  • Possible duplicate of [How to grep (search) committed code in the git history?](https://stackoverflow.com/questions/2928584/how-to-grep-search-committed-code-in-the-git-history) – nekketsuuu Jul 11 '17 at 21:01

8 Answers8

251

You can do this on a Git repository:

git grep "string/regexp" $(git rev-list --all)

GitHub advanced search has code search capability:

The code search will look through all of the code publicly hosted on GitHub. You can also filter by:

  • the language: language:
  • the repository name (including the username): repo:
  • the file path: path:
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
manojlds
  • 290,304
  • 63
  • 469
  • 417
  • This causes me a segmentation fault. Might be tortoisegitmerge (Windows), though. – bean5 Aug 01 '14 at 17:47
  • 18
    This is really not the best way to do this. It doesn't control the amount of git refs that are passed to `git grep ...`. Look to the other answers, they're far better than this one even though it's marked as the accepted answer! – slm Mar 20 '17 at 15:17
  • 2
    it would be great if you can add an example for your filters, e.g. `path:`, because the documentation at a glance doesnt look clear where to apply this filter, im assuming its before the quotes in your query example? – blamb May 30 '17 at 18:19
  • 3
    how can I list branch name only. Currently, it list all the hash contains the string. – harryfeng Aug 10 '17 at 19:11
  • 12
    Github search is on master branch *only*. From https://help.github.com/articles/searching-code/: "Only the default branch is indexed for code search. In most cases, this will be the master branch." – RedPanda Feb 28 '18 at 22:55
  • 3
    This will only work on a relatively smallish git repository. A git sha is 40 chars plus a space (or LF in this case) between them. On linux your arg list is limited to ~128kb (~256kb on a Mac). Your argument list will get way too big after a 3k-4k commits (6k - 8k on a Mac). That's not at all unreasonably on a fair sized repository. – stuckj Jun 12 '18 at 15:10
  • 1
    To find the branch name (having located the commit hash), you can use `git branch -a --contains ` – Russ Oct 01 '18 at 11:40
  • 2
    This gives `Wed Oct 17 02:39 PM liminex: git grep '["]Welcome' $(git rev-list --all)` -> `bash: /usr/bin/git: Argument list too long` – fIwJlxSzApHEZIl Oct 17 '18 at 21:41
  • 1
    Hi, i'm developing a tool to search in all remote and local repos using this command : https://github.com/GaetanoPiazzolla/git-search if you want, take a look. – Gaetano Piazzolla Sep 14 '20 at 07:36
  • If this only searches one branch, then this doesn't really answer the question. – BrainSlugs83 Nov 10 '21 at 00:26
  • github search is broken for private organization repositories https://github.com/orgs/community/discussions/45538 – Anton Duzenko Jun 14 '23 at 16:34
  • @fIwJlxSzApHEZIl [this](https://stackoverflow.com/a/16615508/6565511) answer by teastburn resolves this `-bash: /usr/bin/git: Argument list too long" ` issue – Nathan majicvr.com Jun 25 '23 at 01:37
197

If you use @manojlds Git grep command and get an error:

-bash: /usr/bin/git: Argument list too long" 

then you should use xargs:

git rev-list --all | xargs git grep "string/regexp"

Also see How to grep (search) committed code in the Git history

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
teastburn
  • 2,938
  • 1
  • 20
  • 12
  • 1
    Also, this seems to be more compatible with other kind of consoles like fishshell – Daniel Aug 17 '16 at 14:18
  • 5
    Thanks!!! using ZSH and this worked while @manojlds command gave the error you mentioned! But warning, this can take VERY long time for a large repo with a long history. – lacostenycoder Feb 28 '18 at 16:29
  • 3
    If you are looking in a specific file, you can use: `git rev-list --all | xargs -J % git grep "string/rexexp" % -- filename`. This will run `git grep` on blocks of commits that are inserted where the `%` appears. – rgov Sep 29 '21 at 19:46
  • @rgov What is the `-J` supposed to do? Because `xargs -J` seems not to exist on all versions of `xargs`: https://man7.org/linux/man-pages/man1/xargs.1.html – Jann Poppinga Feb 22 '23 at 06:58
  • This flag might be unique to macOS/BSD. `xargs -I % echo %` would run `echo ` once for each input line. `xargs -J % echo %` would run `echo ...` for as many input lines as it can fit in one command, resulting in fewer invocations. Using `-I` also works but will call `git grep` more times. – rgov Feb 22 '23 at 10:31
134

In many cases git rev-list --all can return a huge number of commits, taking forever to scan. If you, instead of searching through every commit on every branch in your repository history, just want to search all branch tips, you can replace it with git show-ref -s --heads. So in total:

git grep "string" `git show-ref -s --heads`

or:

git show-ref -s --heads | xargs git grep "string"

Tip: You can write output in file to view in an editor:

nano ~/history.txt
git show-ref -s --heads | xargs git grep "search string here" >> ~/history.txt
Dan Berindei
  • 7,054
  • 3
  • 41
  • 48
Zitrax
  • 19,036
  • 20
  • 88
  • 110
  • 13
    `git show-ref --heads` lists the hash and the ref name so it (2nd line) will search twice. so `git show-ref --heads | cut -d' ' -f2` is better as it will only list the ref names. – hIpPy May 25 '17 at 06:27
  • 8
    I can't believe how many times this question has been asked and answered, yet you're the only one with the *correct* answer. – Sammitch Sep 29 '17 at 19:39
  • 6
    `git show-ref --heads -s` outputs the SHA1 hash only. Also, if there are multiple branches pointing to the same commit, you'll have duplicates. You can remove them with `sort -u`, like so `git show-ref --heads -s | sort -u | xargs git grep ...` – Steve Feb 23 '18 at 16:27
  • 3
    Here's the function I added to my bashrc. Hope it helps someone: `function gsearch { git grep $1 $(git show-ref --heads) | grep "refs/heads" | grep $1 } # last grep to keep grep color highlight` – AFP_555 Feb 05 '19 at 02:27
  • 6
    This should be the accepted answer. Grepping a string across all branches *but for the latest content only* is a very common use case. – dr_ Jul 11 '19 at 11:48
  • Case-insensitive search across all branches, filtered by file extension: ```git grep -i "string" `git show-ref --heads | cut -d' ' -f2` -- '*.json'``` – user3100212 Sep 01 '23 at 08:58
40

There are a few issues with the solutions listed here (even accepted).

You do not need to list all the hashes as you'll get duplicates. Also, it takes more time.

It builds on this where you can search a string "test -f /" on multiple branches master and dev as

git grep "test -f /" master dev

which is same as

printf "master\ndev" | xargs git grep "test -f /"

So here goes.

This finds the hashes for the tip of all local branches and searches only in those commits:

git branch -v --no-abbrev | awk -F' *' '{print $3}' | xargs git grep "string/regexp"

If you need to search in remote branches too then add -a:

git branch -a -v --no-abbrev | awk -F' *' '{print $3}' | xargs git grep "string/regexp"

Further:

# Search in local branches
git branch | cut -c3- | xargs git grep "string"

# Search in remote branches
git branch -r | cut -c3- | xargs git grep "string"

# Search in all (local and remote) branches
git branch -a | cut -c3- | cut -d' ' -f 1 | xargs git grep "string"

# Search in branches, and tags
git show-ref | grep -v "refs/stash" | cut -d' ' -f2 | xargs git grep "string"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
hIpPy
  • 4,649
  • 6
  • 51
  • 65
  • 15
    at least for the search in all branches should be: `git branch -a | cut -c3- | cut -d' ' -f 1 | xargs git grep "string"` or it will fail with `->` symbol in files list, which denotes local to remote branches relation – Ilya Sheershoff Feb 01 '18 at 11:38
  • 2
    This comment, right here above my comment, is the correct answer! It's the only one that didn't error out. – user3147973 Jan 10 '21 at 17:47
  • Is there a way to get the branch names from this? – Stefan Mar 24 '21 at 15:36
  • Thanks @IlyaSheershoff ! You need to add `cut -d' ' -f 1` to the remote branch search as well. – Anurag Pande Apr 21 '22 at 20:56
  • A simpler (and more robust) replacement for the cut / awk operation would be to use the `--format` parameter of `git branch`: `git branch -a --format "%(refname)" ` only returns the refnames (one per line) – creinig Apr 05 '23 at 12:41
18

You can try this:

git log -Sxxxx  # Search all commits
git log -Sxxxx  --branches[=<pattern>]   # Search branches
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Victor Choy
  • 4,006
  • 28
  • 35
4

Following @peter-mortensen & manojlds's solution, I use git for-each-ref as subcommand to list only branches with name.

git grep "string/regexp" $(git for-each-ref --format='%(refname:short)' refs/heads)

This accomplish a better visualization, showing only named braches and making only one result for each branch.

Pierre.Vriens
  • 2,117
  • 75
  • 29
  • 42
Anibal Anto
  • 99
  • 1
  • 2
1

To display the branch name along with the search results, you can use a loop to search each branch separately, like this:

bash code

for branch in $(git branch | awk '{print $1}'); do
    echo "Branch: $branch"
    git grep "SEARCH_WORD" $(git rev-parse $branch)
done

This loop uses git branch to list all branches, and awk to extract just the branch names. Then, it uses git rev-parse to get the commit hash of each branch, and git grep to search for the string "deleteTemplateDocument" in that branch. The output will show the branch name and the matching results for each branch.

git log -S <search string> --source --all

https://stackoverflow.com/a/5816177/5368856

Revert a commit, commit id may not be at HEAD

git revert commit_id
-1

To ignore case use -i:

git log -i --all --grep='word1 Word2'
joydeba
  • 778
  • 1
  • 9
  • 24