Using Git, how could I search for a string across all branches?
Asked Answered
D

11

321

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...)

Densimeter answered 22/8, 2011 at 17:41 Comment(2)
git-grep might be what you're looking for, but I'm not sure yet which options you'd need...Ramey
See also: How to grep (search through) committed code in the Git historyWindrow
T
277

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:
Thrips answered 22/8, 2011 at 17:50 Comment(13)
This causes me a segmentation fault. Might be tortoisegitmerge (Windows), though.Markswoman
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!Ramon
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?Monas
how can I list branch name only. Currently, it list all the hash contains the string.Nautical
Github search is on master branch only. From help.github.com/articles/searching-code: "Only the default branch is indexed for code search. In most cases, this will be the master branch."Roulade
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.Orcus
To find the branch name (having located the commit hash), you can use git branch -a --contains <commit_hash>Sonnysonobuoy
This gives Wed Oct 17 02:39 PM liminex: git grep '["]Welcome' $(git rev-list --all) -> bash: /usr/bin/git: Argument list too longDisciplinarian
Hi, i'm developing a tool to search in all remote and local repos using this command : github.com/GaetanoPiazzolla/git-search if you want, take a look.Wiskind
If this only searches one branch, then this doesn't really answer the question.Bigler
github search is broken for private organization repositories github.com/orgs/community/discussions/45538Secrest
@Disciplinarian this answer by teastburn resolves this -bash: /usr/bin/git: Argument list too long" issueFlinders
git grep "string/regexp" $(git rev-list --all) doesn't just search the tips of all branches in the repo, it searches all commits in all branches and tags in the entire repo. That's quite different, depending on what someone wants. To just search the tips of all branches, see my answer here. I also speed it up with one process per branch. For my super long and thorough answer with full explanations, see here.Windrow
C
207

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 through) committed code in the Git history

Cecillececily answered 17/5, 2013 at 18:18 Comment(5)
Also, this seems to be more compatible with other kind of consoles like fishshellMortify
Thanks!!! using ZSH and this worked while @Thrips command gave the error you mentioned! But warning, this can take VERY long time for a large repo with a long history.Cordi
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.Chordophone
@Chordophone What is the -J supposed to do? Because xargs -J seems not to exist on all versions of xargs: man7.org/linux/man-pages/man1/xargs.1.htmlFreyah
This flag might be unique to macOS/BSD. xargs -I % echo % would run echo <input line> once for each input line. xargs -J % echo % would run echo <input line 1> <input line 2> <input line 3> ... 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.Chordophone
P
141

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
Pubescent answered 22/6, 2016 at 8:19 Comment(8)
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.Nicholnichola
I can't believe how many times this question has been asked and answered, yet you're the only one with the correct answer.Distinguished
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 ...Soonsooner
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 highlightBugbane
This should be the accepted answer. Grepping a string across all branches but for the latest content only is a very common use case.Lucie
Case-insensitive search across all branches, filtered by file extension: git grep -i "string" `git show-ref --heads | cut -d' ' -f2` -- '*.json'Wormeaten
This can also be useful for showing remotes. Since the OP was asking for local references only, I'm mentioning this only as a comment, but it was extremely useful for searching across codecommit repos, as AWS doesn't provide a search feature: git grep "v2-additional-subjects" git for-each-ref --format="%(refname)" refs/remotes/origin/ | cut -d/ -f3-Idiopathy
This can also be useful for showing remotes. Since the OP was asking for local references only, I'm mentioning this only as a comment, but it was extremely useful for searching across codecommit repos, as AWS doesn't provide a search feature: git grep "v2-additional-subjects" `git for-each-ref --format="%(refname)" refs/remotes/origin/ | cut -d/ -f3-`Idiopathy
N
42

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"
Nicholnichola answered 24/3, 2017 at 5:9 Comment(5)
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 relationEdveh
This comment, right here above my comment, is the correct answer! It's the only one that didn't error out.Kileykilgore
Is there a way to get the branch names from this?Shere
Thanks @IlyaSheershoff ! You need to add cut -d' ' -f 1 to the remote branch search as well.Suzetta
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)Rosauraroscius
C
24

