← Blog

Analiza la evolución de tu código usando Julia

Christopher Villamarín

Cada vez que haces git commit, guardas algo más que código: guardas una decisión. A lo largo del tiempo, esas decisiones acumuladas cuentan la historia de un proyecto desde qué lenguajes programación usas hasta cuáles abandonaste; qué partes crecieron y cuáles murieron.

El script que presento aquí lee esa historia directamente desde tu historial de Git y la convierte en un gráfico de área apilada e interactivo. Para cada extensión de archivo que te interese rastrear, calcula las líneas netas commit a commit y las acumula en una línea de tiempo. El resultado es un HTML listo para el navegador.

Está escrito en Julia y no usa regex: la detección de fechas es puramente posicional y la extracción de extensiones trabaja con índices de texto. El resultado es un archivo evolucion_codigo.html generado con PlotlyBase, con hover unificado y tema oscuro.

using PlotlyBase
function generar_plotly_evolucion()
println("Procesando historial de Git...")
datos_por_ext = Dict{String,Dict{String,Int}}()
extensiones_interes = Set(["jl", "py", "c", "cpp", "h", "php", "js", "html", "css", "astro", "ts", "tsx", "dart", "rust", "go", "rb", "swift", "kt", "scala", "lua", "r", "sql", "zig", "nim", "elixir", "clj", "cljs", "lisp", "fsharp", "ocaml", "haskell", "groovy", "perl", "vb", "powershell", "bash", "zsh", "fish", "makefile", "dockerfile", "yaml", "json", "xml", "toml"])
fechas_set = Set{String}()
fecha_curr = ""
for linea in eachline(pipeline(`git log --pretty=format:%as --numstat`))
linea = strip(linea)
isempty(linea) && continue
# Detección estricta y sin Regex (más rápido para el CPU)
if length(linea) == 10 && linea[5] == '-' && linea[8] == '-'
fecha_curr = linea
push!(fechas_set, fecha_curr)
continue
end
# Dividir solo en 3 partes máximas
partes = split(linea, limit=3)
if length(partes) == 3
add_str, del_str, archivo = partes
(add_str == "-" || del_str == "-") && continue
# Extraer la extensión con índices en lugar de Regex
idx = findlast('.', archivo)
if idx !== nothing && idx < length(archivo)
ext = lowercase(archivo[idx+1:end])
if ext in extensiones_interes
add = parse(Int, add_str)
del = parse(Int, del_str)
# Obtener o crear el diccionario interno
d_ext = get!(datos_por_ext, ext, Dict{String,Int}())
d_ext[fecha_curr] = get(d_ext, fecha_curr, 0) + (add - del)
end
end
end
end
fechas_todas = sort(collect(fechas_set))
traces = GenericTrace[]
for ext in sort(collect(keys(datos_por_ext)))
d_ext = datos_por_ext[ext]
serie_acumulada = Int[]
suma = 0
# Rellenar los días usando el arreglo de strings ordenado
for d in fechas_todas
suma += get(d_ext, d, 0)
push!(serie_acumulada, max(0, suma))
end
t = scatter(
x=fechas_todas,
y=serie_acumulada,
mode="lines",
stackgroup="one",
name=".$ext",
fill="tonexty"
)
push!(traces, t)
end
layout = Layout(
title="Evolución de Código por Lenguaje",
xaxis_title="Fecha",
yaxis_title="Líneas de Código",
hovermode="x unified",
template="plotly_dark"
)
p = Plot(traces, layout)
open("evolucion_codigo.html", "w") do io
PlotlyBase.to_html(io, p)
end
println("¡Listo! Se ha creado 'evolucion_codigo.html'.")
end
generar_plotly_evolucion()

Instalación

Para ejecutar este script necesitas instalar PlotlyBase en Julia.

julia -e 'import Pkg; Pkg.add("PlotlyBase")'

Con esto deberías poder ejecutar el script y generar evolucion_codigo.html.

El script asume que estás dentro de un repositorio Git con un historial de commits y que tienes permisos para ejecutar comandos de Git desde la terminal. Para ejecutarlo tienes que escribir el siguiente comando:

julia script.jl

Ejemplo de resultado:

Resultado del script en el portafolio

Ten en cuenta que el análisis puede fallar o tardar mucho en repositorios muy grandes, con un historial de años o con muchísimos commits, ya que recorre todo el historial de Git.