2012-06-05 5 views
6

En la línea de comandos, si escriborecuperación eficiente de comunicados que contienen una confirmación

git tag --contains {commit} 

para obtener una lista de las versiones que contienen un commit dado, se tarda alrededor de 11 a 20 segundos para cada confirmación. Dado que la base de código de destino existe más de 300,000 confirmaciones, tomaría mucho tiempo recuperar esta información para todas las confirmaciones.

Sin embargo, gitk aparentemente se las arregla para hacer un buen trabajo al recuperar esta información. Por lo que busqué, usa un caché para ese propósito.

Tengo dos preguntas:

  1. ¿Cómo puedo interpretar que el formato de caché?
  2. ¿Hay alguna forma de obtener un volcado de la herramienta de línea de comandos git para generar esa misma información?
+0

¿Sería útil implementar su propia funcionalidad de caché cli? Si es así, creo que puedo aportar algunas ideas para eso. –

+0

Sí, eso funcionaría para mí. – leco

Respuesta

5

Puede obtener esto casi directamente en git rev-list.

latest.awk:

BEGIN { thiscommit=""; } 
$1 == "commit" { 
    if (thiscommit != "") 
     print thiscommit, tags[thiscommit] 
    thiscommit=$2 
    line[$2]=NR 
    latest = 0; 
    for (i = 3 ; i <= NF ; ++i) if (line[$i] > latest) { 
     latest = line[$i]; 
     tags[$2] = tags[$i]; 
    } 
    next; 
} 
$1 != "commit" { tags[thiscommit] = $0; } 
END { if (thiscommit != "") print thiscommit, tags[thiscommit]; } 

un comando de ejemplo:

git rev-list --date-order --children --format=%d --all | awk -f latest.awk 

también se puede utilizar --topo-order, y es probable que tenga que eliminar a los árbitros no deseados en la lógica $1!="commit".

Dependiendo del tipo de transitividad que desee y de lo explícito que sea el listado, la acumulación de las etiquetas puede necesitar un diccionario. Aquí hay una que recibe una lista explícita de todas las referencias para todas las confirmaciones:

all.awk:

BEGIN { 
    thiscommit=""; 
} 
$1 == "commit" { 
    if (thiscommit != "") 
     print thiscommit, tags[thiscommit] 
    thiscommit=$2 
    line[$2]=NR 
    split("",seen); 
    for (i = 3 ; i <= NF ; ++i) { 
     nnew=split(tags[$i],new); 
     for (n = 1 ; n <= nnew ; ++n) { 
      if (!seen[new[n]]) { 
       tags[$2]= tags[$2]" "new[n] 
       seen[new[n]] = 1 
      } 
     } 
    } 
    next; 
} 
$1 != "commit" { 
    nnew=split($0,new,", "); 
    new[1]=substr(new[1],3); 
    new[nnew]=substr(new[nnew],1,length(new[nnew])-1); 
    for (n = 1; n <= nnew ; ++n) 
     tags[thiscommit] = tags[thiscommit]" "new[n] 

} 
END { if (thiscommit != "") print thiscommit, tags[thiscommit]; } 

all.awk tomó unos minutos para hacer el kernel de linux repo 322K compromete, alrededor de un millar de un segundo o algo por el estilo (muchas cadenas duplicadas y procesamiento redundante) por lo que probablemente quieras volver a escribir eso en C++ si realmente buscas el producto cruzado completo ... pero no creo que gitk lo demuestre, solo los vecinos más cercanos, a la derecha ?

+0

Para aclararnos a nosotros los usuarios que no son awk: estos scripts hacen exactamente lo mismo que 'git tag --contains {commit}'? –

+0

% d de rev-list muestra todas las referencias, no solo las etiquetas, por lo que all.awk obtiene todas las etiquetas y ramas, no solo las etiquetas, pero aparte de eso, sí, all.awk es un lote --contiene ... por cierto, no tomará dos horas para aprender awk. – jthill

Cuestiones relacionadas