Como encontrar o commit do Git que introduziu uma string em qualquer ramificação?

396

Quero poder encontrar uma determinada string que foi introduzida em qualquer commit em qualquer branch, como posso fazer isso? Eu encontrei algo (que eu modifiquei para o Win32), mas git whatchangednão parece estar olhando para os diferentes ramos (ignore o pedaço py3k, é apenas uma correção de feed de linha msys / win)

git whatchanged -- <file> | \
grep "^commit " | \
python -c "exec(\"import sys,msvcrt,os\nmsvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)\nfor l in sys.stdin: print(l.split()[1])\")" | \
xargs -i% git show origin % -- <file>

Realmente não importa se sua solução é lenta.

Jonas Byström
fonte

Respostas:

685

Você pode fazer:

git log -S <whatever> --source --all

Para encontrar todas as confirmações que adicionaram ou removeram a sequência fixa whatever . O --allparâmetro significa iniciar de cada ramificação e --sourcemostrar quais dessas ramificações levaram a encontrar essa confirmação. Muitas vezes, é útil adicionar -ppara mostrar os patches que cada um desses commit introduziria também.

As versões do git desde 1.7.4 também têm uma -Gopção semelhante , que recebe uma expressão regular . Na verdade, isso tem semânticas diferentes (e um pouco mais óbvias), explicadas nesta postagem no blog de Junio ​​Hamano .

Como thameera aponta nos comentários, você precisa colocar aspas no termo de pesquisa se ele contiver espaços ou outros caracteres especiais, por exemplo:

git log -S 'hello world' --source --all
git log -S "dude, where's my car?" --source --all

Aqui está um exemplo usando -Gpara encontrar ocorrências de function foo() {:

git log -G "^(\s)*function foo[(][)](\s)*{$" --source --all
Mark Longair
fonte
19
+1 por excelência. Apontar para -S é uma coisa, explicar melhor. Além disso, eu gosto de usar --decorate para ver de que ramos as coisas vêm
sehe
7
@sehe: Obrigado pelo seu bom comentário. Acho que vale a pena notar que --decorateapenas adiciona o nome do ramo ao commit na ponta de cada ramo. Na prática, eu realmente não usar --sourceou --decorate, e em vez disso usar git branch -a --contains <commit-hash>para descobrir qual ramos conter a cometer estou interessado.
Mark Longair
3
add -p para ver o diff em linha, assim, FWIW
rogerdpack
11
@ MarkLongair não mostra as alterações feitas na mesclagem. Alguma sugestão para mostrar isso também?
Pahlevi Fikri Auliya
2
Para mim, isso só funciona se eu remover o espaço entre o -S e o termo de pesquisa, ou seja git log -S"dude, where's my car?" --source --all,. A @ribamar também escreveu isso em uma resposta abaixo, mas pode ser facilmente ignorada ao lado desta resposta principal.
bug313
69

--reverse também é útil, pois você deseja o primeiro commit que fez a alteração:

git log --all -p --reverse --source -S 'needle'

Dessa forma, as confirmações mais antigas aparecerão primeiro.

Ciro Santilli adicionou uma nova foto
fonte
20

A resposta de Mark Longair é excelente, mas achei que esta versão mais simples funcionou para mim.

git log -S whatever
Steven Penny
fonte
24
Apenas para esclarecer, isso funciona bem se o commit que você está procurando estiver HEAD, mas essa pergunta específica foi feita especificamente sobre a procura em todas as ramificações em um repositório.
precisa saber é o seguinte
18

Brincando com as mesmas respostas:

$ git config --global alias.find '!git log --color -p -S '
  • ! é necessário porque, de outra maneira, o git não passa o argumento corretamente para -S. Veja esta resposta
  • --color e -p ajuda a mostrar exatamente "o que mudou"

Agora você pode fazer

$ git find <whatever>

ou

$ git find <whatever> --all
$ git find <whatever> master develop
albfan
fonte
6
git log -S"string_to_search" # options like --source --reverse --all etc

Preste atenção para não usar espaços entre S e "string_to_search". Em algumas configurações (git 1.7.1), você receberá um erro como:

fatal: ambiguous argument 'string_to_search': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions
ribamar
fonte
2

Embora isso não responda diretamente à sua pergunta, acho que pode ser uma boa solução para você no futuro. Vi uma parte do meu código, que era ruim. Não sabia quem o escreveu ou quando. Pude ver todas as alterações do arquivo, mas ficou claro que o código havia sido movido de outro arquivo para este. Eu queria descobrir quem realmente o adicionou em primeiro lugar.

Para fazer isso, usei o Git bisect , que rapidamente me permitiu encontrar o pecador.

Eu corri git bisect starte depois git bisect bad, porque a revisão teve o problema. Como não sabia quando o problema ocorreu, direcionei o primeiro commit para o "bom" git bisect good <initial sha>,.

Então continuei pesquisando no repositório o código incorreto. Quando descobri isso, eu corri git bisect bad, e quando ela não estava lá: git bisect good.

Em ~ 11 etapas, eu havia coberto ~ 1000 confirmações e encontrei a confirmação exata, onde o problema foi introduzido. Muito bem.

Eldamir
fonte
2

Não sei por que a resposta aceita não funciona no meu ambiente; finalmente, corro o comando abaixo para obter o que preciso

git log --pretty=format:"%h - %an, %ar : %s"|grep "STRING"
BMW
fonte