git-import nativa fornecida com o ClickHouse.
Os dados gerados incluem um arquivo tsv para cada uma das seguintes tabelas:
commits- commits com estatísticas.file_changes- arquivos alterados em cada commit, com informações sobre a alteração e estatísticas.line_changes- cada linha alterada em cada arquivo alterado em cada commit, com informações completas sobre a linha e sobre a alteração anterior dessa linha.
commits- 7.8M - 266,051 linhasfile_changes- 53M - 266,051 linhasline_changes- 2.7G - 7,535,157 linhas
Gerando os dados
- Linux -
~/clickhouse git-import- 160 min
Baixando e inserindo os dados
- ClickHouse (8 de nov. de 2022)
- https://datasets-documentation.s3.amazonaws.com/github/commits/clickhouse/commits.tsv.xz - 2.5 MB
- https://datasets-documentation.s3.amazonaws.com/github/commits/clickhouse/file_changes.tsv.xz - 4.5MB
- https://datasets-documentation.s3.amazonaws.com/github/commits/clickhouse/line_changes.tsv.xz - 127.4 MB
- Linux (8 de nov. de 2022)
INSERT INTO SELECT e a função s3. Por exemplo, a seguir, inserimos os arquivos do ClickHouse em suas respectivas tabelas:
commits
Consultas
git_clickhouse. Fornecemos um link para esse ambiente em todas as consultas, adaptando o nome do banco de dados conforme necessário. Observe que os resultados no play podem variar em relação aos apresentados aqui devido a diferenças no momento da coleta dos dados.
Histórico de um único arquivo
StorageReplicatedMergeTree.cpp. Como essas mensagens provavelmente são mais interessantes, ordenamos da mais recente para a mais antiga.
play
Encontre os arquivos ativos atuais
dbms, libs, tests/testflows/ durante suas renomeações. Portanto, também os excluímos.
play
old_path para obter uma lista dos arquivos excluídos como resultado da renomeação. Em seguida, unimos isso à última operação de cada path. Por fim, filtramos essa lista para manter apenas os casos em que o evento final não é um Delete.
play
--skip-paths 'generated\.cpp|^(contrib|docs?|website|libs/(libcityhash|liblz4|libdivide|libvectorclass|libdouble-conversion|libcpuid|libzstd|libfarmhash|libmetrohash|libpoco|libwidechar_width))/'
Ao aplicar esse padrão a git list-files, são reportados 18155.
- Uma renomeação pode ocorrer junto com outras modificações no arquivo. Elas são listadas como eventos separados em file_changes, mas com o mesmo horário. A função
argMaxnão tem como distinguir isso — ela escolhe o primeiro valor. A ordenação natural das inserções (a única forma de saber a ordem correta) não é preservada na união, então eventos de modificação podem acabar sendo selecionados. Por exemplo, abaixo, o arquivosrc/Functions/geometryFromColumn.hpassa por várias modificações antes de ser renomeado parasrc/Functions/geometryConverters.h. Nossa solução atual pode selecionar um evento Modify como a alteração mais recente, fazendo com quesrc/Functions/geometryFromColumn.hseja mantido.
- Histórico de commits inconsistente - eventos de exclusão ausentes. Origem e causa ainda a definir.
Listar os arquivos com mais modificações
Em que dia da semana os commits costumam ocorrer?
Histórico de subdiretório/arquivo — número de linhas, commits e colaboradores ao longo do tempo
toStartOfWeek — adapte conforme necessário.
play
Linhas de código mais antigas do repositório
Arquivos com o histórico mais longo
Distribuição de colaboradores entre documentação e código ao longo do mês
docs/ foram filtradas devido a um histórico de commits muito desorganizado. Portanto, os resultados desta consulta não são exatos.
Escrevemos mais documentação em determinados períodos do mês, por exemplo, perto das datas de lançamento? Podemos usar a função countIf para calcular uma proporção simples e visualizar o resultado com a função bar.
play
bar nos ajudam a visualizar essas distribuições:
play
sign = -1 indica uma exclusão de código. Excluímos a pontuação e a inserção de linhas vazias.
play
LIMIT BY para 3, para obter os 3 principais responsáveis pela remoção de código de cada autor e dar mais variedade à visualização.
Alexey claramente gosta de remover código de outras pessoas. Vamos excluí-lo para ter uma visão mais equilibrada da remoção de código.
Quem tem a maior porcentagem de contribuição por dia da semana?
Distribuição da idade do código em todo o repositório
Listar os arquivos que foram reescritos mais vezes?
path e commit_hash, retornando o número de linhas adicionadas e removidas. Usando uma função de janela, estimamos o tamanho total do arquivo em qualquer ponto no tempo fazendo uma soma cumulativa e estimando o impacto de cada alteração no tamanho do arquivo como lines added - lines removed. Com essa estatística, podemos calcular a porcentagem do arquivo que foi adicionada ou removida em cada alteração. Por fim, contamos o número de alterações de arquivo que constituem um rewrite por arquivo, ou seja, (percent_add >= 0.5) AND (percent_delete >= 0.5) AND current_size > 50. Observe que exigimos que os arquivos tenham mais de 50 linhas para evitar que contribuições iniciais em um arquivo sejam contadas como um rewrite. Isso também evita um viés em relação a arquivos muito pequenos, que podem ter maior probabilidade de serem reescritos.
executar
Em que dia da semana o código tem mais chances de permanecer no repositório?
Arquivos ordenados por idade média do código
Quem tende a escrever mais testes / código em CPP / comentários?
tests e calcular a proporção em relação ao total de contribuições.
Aqui, limitamos a consulta a usuários com mais de 20 alterações para focar em contribuidores regulares e evitar viés de contribuições pontuais.
play
Qual é o tempo médio até que o código seja reescrito e a mediana (meia-vida da degradação do código)?
Qual é o pior momento para escrever código, no sentido de que ele tem a maior chance de ser reescrito?
consecutive_day.
Em seguida, as funções de array calculam a maior sequência de 1s consecutivos de cada autor. Primeiro, a função groupArray é usada para reunir todos os valores de consecutive_day de um autor. Esse array de 1s e 0s é então dividido nos valores 0 em subarrays. Por fim, calculamos o subarray mais longo.
play
Histórico de commits de um arquivo, linha por linha
path recebe o novo caminho do arquivo, e old_path representa o caminho anterior, por exemplo.
play
file_path_history('src/Storages/StorageReplicatedMergeTree.cpp'), percorremos recursivamente o histórico de renomeações, com cada função chamando o nível seguinte com old_path. Os resultados são combinados usando arrayConcat.
Por exemplo,
path.
Questões em aberto
Git blame
arrayFold ou arrayReduce, que permitem manter o estado a cada iteração.
Uma solução aproximada, suficiente para uma análise de alto nível, pode ser algo assim: