Saltar al contenido principal
Este conjunto de datos contiene todos los commits y cambios del repositorio de ClickHouse. Puede generarse con la herramienta nativa git-import incluida con ClickHouse. Los datos generados incluyen un archivo tsv para cada una de las siguientes tablas:
  • commits - commits con estadísticas.
  • file_changes - archivos modificados en cada commit, con información sobre el cambio y estadísticas.
  • line_changes - cada línea modificada en cada archivo modificado de cada commit, con información completa sobre la línea y sobre el cambio anterior de esa línea.
A fecha de 8 de noviembre de 2022, cada TSV tiene aproximadamente el siguiente tamaño y número de filas:
  • commits - 7.8M - 266,051 filas
  • file_changes - 53M - 266,051 filas
  • line_changes - 2.7G - 7,535,157 filas

Generación de datos

Esto es opcional. Ofrecemos los datos de forma gratuita; consulta Descarga e inserción de los datos.
Este proceso tardará unos 3 minutos en completarse (a fecha del 8 de noviembre de 2022, en un MacBook Pro 2021) para el repositorio de ClickHouse. La lista completa de opciones disponibles puede consultarse en la ayuda integrada de la herramienta.
Esta ayuda también incluye el DDL de cada una de las tablas anteriores, p. ej.
Estas consultas deberían funcionar en cualquier repositorio. No dudes en explorar y compartir tus hallazgos. Algunas indicaciones sobre los tiempos de ejecución (a noviembre de 2022):
  • Linux - ~/clickhouse git-import - 160 min

Descarga e inserción de datos

Los siguientes datos pueden utilizarse para reproducir un entorno de trabajo funcional. Como alternativa, este conjunto de datos está disponible en play.clickhouse.com; consulta Queries para obtener más información. A continuación se muestran los archivos generados para los siguientes repositorios: Para insertar estos datos, prepara la base de datos ejecutando las siguientes consultas:
Inserta los datos mediante INSERT INTO SELECT y la función s3. Por ejemplo, a continuación insertamos los archivos de ClickHouse en sus respectivas tablas: commits
file_changes
line_changes

Consultas

La herramienta sugiere varias consultas en su salida de ayuda. Hemos respondido a estas, además de incluir algunas preguntas complementarias de interés. Estas consultas están ordenadas, de forma aproximada, por complejidad creciente, en lugar de seguir el orden arbitrario de la herramienta. Este conjunto de datos está disponible en play.clickhouse.com en las bases de datos git_clickhouse. Proporcionamos un enlace a este entorno para todas las consultas, adaptando el nombre de la base de datos según sea necesario. Ten en cuenta que los resultados en play pueden variar con respecto a los que se presentan aquí debido a diferencias en el momento de la recopilación de los datos.

Historial de un solo archivo

La más sencilla de las consultas. Aquí vemos todos los mensajes de commit de StorageReplicatedMergeTree.cpp. Como probablemente sean los más interesantes, los ordenamos empezando por los más recientes. play
También podemos revisar los cambios por línea, sin contar los cambios de nombre; es decir, no mostraremos los cambios anteriores a un cambio de nombre cuando el archivo existía con otro nombre: play
Ten en cuenta que existe una variante más compleja de esta consulta en la que se obtiene el historial de commits línea por línea de un archivo, teniendo en cuenta los cambios de nombre.

Encontrar los archivos activos actuales

