Como posso pesquisar nas ramificações do Git um arquivo ou diretório?

323

No Git, como eu poderia procurar um arquivo ou diretório por caminho em vários ramos?

Escrevi algo em um ramo, mas não me lembro qual deles. Agora eu preciso encontrá-lo.

Esclarecimento : Estou procurando um arquivo que criei em um dos meus ramos. Gostaria de encontrá-lo pelo caminho, e não pelo seu conteúdo, pois não me lembro qual é o conteúdo.

Peeja
fonte
Não estou claro sobre a questão. Este arquivo estava em uma ramificação que foi excluída agora? O arquivo foi excluído?
Abizern

Respostas:

444

git log+ git branchencontrará para você:

% git log --all -- somefile

commit 55d2069a092e07c56a6b4d321509ba7620664c63
Author: Dustin Sallings <[email protected]>
Date:   Tue Dec 16 14:16:22 2008 -0800

    added somefile


% git branch -a --contains 55d2069
  otherbranch

Também suporta globbing:

% git log --all -- '**/my_file.png'

As aspas simples são necessárias (pelo menos se estiver usando o shell Bash) para que o shell passe o padrão glob para o git inalterado, em vez de expandi-lo (como no Unix find).

Dustin
fonte
2
Isso funciona se você souber o caminho exato para somefile: se precisar de pesquisa regex sobre o caminho / nome do arquivo, por exemplo, poderá usar a resposta do ididak.
ShreevatsaR
70
Também suporta globbing:git log --all -- **/my_file.png
webmat
3
Eu usei isso para um problema um pouco diferente. Eu estava tentando encontrar todos os arquivos * .sql que eu havia confirmado em uma ramificação específica. Então eu usei git log --grep='branch' --author='me' -- *.sql. Funcionou como um encanto. git versão 1.7.11.1
thepriebe 17/09/12
1
Observe que também gitksuporta o globbing. Essa é uma excelente resposta @webmat! Se você quiser ver onde foi excluído / criado / etc, pode usar git log --all --stat -- **/my_file.png, dessa forma, não precisará adivinhar se está fazendo o check-out de um commit que o excluiu.
precisa saber é o seguinte
1
@ webmat: Tomei a liberdade de adicionar suas informações sobre globbing à resposta. Obrigado por mencionar!
sleske
65

git ls-tree pode ajudar. Para pesquisar em todas as ramificações existentes:

for branch in `git for-each-ref --format="%(refname)" refs/heads`; do
  echo $branch :; git ls-tree -r --name-only $branch | grep '<foo>'
done

A vantagem disso é que você também pode procurar com expressões regulares o nome do arquivo.

ididak
fonte
3
Alguns comentários esperançosamente úteis: (a) Você provavelmente deseja adicionar "-r" ao "git ls-tree" para encontrar o arquivo, mesmo que esteja em um subdiretório. (b) Uma alternativa talvez mais limpa à primeira linha seria usar "git para cada ref", por exemplo, "para ramificação em git for-each-ref --format="%(refname)" refs/heads; do" (c) "git ls-tree - name-only" tornará a saída mais organizada (d) pode valer a pena ressaltar em sua resposta que há uma vantagem disso sobre a solução de Dustin, a saber, que você não precisa saber exatamente o nome do arquivo - é possível pesquisar por expressão regular que corresponde a qualquer parte do caminho
Mark Longair
9
Eu envolvi isso em um script para que você possa executar "gitfind.sh <regex>"; O Gist é gist.github.com/62d981890eccb48a99dc
Handyman5
3
Observe que isso pesquisará apenas nas filiais locais . Para pesquisar ramificações de rastreamento remoto, use em refs/remotesvez de refs/heads. Para pesquisar tudo (ramificações locais, ramificações de rastreamento remoto e tags), basta usar refs/.
sleske
19

Embora a resposta do ididak seja bem legal, e o Handyman5 forneça um script para usá-lo, achei um pouco restrito o uso dessa abordagem.

Às vezes, você precisa procurar algo que possa aparecer / desaparecer ao longo do tempo; então, por que não procurar todos os commits? Além disso, às vezes você precisa de uma resposta detalhada e outras vezes apenas confirma as correspondências. Aqui estão duas versões dessas opções. Coloque estes scripts no seu caminho:

git-find-file

for branch in $(git rev-list --all)
do
  if (git ls-tree -r --name-only $branch | grep --quiet "$1")
  then
     echo $branch
  fi
done

git-find-file-verbose

for branch in $(git rev-list --all)
do
  git ls-tree -r --name-only $branch | grep "$1" | sed 's/^/'$branch': /'
done

Agora você pode fazer

$ git find-file <regex>
sha1
sha2

$ git find-file-verbose <regex>
sha1: path/to/<regex>/searched
sha1: path/to/another/<regex>/in/same/sha
sha2: path/to/other/<regex>/in/other/sha

Veja que, usando getopt, você pode modificar esse script para pesquisar alternadamente todos os commits, refs, refs / heads, verbos etc.

$ git find-file <regex>
$ git find-file --verbose <regex>
$ git find-file --verbose --decorated --color <regex>

Confira https://github.com/albfan/git-find-file para uma possível implementação.

albfan
fonte
Você quis dizer "Agora você pode fazer o git-find-file <regex>"? Eu consegui, obrigado!
Elias Lynn
1
Pessoalmente, acho muito mais útil usar $ (git branch | cut -c 3-) em vez de $ (git rev-list --all). Eu não me importo em encontrar um monte de commits, me preocupo com ramos nomeados.
Campadrenalin
Também mudei os scripts para usar $ (git branch | cut -c 3-), pois o loop sobre todas as confirmações era muito lento.
i4h 26/10/2015
Visto todo o barulho que eu acho que vale a pena criar um repositório para isso. github.com/albfan/git-find-file . Abri alguns problemas, sinta-se à vontade para propor mais ou enviar RP para ele.
Albfan #
1
@lumbric instalar script no caminho funciona fora da caixa, é uma característica git
albfan
10

Você pode usar gitk --alle procurar confirmações "comoventes" e o nome do caminho em que está interessado.

Greg Hewgill
fonte
3
Conforme declarado, use gitk --all e, em seguida, em Exibir | Nova exibição, habilite Todas as ramificações. Em seguida, defina seus critérios de pesquisa: nomes de arquivos (com caracteres curinga) no penúltimo campo. Finalmente: OK.
MikeW
8

Copie e cole para usar git find-file SEARCHPATTERN

Imprimir todas as ramificações pesquisadas:

git config --global alias.find-file '!for branch in `git for-each-ref --format="%(refname)" refs/heads`; do echo "${branch}:"; git ls-tree -r --name-only $branch | nl -bn -w3 | grep "$1"; done; :'

Imprimir apenas ramificações com resultados:

git config --global alias.find-file '!for branch in $(git for-each-ref --format="%(refname)" refs/heads); do if git ls-tree -r --name-only $branch | grep "$1" > /dev/null; then  echo "${branch}:"; git ls-tree -r --name-only $branch | nl -bn -w3 | grep "$1"; fi; done; :'

Esses comandos adicionarão alguns scripts shell mínimos diretamente ao seu alias~/.gitconfig como git global .

lumbric
fonte
está pesquisando apenas no ramo mestre
Nasif Imtiaz Ohi
Ele pesquisa em todas as filiais locais
Leonardo Herrera
-1

Uma implementação bastante decente do findcomando para repositórios Git pode ser encontrada aqui:

https://github.com/mirabilos/git-find

Dominik George
fonte