Como pesquisar em todos os commits do Git e Mercurial no repositório para uma determinada string?

287

Eu tenho um repositório Git com poucos ramos e commits dangling. Eu gostaria de procurar todos os commits no repositório por uma string específica.

Eu sei como obter um log de todos os commits no histórico, mas eles não incluem ramificações ou blobs pendentes, apenas o histórico do HEAD. Eu quero pegar todos eles, encontrar um commit específico que tenha sido extraviado.

Eu também gostaria de saber como fazer isso no Mercurial, pois estou considerando a opção.

Josip
fonte

Respostas:

331

Você pode ver confirmações pendentes com git log -g.

-g, --walk-reflogs
 Instead of walking the commit ancestry chain, walk reflog entries from
 the most recent one to older ones. 

Portanto, você pode fazer isso para encontrar uma sequência específica em uma mensagem de confirmação que está pendente:

git log -g --grep=search_for_this

Como alternativa, se você deseja pesquisar as alterações para uma sequência específica, pode usar a opção de pesquisa de picareta "-S":

git log -g -Ssearch_for_this
# this also works but may be slower, it only shows text-added results
git grep search_for_this $(git log -g --pretty=format:%h)

O Git 1.7.4 adicionará a opção -G , permitindo que você passe -G <regexp> para descobrir quando uma linha que contém <regexp> foi movida, o que -S não pode fazer. -S informa apenas quando o número total de linhas que contêm a sequência foi alterado (ou seja, adicionando / removendo a sequência).

Por fim, você pode usar o gitk para visualizar os commits dangling com:

gitk --all $(git log -g --pretty=format:%h)

E, em seguida, use seus recursos de pesquisa para procurar o arquivo extraviado. Todo esse trabalho, assumindo que a confirmação ausente não "expirou" e foi coletado como lixo, o que pode ocorrer se ficar pendurado por 30 dias e você expirar os reflogs ou executar um comando que os expire.

richq
fonte
4
Talvez, em vez de executar "git grep" em um número (possivelmente grande) de confirmações, que encontrem todas as confirmações que tenham 'search_for_this' em algum lugar do projeto, use a chamada pesquisa "pickaxe", ou seja, a opção '-S' para git log , que encontra confirmações que introduziram ou removeram determinada sequência ou para ser mais exato onde o número de ocorrências de uma determinada sequência foi alterado.
21749 Jakub Narębski
5
Você pode especificar vários ramos, ou o uso opção '--all', por exemplo, 'git log --grep = "string em uma mensagem de commit" --all'
Jakub Narębski
Isso só me permitiu encontrar um commit perdido por 2 dias de trabalho. Totalmente salvou minha bunda, obrigado!
Mike Chamberlain
2
Eu me deparei com algumas situações em que eu tinha confirmações no meu banco de dados, mas não no meu reflog. Não sei como isso é comum. Eu estava experimentando diferentes pontes hg / git. Eu acho que também pode surgir com esconderijos caídos. De qualquer forma, esse alias funciona bem para capturar esses casos:!git fsck --unreachable | sed -ne 's/^unreachable commit //p' | xargs git log --no-walk
dubiousjim
Observe que isso não inclui a pesquisa de objetos de anotação. Isso ainda não foi implementado: git.661346.n2.nabble.com/…
Antony Stubbs
54

No Mercurial, você usa hg log --keywordpara procurar palavras-chave nas mensagens de confirmação e hg log --userprocurar um usuário específico. Veja hg help logoutras maneiras de limitar o log.

Martin Geisler
fonte
36
Josip escreveu que ele está pensando em mudar para o Mercurial e que ele também gostaria de ouvir como é feito lá.
Martin Geisler)
1
hg log -kas pesquisas também confirmam o nome de usuário e os arquivos nos conjuntos de alterações (vejo isso em commands.py:log), que é uma das poucas coisas que não entendo em hg. Deve haver opções separadas para procurar mensagens de confirmação e nomes de arquivos. Parece que hg log --template '{desc}\n'|grepé o caminho certo.
Geoffrey Zheng
@ GeoffreyZheng: existem maneiras de fazer isso. Consulte "hg help revsets", especialmente as funções desc (), user () e file (). Há também opções de log hg para a maior parte desse comportamento. Na minha experiência, embora -k / keyword () seja geralmente a maneira mais útil de procurar coisas.
Kevin Chifre
Como se pesquisa o conteúdo real do arquivo confirmado ... as diferenças? Eu sei que seria uma pesquisa lenta, mas quero fazer uma pesquisa profunda por um nome de função ausente.
Jonathan
Oh, aqui está ele:hg grep --all <term>
Jonathan
24

