Em um grande monorepo (diretório .git de 10 GB), observei o seguinte comportamento.
# When outputing to a file, it is very fast:
time git log -2 > /tmp/X
real 0m0.076s
user 0m0.007s
sys 0m0.046s
# When outputting to the tty, it is more than 10x slower:
time git log -2
# ... Output omitted
real 0m0.830s
user 0m0.078s
sys 0m0.586s
Aqui estão todas as minhas configurações relacionadas ao log:
$ git config -l | grep log
log.mailmap=true
core.logallrefupdates=true
O que causa a diferença no desempenho e como posso obter o mesmo desempenho quando o git log está gerando saída para um tty?
Mais observações:
Em um repositório menor,
git log -2
é rápido mesmo ao enviar para tty, então o problema parece estar correlacionado com um repositório grande.real 0m0.057s user 0m0.008s sys 0m0.022s
O Cat no arquivo de saída é rápido, então não é apenas a escrita no stdout que é lenta.
time cat /tmp/X real 0m0.015s user 0m0.001s sys 0m0.005s
Forçar um tty com
expect
'sunbuffer
também torna mais lentogit log
:time unbuffer git log -2 > /tmp/X real 0m1.007s user 0m0.104s sys 0m0.669s
Em comparação,
unbuffer
ele próprio tem uma sobrecarga de ~240 ms:time unbuffer cat /tmp/X real 0m0.239s user 0m0.033s sys 0m0.111s
Com base na excelente sugestão de @LeGEC e em algumas experiências adicionais, parece que a causa da diferença é a decoração.
Assim, temos os seguintes resultados:
Conforme escrito em sua resposta, acho que você identificou a causa da sua lentidão: um número muito alto de referências no seu repositório local fica lento
git log
quando ele tenta imprimir a decoração para cada commit.Verifique que tipo de referências compõem a maior parte delas. Você pode comparar os seguintes números:
Se você descobrir que tem uma quantidade enorme de ramificações remotas: tente executar
git fetch --prune
para se livrar de referências remotas (refs emrefs/remotes/origin/*
) que foram excluídas no upstream.Se os 3 números não somarem a quantidade total de linhas em
packed-refs
, verifique quais outras referências poderiam aumentar a contagem.packed-refs
: é apenas um arquivo de texto, uma linha por referência,git for-each-ref
, por exemplo:cut -d/ -f1-2
diz "use/
como um separador de campo, mantenha apenas os 2 primeiros campos", você pode restringir os números mais altos e obter mais detalhes aumentando o segundo número em-f1-x