git informe movió líneas

Quiero rastrear la cantidad de adiciones y eliminaciones que excluyen las líneas movidas. Entonces, si un compromiso tiene 10 adiciones, 5 eliminaciones y 3 líneas movidas, entonces tengo 7 adiciones, 2 eliminaciones, excluidas las líneas movidas. El 10 y 5 están dados por el siguiente código. Necesito generar el 3 (solo necesito una detección de línea movida débil, por ejemplo, cualquier línea que aparezca idénticamente como eliminada simultáneamente de una location y agregada a otra location dentro de la misma confirmación).

Estoy usando lo siguiente para rastrear el número de adiciones y eliminaciones de un file importante en mi repository de git.

git log --since=2014-08-01 --date=short --pretty=format:"%ad%x09" --numstat -- file.tex 

Esto produce lo siguiente, donde el primer número es adiciones y el segundo número es eliminaciones.

 2014-08-19 72 0 file.tex 2014-08-19 211 290 file.tex ... 

Quiero agregar una tercera columna, llamarla líneas movidas. Las líneas movidas por compromiso se pueden encontrar haciendo lo siguiente en un bucle para cada confirmación:

  1. Conjunto de cambios Grep para líneas que comienzan con + o –
  2. Tira líder + o –
  3. sort
  4. uniq -d
  5. wc -l

¿Existe una manera rápida y elegante de ejecutar este pseudocódigo o simplemente necesito volcar y analizar un montón de diferencias completas de git para get lo que necesito?

Escribí la siguiente implementación en el lenguaje TXR . Al principio, utilicé tu algorithm para determinar el conteo movido. Sin embargo, noté que produce resultados que no son útiles: por ejemplo, identificaba valores positivos para "líneas movidas" en cambios que no contenían más que líneas + , simplemente porque algunas de las líneas + eran duplicadas entre sí. El nuevo algorithm se analiza en Notas al final.

El progtwig completo:

 #!/usr/bin/env txr @(bind option-spec @(list (opt nil "since" :str "Specifies the starting date (passed \ \ through to git); it is mandatory.") (opt nil "help" :bool "Prints this help text"))) @(bind parsed-opts @(getopts option-spec *args*)) @(if (or [parsed-opts "help"] (not [parsed-opts "since"]))) @ (output) usage: @{self-path} --since=<date> -- git arguments @ (end) @ (do (opthelp option-spec) (exit 0)) @(end) @(do (defun histogram (strings) [group-networkinguce (hash :equal-based) identity (op succ @1) strings 0]) (defun moved (ab) (let* ((hist-a (histogram a)) (hist-b (histogram b)) (isec [hash-isec hist-a hist-b min])) [networkinguce-left + (hash-values isec) 0]))) @(next (open-command `git log --since=@[parsed-opts "since"] \ \ --date=short --pretty=format:"%H:%ad%x09" \ \ --numstat @{parsed-opts.out-args}`)) @(repeat) @sha:@date@\t @ (collect :gap 0) @added@\t@removed@\t@rawpath @ (next :string rawpath) @ (cases) @pro/{@before => @after}/@epi @ (bind path `@pro/@after/@epi`) @ (or) @before => @after @ (bind path after) @ (or) @ (bind path rawpath) @ (end) @ (next (open-command `git show -p @sha -- @path`)) @ (collect :vars ((+line nil) (-line nil))) @ (cases) +@{+line} @ (or) -@{-line} @ (end) @ (end) @ (flatten -line +line) @ (bind moved @(moved +line -line)) @ (end) @ (output) @date@\t @ (repeat) @added@\t@removed@\t@moved@\t@rawpath @ (end) @ (end) @(end) 

Tengo esto en un file ejecutable marcado llamado movedlines.txr y el uso de ejemplo es:

 $ ./movedlines.txr --since=2017-01-01 path/to 

La opción --since es obligatoria; la path/to es un argumento opcional pasado a git . Si no especifica la opción obligatoria, o especifica --help , entonces el progtwig imprime un resumen de ayuda y se cierra.

Notas:

  • Cambié ligeramente el formatting de salida de su command git ejemplo para include el SHA a la izquierda de la date, separado por dos puntos: vea el %H El progtwig lo analiza y luego puede usar el SHA para hacer un git show -p en cada file en cada set. El SHA se omite cuando la imitación de la salida es regurgitada por el progtwig con la columna movida adicional.

  • Hay una complicación en que la salida de git muestra cambios de nombre. La syntax se divide en tres casos, que son analizados de manera clara y fácil por casos que usan el constructo @(cases) . Si se cambia el nombre de una ruta completa, el cambio de nombre es from => to . Si se renombran solo algunos componentes, es be/fore/{from => to}/after . No sé si se produce una syntax de llaves múltiples en una ruta; No lo he visto Debemos establecer esta syntax y convertirla en una ruta simple, porque git no la entiende. Es decir, debemos convertir be/fore/{from => to}/after en be/fore/to/after . Tal vez haya una opción de git para tener las routes de salida de esa manera sin la notación; No me molesté en mirar.

  • La secuencia de commands no es sólida robusta contra espacios en nombres de file debido al uso de open-command . Para eso necesitamos open-process que tome una list de arguments.

  • El algorithm calcula histogtwigs de frecuencia separados de las líneas diff y + (less su línea principal o + ). A continuación, calcula la intersección de estos sets, que conserva solo las inputs de histogtwig que se producen en ambos histogtwigs. La function de unión para la intersección es min . Entonces, por ejemplo, supongamos que la línea abc se agregó 5 veces y se eliminó 3 veces. (min 3 5) es 3 y ese es el número de líneas abc movidas. Esto conmuta. Si se eliminan 3 apariciones de abc y se agregan 5, eso implica 3 movimientos. Esto de ninguna manera se postula como algún tipo de algorithm perfecto para detectar movimientos. Tiene dificultades obvias como no detectar las líneas que se mueven de hecho, sino que también sufren un cambio trivial en el espacio en blanco, como la indentación.