Dado o hash de um blob, existe uma maneira de obter uma lista de confirmações que possuem esse blob em sua árvore?
git
version-control
Somente leitura
fonte
fonte
git hash-object
orsha1("blob " + filesize + "\0" + data)
, e não simplesmente o sha1sum do conteúdo do blob.git log --follow filepath
(e usar isso para acelerar a solução de Aristóteles, se desejar).~/.bin
e nomeie-ogit-find-object
. Você pode usá-lo comgit find-object
.git describe <hash>
: Veja minha resposta abaixo .Respostas:
Os dois scripts a seguir tomam o SHA1 do blob como o primeiro argumento e, depois dele, opcionalmente, quaisquer argumentos que
git log
entenderão. Por exemplo,--all
para pesquisar em todos os ramos, em vez de apenas no atual, ou-g
no reflog, ou qualquer outra coisa que você queira.Aqui está como um script de shell - curto e doce, mas lento:
E uma versão otimizada no Perl, ainda bastante curta, mas muito mais rápida:
fonte
git rev-parse --verify $theprefix
my $blob_arg = shift; open my $rev_parse, '-|', git => 'rev-parse' => '--verify', $blob_arg or die "Couldn't open pipe to git-rev-parse: $!\n"; my $obj_name = <$rev_parse>; chomp $obj_name; close $rev_parse or die "Couldn't expand passed blob.\n"; $obj_name eq $blob_arg or print "(full blob is $obj_name)\n";
obj_name="$1" shift git log --all --pretty=format:'%T %h %s %n' -- "$@" | while read tree commit cdate subject ; do if [ -z $tree ] ; then continue fi if git ls-tree -r $tree | grep -q "$obj_name" ; then echo "$cdate $commit $@ $subject" fi done
--all
como um argumento adicional. (Encontrar todas as confirmações em todo o repo é importante em casos como excluir um arquivo grande do histórico do repo ).Infelizmente, os scripts foram um pouco lentos para mim, então tive que otimizar um pouco. Felizmente, eu tinha não apenas o hash, mas também o caminho de um arquivo.
fonte
<hash>
dado<path>
, remover o<path>
argumento dogit log
irá funcionar. O primeiro resultado retornado é o commit desejado.Com o Git 2.16 (primeiro trimestre de 2018),
git describe
seria uma boa solução, pois foi ensinado a cavar árvores mais profundamente para encontrar um<commit-ish>:<path>
que se refira a um determinado objeto de blob.Consulte commit 644eb60 , commit 4dbc59a , commit cdaed0c , commit c87b653 , commit ce5b6f9 (16 de novembro de 2017) e commit 91904f5 , commit 2deda00 (02 de novembro de 2017) por Stefan Beller (
stefanbeller
) .(Mesclado por Junio C Hamano -
gitster
- na commit 556de1a , 28 de dezembro de 2017)Isso significa que a
git describe
página de manual é adicionada aos propósitos deste comando:Mas:
fonte
git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | awk '/^blob/ {print substr($0,6)}' | sort --numeric-sort --key=2 -r | head -n 20
, o que gera um dos 20 maiores blobs. Em seguida, você pode passar o ID do blob da saída acima paragit describe
. Trabalhou como um encanto! Obrigado!Eu pensei que isso seria uma coisa geralmente útil, então eu escrevi um pequeno script perl para fazer isso:
Vou colocar isso no github quando chegar em casa hoje à noite.
Atualização: Parece que alguém já fez isso . Essa usa a mesma ideia geral, mas os detalhes são diferentes e a implementação é muito mais curta. Não sei o que seria mais rápido, mas o desempenho provavelmente não é uma preocupação aqui!
Atualização 2: Para o que vale a pena, minha implementação é de ordens de magnitude mais rápidas, especialmente para um grande repositório. Isso
git ls-tree -r
realmente dói.Atualização 3: devo observar que meus comentários de desempenho acima se aplicam à implementação que eu vinculei acima na primeira atualização. A implementação de Aristóteles tem um desempenho comparável ao meu. Mais detalhes nos comentários para quem está curioso.
fonte
git rev-parse $commit^{}
Embora a pergunta original não peça, acho útil verificar também a área de preparação para ver se um blob é referenciado. Modifiquei o script bash original para fazer isso e encontrei o que estava fazendo referência a um blob corrompido no meu repositório:
fonte
Então ... eu precisava encontrar todos os arquivos acima de um determinado limite em um repositório com mais de 8 GB de tamanho, com mais de 108.000 revisões. Adaptei o script perl de Aristóteles junto com um script rubi que escrevi para alcançar essa solução completa.
Primeiro,
git gc
- faça isso para garantir que todos os objetos estejam em arquivos de pacote - não examinamos objetos que não estão em arquivos de pacote.Próximo Execute este script para localizar todos os blobs sobre os bytes CUTOFF_SIZE. Capture a saída para um arquivo como "large-blobs.log"
Em seguida, edite o arquivo para remover todos os blobs que você não espera e os bits INPUT_THREAD na parte superior. Depois de ter apenas linhas para os sha1s que deseja encontrar, execute o seguinte script como este:
Onde o
git-find-blob
script está abaixo.A saída será assim:
E assim por diante. Todo commit que contém um arquivo grande em sua árvore será listado. se você
grep
definir as linhas que começam com uma guia euniq
, terá uma lista de todos os caminhos que você pode filtrar para remover ou se pode fazer algo mais complicado.Permitam-me reiterar: esse processo foi executado com êxito, em um repo de 10 GB com 108.000 confirmações. Demorou muito mais tempo do que eu previa ao executar um grande número de blobs, porém, em 10 horas, terei que ver se o bit de memorização está funcionando ...
fonte
-- --all
. (Encontrar todas as confirmações em todo o repo é importante em casos como excluir completamente um arquivo grande do histórico do repo ).Além de
git describe
que eu menciono na minha resposta anterior ,git log
egit diff
agora beneficia assim do "--find-object=<object-id>
" opção para limitar os resultados a mudanças que envolvem o objeto nomeado.Isso está no Git 2.16.x / 2.17 (primeiro trimestre de 2018)
Consulte commit 4d8c51a , commit 5e50525 , commit 15af58c , commit cf63051 , commit c1ddc46 , commit 929ed70 (04 jan 2018) por Stefan Beller (
stefanbeller
) .(Incorporado por Junio C Hamano -
gitster
- in commit c0d75f0 , 23 de janeiro de 2018)fonte