É possível executar uma 'pesquisa grep' em todas as ramificações de um projeto Git?

Respostas:

189

A pergunta " Como grep (pesquisar) código confirmado no histórico do git? " Recomenda:

 git grep <regexp> $(git rev-list --all)

Isso pesquisa todos os commits, que devem incluir todos os branches.

Outra forma seria:

git rev-list --all | (
    while read revision; do
        git grep -F 'yourWord' $revision
    done
)

Você pode encontrar ainda mais exemplos neste artigo :

Eu tentei o acima em um projeto grande o suficiente para que o git se queixasse do tamanho do argumento, portanto, se você enfrentar esse problema, faça algo como:

git rev-list --all | (while read rev; do git grep -e <regexp> $rev; done)

(veja uma alternativa na última seção desta resposta, abaixo)

Não esqueça essas configurações, se você as quiser:

# Allow Extended Regular Expressions
git config --global grep.extendRegexp true
# Always Include Line Numbers
git config --global grep.lineNumber true

Esse alias também pode ajudar:

git config --global alias.g "grep --break --heading --line-number"

Nota: chernjie sugeriu que isso git rev-list --allé um exagero.

Um comando mais refinado pode ser:

git branch -a | tr -d \* | xargs git grep <regexp>

O que permitirá pesquisar apenas ramificações (incluindo ramificações remotas)

Você pode até criar um alias do bash / zsh para ele:

alias grep_all="git branch -a | tr -d \* | xargs git grep"
grep_all <regexp>

Atualização em agosto de 2016: a RM recomenda nos comentários

Recebi um " fatal: bad flag '->' used after filename" ao tentar a git branchversão. O erro foi associado a uma HEADnotação de alias.

Eu o resolvi adicionando um sed '/->/d'no pipe, entre tros xargscomandos e.

 git branch -a | tr -d \* | sed '/->/d' | xargs git grep <regexp>

Isso é:

alias grep_all="git branch -a | tr -d \* | sed '/->/d' | xargs git grep"
grep_all <regexp>
VonC
fonte
Não é uma boa ideia canalizar a saída git branchpara tr ou sed; git branché um comando de porcelana destinado ao consumo humano. Consulte stackoverflow.com/a/3847586/2562319 para alternativas preferidas.
jbyler
@jbyler Bom ponto. Ironicamente, postei a resposta em porcelana muito antes desta resposta: stackoverflow.com/a/6978402/6309 . E eu o uso, por exemplo, em stackoverflow.com/a/19206916/6309 .
VonC
Sim, legal. Olhando através das outras respostas, acho que a resposta de @errordeveloper é a mais limpa: stackoverflow.com/a/21284342/2562319 : "git grep <regexp> $ (git para-cada-ref -format = '% (refname) 'refs /) "
jbyler
1
Existe alguma maneira de mostrar o nome do ramo que corresponde à pesquisa?
franksands
63

git log pode ser uma maneira mais eficaz de pesquisar texto em todos os ramos, especialmente se houver muitas correspondências, e você desejar ver alterações mais recentes (relevantes) primeiro.

git log -p --all -S 'search string'
git log -p --all -G 'match regular expression'

Esses comandos de log listam confirmações que adicionam ou removem a sequência de pesquisa / regex especificada, (geralmente) mais recentes primeiro. A -popção faz com que o diff relevante seja mostrado onde o padrão foi adicionado ou removido, para que você possa vê-lo em contexto.

Depois de encontrar um commit relevante que adiciona o texto que você estava procurando (por exemplo, 8beeff00d), encontre os ramos que contêm o commit:

git branch -a --contains 8beeff00d
Edward Anderson
fonte
22

Achei isso mais útil:

git grep -i foo `git for-each-ref --format='%(refname)' refs/`

Você precisaria ajustar os últimos argumentos, dependendo se deseja examinar apenas as ramificações remotas e locais, ou seja:

  • git grep -i foo $(git for-each-ref --format='%(refname)' refs/remotes)
  • git grep -i foo $(git for-each-ref --format='%(refname)' refs/heads)

O alias que eu criei tem a seguinte aparência:

grep-refs = !sh -c 'git grep "$0" "$@" "$(git for-each-ref --format=\"%(refname)\"" refs/)'
errordeveloper
fonte
1
Alias ​​interessante. +1. Mais preciso do que na minha resposta.
VonC
Como fazer com que seu alias funcione para a pesquisa de frases? Quando passo "foo bar" como parâmetro, recebo: fatal: argumento ambíguo 'bar': revisão desconhecida ou caminho que não está na árvore de trabalho. Uso '-' para caminhos separados de revisões
jutky
Tente escapar do espaço: "foo \ bar"
Garry Gomez
Essa deve ser claramente a resposta aceita;) Eu a expandi para pesquisar apenas nos ramos mais recentes do meu projeto (tenho mais de 500, não pergunte, e cada grep leva cerca de 4s para que eu não queira nem precise para pesquisar em mais do que, digamos, as 100 mais recentes). Por isso eu atualizei o git for-each-refcom --sort=-committerdate --count=100! Obrigado pela ideia original!
Vser 29/01
6

É possível fazer isso de duas maneiras comuns: aliases Bash ou Git

Aqui estão três comandos:

  1. git grep-branch - Pesquisa em todas as filiais locais e remotas
  2. git grep-branch-local - Pesquisar apenas em agências locais
  3. git grep-branch-remote - Apenas ramificações remotas

O uso é o mesmo que git grep

git grep-branch "find my text"
git grep-branch --some-grep-options "find my text"

GREP usando: aliases de Git

Arquivo ~ / .gitconfig

Os comandos devem ser adicionados manualmente ao ~/.gitconfigarquivo, porque git config --global aliasavalie o código complexo que você adiciona e estrague tudo.


[alias]
    grep-branch        = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' | xargs git grep $@; };f "
    grep-branch-remote = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' | grep '^remotes' | xargs git grep $@; };f"
    grep-branch-local  = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' -e '^remotes' | xargs git grep $@;  };f "

Nota: Quando você adiciona aliases e eles não são executados - verifique as barras invertidas, \eles podem exigir escape adicional \\em comparação aos comandos bash .

  • git branch -a - Exibir todos os ramos;
  • sed -e 's/[ \\*]*//'- Aparar espaços (de branch -a) e * (o nome do ramo ativo possui);
  • grep -v -e '\\->'- Ignore nomes complexos como remotes/origin/HEAD -> origin/master;
  • grep '^remotes' - Obtenha todas as filiais remotas;
  • grep -v -e '^remotes'- Obter filiais, exceto filiais remotas;

Exemplo git grep-branch-local -n getTastyCookies

-n Prefixe o número da linha às linhas correspondentes.

[user@pc project]$ git grep-branch-local -n getTastyCookies

dev:53:modules/factory/getters.php:function getTastyCookies($user);
master:50:modules/factory/getters.php:function getTastyCookies($user)

A estrutura atual é:

: - Separador

  1. Ramo: dev
  2. Número da linha: 53
  3. Caminho de arquivo: modules/factory/getters.php
  4. Linha correspondente: function getTastyCookies($user)

GREP usando: BASH

Como você deve saber: Os comandos Bash devem ser armazenados em .shscripts ou executados em um shell.

Apenas filiais locais

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' -e '^remotes' | xargs git grep "TEXT"

Apenas ramificações remotas

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' | grep '^remotes' | xargs git grep "TEXT"

Filiais locais e remotas

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' | xargs git grep "TEXT"
Devaldo
fonte
Parece bom, mas eu tenho esse erro git grep-branch "find my text":fatal: ambiguous argument 'client': both revision and filename
nealmcb
Por que sempre usar -a, que mostra todos os ramos? Eu sugeriria o uso de opções no git branchcomando para separar braches. Ao olhar para as filiais locais, há apenas uma *, portanto não há necessidade de escapar dela por sed. Assim: git branch | sed -e 's/*/ /' | xargs git grep "TEXT"somente para filiais locais, somente git branch -r | grep -v -- "->" | xargs git grep "TEXT"para filiais remotas e git branch -a | grep -v -- "->" | xargs git grep "TEXT"para todas as filiais
jalanb
4

Aqui está como eu faço:

git for-each-ref --format='%(*refname)' | xargs git grep SEARCHTERM
William Entriken
fonte
2
A única solução que funcionou para mim no Windows (em Git bash)
Ivan
4

Se você atribuir a qualquer commit um valor de hash SHA-1 git grep, ele deverá pesquisar neles, em vez da cópia de trabalho.

Para pesquisar todos os galhos, você pode obter todas as árvores com git rev-list --all. Coloque tudo com

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

... e tenha paciência

CharlesB
fonte