Além da resposta richq de usar git log -g --grep=<regexp>ou git grep -e <regexp> $(git log -g --pretty=format:%h): dê uma olhada nas seguintes postagens de blog de Junio ​​C Hamano, atual mantenedor do git


Resumo

O git grep e o git log --grep são orientados a linhas , pois procuram linhas que correspondam ao padrão especificado.

Você pode usar git log --grep=<foo> --grep=<bar>(ou git log --author=<foo> --grep=<bar>que se traduz internamente em dois --grep) para encontrar confirmações que correspondam a qualquer um dos padrões (implícito OU semântico).

Por ser orientado a linhas, a útil AND semântica é usada git log --all-match --grep=<foo> --grep=<bar>para encontrar o commit que possui a linha correspondente primeiro e a linha correspondente segundo em algum lugar.

Com git grepvocê pode combinar vários padrões (todos os que devem usar o -e <regexp>formulário) com --or(que é o padrão), --and, --not, (e ). Para grep --all-matchsignifica que o arquivo deve ter linhas que correspondam a cada uma das alternativas.

Jakub Narębski
fonte
Hey Jakub, mente integrando citações / resumos dessas postagens aqui? Parece uma das respostas apenas para links antigos no momento.
Nathan Tuggy
11

Com base na resposta da rq, descobri que esta linha faz o que eu quero:

git grep "search for something" $(git log -g --pretty=format:%h -S"search for something")

O qual reportará o ID de confirmação, o nome do arquivo e exibirá a linha correspondente, assim:

91ba969:testFile:this is a test

... Alguém concorda que essa seria uma boa opção para ser incluída no comando git grep padrão?

Sam Hiatt
fonte
5

Qualquer comando que aceite referências como argumentos aceitará a --allopção documentada na página de manual da git rev-listseguinte maneira:

   --all
       Pretend as if all the refs in $GIT_DIR/refs/ are listed on the
       command line as <commit>.

Por exemplo git log -Sstring --all, exibirá todos os commits mencionados stringe acessíveis a partir de uma ramificação ou de uma tag (presumo que seus commits pendentes sejam pelo menos nomeados com uma tag).

adl
fonte
3
Não parece ser esse o caso git grep, onde --allparece ser traduzido para / usado como --all-match. Isso me parece um bug .. usando o Git 1.7.2.3 (usando o $(git rev-list --all)works).
blueyed 02/02
5

Com o Mercurial, você faz um

$ hg grep "search for this" [file...]

Existem outras opções que restringem o intervalo de revisões pesquisadas.

Yawar
fonte
1
Eu também gosto da bandeirahg grep --all
Jonathan
2

Não sei sobre o git, mas no Mercurial, eu apenas canalizava a saída do hg log para algum script sed / perl / any para procurar o que você estava procurando. Você pode personalizar a saída do hg log usando um modelo ou um estilo para facilitar a pesquisa, se desejar.

Isso incluirá todas as ramificações nomeadas no repositório. O Mercurial não tem algo parecido com bolhas pendentes.

Kurt Schelfthout
fonte
1
Não entendo como essa resposta é relevante para o problema especificado.
jribeiro
3
É uma resposta para a pergunta do Mercurial, que a pergunta original faz no último parágrafo.
Kurt Schelfthout
1

Para adicionar apenas mais uma solução ainda não mencionada, devo dizer que o uso da caixa de pesquisa gráfica do gitg foi a solução mais simples para mim. Ele selecionará a primeira ocorrência e você poderá encontrar a próxima com Ctrl-G.

icarito
fonte
1

Um comando no git que acho muito mais fácil encontrar uma string:

git log --pretty=oneline --grep "string to search"

trabalha no Git 2.0.4

Adriano Rosa
fonte