Esto es importante para el análisis posterior, cuando solo queremos tener en cuenta los archivos actuales del repositorio. Estimamos que este conjunto está formado por los archivos que no se han renombrado ni eliminado (y luego vuelto a añadir o renombrar). Ten en cuenta que parece haber habido una interrupción en el historial de commits relacionada con los archivos de los directorios dbms, libs y tests/testflows/ durante sus cambios de nombre. Por ello, también los excluimos. play
Ten en cuenta que esto permite renombrar archivos y luego volver a ponerles sus nombres originales. Primero, agregamos old_path para obtener una lista de los archivos eliminados como resultado del cambio de nombre. Luego, combinamos esto con la última operación de cada path. Por último, filtramos esta lista para quedarnos con aquellos en los que el evento final no es un Delete. play
Ten en cuenta que omitimos la importación de varios directorios durante este proceso, es decir: --skip-paths 'generated\.cpp|^(contrib|docs?|website|libs/(libcityhash|liblz4|libdivide|libvectorclass|libdouble-conversion|libcpuid|libzstd|libfarmhash|libmetrohash|libpoco|libwidechar_width))/' Al aplicar este patrón a git list-files, el resultado es 18155.
Por lo tanto, nuestra solución actual es una estimación de los archivos activos actuales La diferencia aquí se debe a varios factores:
  • Un cambio de nombre puede producirse junto con otras modificaciones del archivo. Estas se registran como eventos independientes en file_changes, pero con la misma hora. La función argMax no tiene forma de distinguirlos: elige el primer valor. El orden natural de las inserciones (el único medio para conocer el orden correcto) no se conserva en la unión, por lo que pueden seleccionarse eventos de modificación. Por ejemplo, a continuación, el archivo src/Functions/geometryFromColumn.h tiene varias modificaciones antes de renombrarse a src/Functions/geometryConverters.h. Nuestra solución actual puede elegir un evento Modify como el cambio más reciente, lo que hace que se conserve src/Functions/geometryFromColumn.h.
play
  • Historial de commits incompleto: faltan eventos de eliminación. El origen y la causa aún están por determinar.
Estas diferencias no deberían afectar de forma significativa a nuestro análisis. Se agradecen versiones mejoradas de esta consulta.

Lista de archivos con más modificaciones

Si nos limitamos a los archivos actuales, consideramos que el número de modificaciones es la suma de eliminaciones y adiciones. play

¿Qué día de la semana suelen realizarse los commits?

play
Esto cuadra con cierta bajada de productividad los viernes. ¡Qué bien ver a gente haciendo commits de código los fines de semana! ¡Muchas gracias a nuestros colaboradores!

Historial del subdirectorio/archivo: número de líneas, commits y colaboradores a lo largo del tiempo

Esto produciría un resultado de consulta muy grande, poco práctico de mostrar o visualizar sin filtrar. Por ello, en el siguiente ejemplo permitimos filtrar por archivo o subdirectorio. Aquí agrupamos por semana mediante la función toStartOfWeek; adáptela según sea necesario. play
Estos datos se prestan bien a la visualización. A continuación, usamos Superset. Para líneas añadidas y eliminadas: Para commits y autores:

Listar archivos con el mayor número de autores

Solo incluir los archivos actuales. probar

Las líneas de código más antiguas del repositorio

Solo se incluyen los archivos actuales. probar

Archivos con el historial más extenso

Se limita solo a los archivos actuales. probar
Nuestra principal estructura de datos, el Merge Tree, está obviamente en constante evolución y cuenta con un largo historial de cambios.

Distribución de colaboradores entre documentación y código a lo largo del mes

Durante la captura de datos, se han filtrado los cambios en la carpeta docs/ debido a un historial de commits muy desordenado. Por lo tanto, los resultados de esta consulta no son precisos. ¿Escribimos más documentación en determinados momentos del mes, por ejemplo, en torno a las fechas de lanzamiento? Podemos usar la función countIf para calcular una proporción simple y visualizar el resultado con la función bar. probar
Quizá un poco más hacia el final del mes, pero en general mantenemos una distribución bastante uniforme. De nuevo, esto no es fiable debido al filtrado aplicado por el filtro de docs durante la inserción de datos.

Autores con el impacto más variado