You can try this:

git log -Sxxxx  # Search all commits
git log -Sxxxx  --branches[=<pattern>]   # Search branches
Corie answered 12/2, 2018 at 4:42 Comment(3)
Across all branches: git log --all -s"search_string"Variable
above needs the capital SDupe
This helped with finding which commit contained a submodule pointing to a commit missing on its remote. I.e. error of the form: fatal: git upload-pack: not our ref <hash>, thanks!Epizoon
L
5

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.

Lycurgus answered 28/8, 2021 at 12:28 Comment(0)
E
1

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

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://mcmap.net/q/12340/-how-to-find-the-git-commit-that-introduced-a-string-in-any-branch

Revert a commit, commit id may not be at HEAD

git revert commit_id
Elevation answered 6/2, 2023 at 6:29 Comment(0)
S
1

For me it is :

git branch | xargs git grep -c "string_to_search"

git branch : looks for branchs in local.

git grep -c : looks for the strings in a given branch.

| xargs : a pipe and xargs to give the branches as inputs to the previous command.

Setting answered 25/12, 2023 at 12:3 Comment(0)
T
0

To ignore case use -i:

git log -i --all --grep='word1 Word2'
Thick answered 21/2, 2022 at 4:52 Comment(1)
This also seems to be the first answer that mentions --grep. Actually, that might be because this searches the git log rather than file contents across all branches, doesn't it? So it doesn't exactly fit the question.Apivorous
W
0

Here's a multi-process way that dramatically increases the speed of the search by spawning one git grep process per branch or commit:

# ---------------------------------------------
# 1. Search all local branches
# ---------------------------------------------
# Search only these files and folders in all local branches
time git branch | awk '{print $NF}' \
    | xargs -P "$(nproc)" -I {} git --no-pager grep -n 'my regex search' {} \
    -- "path/to/my_file.c" "path/to/my_folder"

# ---------------------------------------------
# 2. Search all remote branches of all remotes
# ---------------------------------------------
# Search only these files and folders in all remote branches
time git branch -r | awk '{print $NF}' \
    | xargs -P "$(nproc)" -I {} git --no-pager grep -n 'my regex search' {} \
    -- "path/to/my_file.c" "path/to/my_folder"

# ---------------------------------------------
# 3. Search all local **and** remote branches
# ---------------------------------------------
# Search only these files and folders in all local and remote branches
time git branch -a | awk '{print $NF}' \
    | xargs -P "$(nproc)" -I {} git --no-pager grep -n 'my regex search' {} \
    -- "path/to/my_file.c" "path/to/my_folder"

# ---------------------------------------------
# Search **all commits** in the entire repository
# ---------------------------------------------
# Search only these files and folders in all commits (reachable from any branch 
# or tag) in the whole repository
time git rev-list --all \
    | xargs -P "$(nproc)" -I {} git --no-pager grep -n 'my regex search' {} \
    -- "path/to/my_file.c" "path/to/my_folder"

For a full explanation of each command, and a ton more info., see my full answer here: All about searching (via grep or similar) in your git repositories.

Windrow answered 2/2 at 4:48 Comment(0)
J
0

Highly customizable terminal script:

git branch -r | grep "/master$" | xargs -I{} git --no-pager grep -E -n "(search string 1|search string 2...)" {} -- "*.js" "*.ts" "*.kt" "*.swift" "*.json"

This command will help you search for specific strings (can be regex) in files of various programming languages (optional) within branches name ended with "/master" (optional) in a Git repository.

git brach -r: List of all branches name

grep "/master$": (optional) filter branch name using regex, only search branches that end with /master

git grep: Main program to search

  • --no-pager: (optional) Display all result at once, not using pager program (scroll to display more).

  • -E: This option enables extended regular expression syntax for the search strings.

  • -n: This option displays line numbers along with the matching lines.

"(search string 1|search string 2...)": you can you regex here

-- "*.js" "*.ts" "*.kt" "*.swift" "*.json": (optional) Search with specific file types, add or remove as you want

Jackquelin answered 18/3 at 10:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.