Aquí, consideramos la diversidad como la cantidad de archivos únicos en los que ha contribuido un autor. probar
Veamos quién tiene los commits más variados en su trabajo reciente. En lugar de limitarlo por fecha, lo restringiremos a los últimos N commits de un autor (en este caso, hemos usado 3, pero puedes cambiarlo si quieres): play

Archivos favoritos de un autor

Aquí tomamos a nuestro fundador Alexey Milovidov y limitamos el análisis a los archivos actuales. probar
Esto tiene sentido porque Alexey ha sido responsable de mantener el Change log. Pero ¿qué pasa si usamos el nombre base del archivo para identificar sus archivos más populares? Esto permite contemplar los cambios de nombre y debería centrarse en las contribuciones de código. probar
Esto quizá refleje más sus áreas de interés.

Archivos más grandes con el menor número de autores

Para ello, primero tenemos que identificar los archivos más grandes. Estimar esto reconstruyendo por completo cada archivo a partir del historial de commits sería muy costoso. Como estimación, y suponiendo que nos limitamos a los archivos actuales, sumamos las líneas añadidas y restamos las eliminadas. Después, podemos calcular una proporción entre la longitud y el número de autores. play
Los diccionarios de texto quizá no sean muy realistas, así que limitémonos solo al código mediante un filtro por extensión de archivo. play
Hay cierto sesgo hacia lo reciente en esto: los archivos más nuevos han tenido menos oportunidades de acumular commits. ¿Qué pasa si nos limitamos a archivos con al menos 1 año de antigüedad? probar

Distribución de commits y líneas de código en el tiempo; por día de la semana, por autor; para subdirectorios específicos

Interpretamos esto como el número de líneas añadidas y eliminadas según el día de la semana. En este caso, nos centramos en el directorio Functions probar
Y por hora del día, probar
Esta distribución tiene sentido, ya que la mayor parte de nuestro equipo de desarrollo está en Ámsterdam. Las funciones bar nos ayudan a visualizar estas distribuciones: probar

Matriz de autores que muestra qué autores tienden a reescribir el código de otros autores

El sign = -1 indica una eliminación de código. Excluimos la puntuación y la inserción de líneas vacías. play
Un diagrama de Sankey (SuperSet) permite visualizar esto claramente. Observa que aumentamos nuestro LIMIT BY a 3 para obtener los 3 autores que más código eliminan de cada autor y así mejorar la variedad de la visualización. Está claro que a Alexey le gusta eliminar el código de otras personas. Excluyámoslo para obtener una visión más equilibrada de la eliminación de código.

¿Quién aporta el mayor porcentaje por día de la semana?

Si consideramos solo el número de commits: play
Bien, aquí el colaborador con más trayectoria —nuestro fundador, Alexey— podría tener cierta ventaja. Limitemos el análisis al último año. play
Esto sigue siendo un poco simplista y no refleja el trabajo real de las personas. Una mejor métrica podría ser quién fue el principal contribuyente cada día, como fracción del trabajo total realizado durante el último año. Ten en cuenta que tratamos por igual la eliminación y la adición de código. play

Distribución de la antigüedad del código en el repositorio

Limitamos el análisis a los archivos actuales. Por brevedad, restringimos los resultados a una profundidad de 2, con 5 archivos por carpeta raíz. Ajústelo según sea necesario. play

¿Qué porcentaje del código de un autor han eliminado otros autores?

Para esta consulta, necesitamos el número de líneas escritas por un autor dividido entre el número total de líneas que otros colaboradores le han eliminado. play

¿Qué archivos se reescribieron más veces?

El enfoque más sencillo para responder a esta pregunta podría ser simplemente contar el número de modificaciones de líneas por ruta (limitándose a los archivos actuales), por ejemplo:
Esto no refleja, sin embargo, la idea de una “reescritura”, en la que una gran parte del archivo cambia en un commit. Esto requiere una consulta más compleja. Si consideramos que una reescritura se produce cuando se elimina más del 50 % del archivo y se añade otro 50 %, puedes ajustar la consulta según tu propia interpretación de lo que constituye una reescritura. La consulta se limita únicamente a los archivos actuales. Enumeramos todos los cambios de archivos agrupando por path y commit_hash, y devolvemos el número de líneas añadidas y eliminadas. Mediante una función de ventana, estimamos el tamaño total del archivo en cada momento realizando una suma acumulada y calculando el impacto de cada cambio en el tamaño del archivo como lines added - lines removed. A partir de esta métrica, podemos calcular el porcentaje del archivo que se ha añadido o eliminado en cada cambio. Por último, contamos el número de cambios de archivo que constituyen una reescritura por archivo, es decir, (percent_add >= 0.5) AND (percent_delete >= 0.5) AND current_size > 50. Ten en cuenta que exigimos que los archivos tengan más de 50 líneas para evitar que las contribuciones iniciales a un archivo se contabilicen como una reescritura. Esto también evita un sesgo hacia archivos muy pequeños, que pueden ser más propensos a reescribirse. play

¿Qué día de la semana tiene el código más probabilidades de permanecer en el repositorio?

Para ello, necesitamos identificar de forma única una línea de código. Lo estimamos así (ya que la misma línea puede aparecer varias veces en un archivo) usando la ruta y el contenido de la línea. Consultamos las líneas añadidas, uniéndolas con las líneas eliminadas y filtrando los casos en los que estas últimas ocurren más recientemente que las primeras. Esto nos da las líneas eliminadas, a partir de las cuales podemos calcular el tiempo entre estos dos eventos. Por último, agregamos este conjunto de datos para calcular el número promedio de días que las líneas permanecen en el repositorio según el día de la semana. play

Archivos ordenados por la antigüedad media del código

Esta consulta utiliza el mismo principio que Qué día de la semana tiene el código la mayor probabilidad de permanecer en el repositorio: intenta identificar de forma única una línea de código mediante la ruta y el contenido de la línea. Esto nos permite determinar el tiempo transcurrido entre el momento en que se añadió una línea y el momento en que se eliminó. Sin embargo, filtramos para incluir solo los archivos actuales y únicamente el código, y calculamos el tiempo medio de cada archivo a partir de sus líneas. play

¿Quién suele escribir más tests / código en C++ / comentarios?

Hay varias formas de abordar esta pregunta. Si nos centramos en la proporción entre código y tests, esta consulta es relativamente sencilla: contar el número de contribuciones a carpetas que contienen tests y calcular la proporción con respecto al total de contribuciones. Aquí limitamos la consulta a usuarios con más de 20 cambios para centrarnos en quienes hacen commits con regularidad y evitar sesgos debidos a contribuciones puntuales. play
Podemos representar esta distribución como un histograma. play
La mayoría de los colaboradores escriben más código que pruebas, como cabría esperar. ¿Y quién añade más comentarios al aportar código? play
Ten en cuenta que ordenamos por contribuciones de código. Es un % sorprendentemente alto en todos nuestros principales colaboradores y parte de lo que hace que nuestro código sea tan legible.

¿Cómo varían con el tiempo los commits de un autor en cuanto al porcentaje de código/comentarios?

Calcular esto por autor es trivial,
Idealmente, sin embargo, queremos ver cómo cambia esto de forma agregada para todos los autores desde el primer día en que empiezan a hacer commits. ¿Van reduciendo poco a poco la cantidad de comentarios que escriben? Para calcularlo, primero determinamos la proporción de comentarios de cada autor a lo largo del tiempo, de forma similar a ¿Quién tiende a escribir más pruebas / código CPP / comentarios?. Luego, esto se cruza con la fecha de inicio de cada autor, lo que nos permite calcular la proporción de comentarios por desfase semanal. Después de calcular el promedio por desfase semanal para todos los autores, muestreamos estos resultados seleccionando cada décima semana. play
Es alentador que nuestro % de comentarios se mantenga bastante constante y no disminuya cuanto más tiempo contribuyen los autores.

¿Cuál es el tiempo promedio antes de que el código se reescriba y cuál es la mediana (vida media de la degradación del código)?

Podemos usar el mismo principio que en List files that were rewritten most number of time or by most of authors para identificar reescrituras, pero teniendo en cuenta todos los archivos. Se utiliza una función de ventana para calcular el tiempo entre reescrituras de cada archivo. A partir de esto, podemos calcular el promedio y la mediana para todos los archivos. play

¿Cuándo es peor escribir código, en el sentido de que tenga más probabilidades de reescribirse?

Al igual que en ¿Cuál es el tiempo promedio antes de que el código sea reescrito y la mediana (vida media de la degradación del código)? y Listar archivos que fueron reescritos la mayor cantidad de veces o por la mayor cantidad de autores, excepto que aquí agregamos por día de la semana. Ajústalo según sea necesario; por ejemplo, al mes del año. play

¿De qué autor es el código más duradero?

Definimos “duradero” como el tiempo que permanece el código de un autor antes de ser reescrito. Al igual que en la pregunta anterior ¿Cuál es el tiempo promedio antes de que se reescriba el código y la mediana (vida media de la degradación del código)?, usamos la misma métrica para las reescrituras; es decir, 50% de adiciones y 50% de eliminaciones en el archivo. Calculamos el tiempo promedio de reescritura por autor y solo consideramos a los colaboradores con más de dos archivos. play

Mayor número de días consecutivos de commits por autor

Esta consulta requiere primero calcular los días en que un autor ha realizado commits. Mediante una función de ventana, con partición por autor, podemos calcular los días transcurridos entre sus commits. Para cada commit, si el tiempo desde el commit anterior fue de 1 día, lo marcamos como consecutivo (1); en caso contrario, como 0, y almacenamos este resultado en consecutive_day. A continuación, nuestras funciones de array calculan la secuencia más larga de unos consecutivos de cada autor. Primero, se usa la función groupArray para recopilar todos los valores de consecutive_day de un autor. Luego, este array de 1 y 0 se divide en subarrays en los valores 0. Por último, calculamos el subarray más largo. probar

Historial de commits línea por línea de un archivo

Los archivos se pueden renombrar. Cuando esto ocurre, se genera un evento de cambio de nombre, donde la columna path se establece con la nueva ruta del archivo y old_path representa la ubicación anterior, por ejemplo. play
Esto dificulta consultar el historial completo de un archivo, ya que no tenemos un único valor que vincule todos los cambios de línea o de archivo. Para resolverlo, podemos usar funciones definidas por el usuario (UDF). Actualmente no pueden ser recursivas, así que, para identificar el historial de un archivo, debemos definir una serie de UDF que se llamen entre sí de forma explícita. Esto significa que solo podemos rastrear cambios de nombre hasta una profundidad máxima; en el ejemplo siguiente, esa profundidad es de 5. Es poco probable que un archivo se renombre más veces que eso, así que por ahora es suficiente.
Al llamar a file_path_history('src/Storages/StorageReplicatedMergeTree.cpp'), recorremos de forma recursiva el historial de cambios de nombre; cada función llama al siguiente nivel con old_path. Los resultados se combinan con arrayConcat. Por ejemplo,
Podemos usar esta capacidad para reconstruir ahora los commits de todo el historial de un archivo. En este ejemplo, mostramos un commit para cada uno de los valores de path.

Cuestiones pendientes

Git blame

Actualmente, es especialmente difícil obtener un resultado exacto debido a que no se puede mantener el estado en las funciones de array. Esto será posible con arrayFold o arrayReduce, que permiten conservar el estado en cada iteración. Una solución aproximada, suficiente para un análisis de alto nivel, podría ser algo así:
Agradecemos aquí las soluciones precisas y mejoradas.
Última modificación el 25 de junio de 2026