Filtrar un diff con una expresión regular

Parece que sería extremadamente útil poder filtrar un diff para que no se muestren cambios triviales. Me gustaría escribir una expresión regular que se ejecutaría en la línea y luego pasarle otra cadena que use los arguments capturados para generar una forma canónica. Si las líneas antes y después producen el mismo resultado, entonces serían eliminadas del diff.

Por ejemplo, estoy trabajando en una base de código PHP donde una gran cantidad de accesos a la matriz se escriben como my_array[my_key] cuando deberían ser my_array["my_key"] para evitar problemas si se define una constante my_key . Sería útil generar un diff donde el único cambio en la línea no fuera agregar algunas comillas.

No puedo cambiarlos todos a la vez, ya que no tenemos los resources para probar todo el código base, así que lo estoy arreglando cada vez que realizo un cambio en una function. ¿Cómo puedo conseguir esto? ¿Hay algo más similar a esto que pueda usar para lograr un resultado similar? Por ejemplo, un método más simple podría ser omitir la forma canónica y simplemente ver si la input se transforma en la salida. Por cierto, estoy usando Git

No parece haber ninguna opción para el command diff de Git para respaldar lo que desea hacer. Sin embargo, puede usar la variable de entorno GIT_EXTERNAL_DIFF y una secuencia de commands personalizada (o cualquier ejecutable creado con su scripting o lenguaje de progtwigción preferido) para manipular un parche.

Asumiré que estás en Linux; de lo contrario, podría modificar este concepto para adaptarlo a su entorno. Digamos que tienes un repository Git donde HEAD tiene un file file05 que contiene:

 line 26662: $my_array[my_key] 

Y un file file06 que contiene:

 line 19768: $my_array[my_key] line 19769: $my_array[my_key] line 19770: $my_array[my_key] line 19771: $my_array[my_key] line 19772: $my_array[my_key] line 19773: $my_array[my_key] line 19775: $my_array[my_key] line 19776: $my_array[my_key] 

file05 a:

 line 26662: $my_array["my_key"] 

Y cambias el file06 a:

 line 19768: $my_array[my_key] line 19769: $my_array["my_key"] line 19770: $my_array[my_key] line 19771: $my_array[my_key] line 19772: $my_array[my_key] line 19773: $my_array[my_key] line 19775: $my_array[my_key2] line 19776: $my_array[my_key] 

Usando el siguiente script de shell, vamos a llamarlo mydiff.sh y colocarlo en algún lugar que esté en nuestra PATH :

 #!/bin/bash echo "$@" git diff-files --patch --word-diff=porcelain "${5}" | awk ' /^-./ {rec = FNR; prev = substr($0, 2);} FNR == rec + 1 && /^+./ { ln = substr($0, 2); gsub("\\[\"", "[", ln); gsub("\"\\]", "]", ln); if (prev == ln) { print " " ln; } else { print "-" prev; print "+" ln; } } FNR != rec && FNR != rec + 1 {print;} ' 

Ejecutando el command:

 GIT_EXTERNAL_DIFF=mydiff.sh git --no-pager diff 

Se producirá:

 file05 /tmp/r2aBca_file05 d86525edcf5ec0157366ea6c41bc6e4965b3be1e 100644 file05 0000000000000000000000000000000000000000 100644 index d86525e..c2180dc 100644 --- a/file05 +++ b/file05 @@ -1 +1 @@ line 26662: $my_array[my_key] ~ file06 /tmp/2lgz7J_file06 d84a44f9a9aac6fb82e6ffb94db0eec5c575787d 100644 file06 0000000000000000000000000000000000000000 100644 index d84a44f..bc27446 100644 --- a/file06 +++ b/file06 @@ -1,8 +1,8 @@ line 19768: $my_array[my_key] ~ line 19769: $my_array[my_key] ~ line 19770: $my_array[my_key] ~ line 19771: $my_array[my_key] ~ line 19772: $my_array[my_key] ~ line 19773: $my_array[my_key] ~ line 19775: -$my_array[my_key] +$my_array[my_key2] ~ line 19776: $my_array[my_key] ~ 

Este resultado no muestra cambios para las citas agregadas en file05 y file06 . El script de diff externo básicamente usa el command Git diff-files para crear el parche y filtra el resultado a través de un script GNU awk para manipularlo. Este script de muestra no maneja todas las diferentes combinaciones de files antiguos y nuevos mencionados para GIT_EXTERNAL_DIFF ni GIT_EXTERNAL_DIFF un parche válido, pero debería ser suficiente para comenzar.

Podrías usar expresiones regulares de Perl , Python difflib o lo que sea que te difflib cómodo para implementar una herramienta de diferencias externa que se adapte a tus necesidades.

 $ git diff --help -G<regex> Look for differences whose added or removed line matches the given <regex>. 

EDITAR :

Después de algunas testings, tengo algo así como

 git diff -b -w --word-diff-regex='.*\[[^"]*\]' 

Luego obtuve resultados como:

 diff --git a/test.php b/test.php index 62a2de0..b76891f 100644 --- a/test.php +++ b/test.php @@ -1,3 +1,5 @@ <?php {+$my_array[my_key]+} = "test"; ?> diff --git a/test1.php b/test1.php index 62a2de0..6102fed 100644 --- a/test1.php +++ b/test1.php @@ -1,3 +1,5 @@ <?php some_other_stuff(); ?> 

Tal vez te ayude. Lo encontré aquí http://www.rhinocerus.net/forum/lang-lisp/659593-git-word-diff-regex-lisp-source.html y hay más información en este hilo

EDIT2 :

 git diff -G'\[[A-Za-z_]*\]' --pickaxe-regex 

Normalice los files de input en un primer paso, luego compare los files normalizados. Esto le da el mayor control sobre el process. Por ejemplo, es posible que desee aplicar solo la expresión regular a partes del código que no sean HTML, ni dentro de cadenas, ni dentro de comentarios (o ignore los comentarios por completo). Calcular una diferencia en el código normalizado es la forma correcta de hacer tales cosas; trabajar con expresiones regulares en líneas individuales es mucho más propenso a errores y, como máximo, un truco.

Algunas utilidades de diff como, por ejemplo, meld permiten ocultar la diferencia "insignificante", y vienen con un set de patrones pnetworkingeterminados para, por ejemplo, ocultar cambios de solo espacio en blanco. Esto es más o less lo que quieres, supongo.

de mi propio git –help

–word-diff-regex = <regex>

Use <regex> para decidir qué es una palabra, en lugar de considerar las ejecuciones de espacios no en blanco como una palabra. También implica –word-diff a less que ya esté habilitado. Cada coincidencia no superpuesta de <regex> se considera una palabra. Cualquier cosa entre estas coincidencias se considera espacios en blanco e ignorada (!) A los efectos de encontrar diferencias. Es posible que desee agregar |[^[:space:]] a su expresión regular para asegurarse de que coincida con todos los caracteres que no sean de espacios en blanco. Una coincidencia que contiene una nueva línea se trunca silenciosamente (!) En la nueva línea. La expresión regular también se puede configurar mediante un controller de diff o una opción de configuration, consulte gitattributes (1) o git-config (1). Al otorgarlo explícitamente se anula cualquier configuration de driver o configuration de diff. Los controlleres Diff anulan la configuration.

grepdiff se puede usar para filtrar los trozos en el file diff.

 $ git diff -U1 | grepdiff 'console' --output-matching=hunk 

Muestra solo los trozos que coinciden con la cadena "console" dada.

Utilizo un enfoque que combina git diff y aplicando una coincidencia de expresión regular en los resultados. En algún código de testing (PERL), sé que la testing es exitosa cuando el OutputFingerprint almacenado en los files resultantes de las testings no ha cambiado.

Primero, hago un

 my $matches = `git diff -- mytestfile` 

y luego evaluar el resultado:

 if($matches =~ /OutputFingerprint/){ fail(); return 1; }else{ ok(); return 0; } 

Si el objective es minimizar las diferencias triviales, puede considerar nuestra herramienta SmartDifferencer .

Estas herramientas comparan la syntax del lenguaje, no el layout, por lo que muchos cambios triviales (layout, comentarios modificados, incluso cambios en los numbers) se ignoran y no se informan. Cada herramienta tiene un analizador de lenguaje completo; hay una versión para muchos idiomas, incluido PHP.

No manejará el ejemplo $ FOO [abc] como "semánticamente idéntico" a $ FOO ["abc"], porque no lo son. Si abc actaully tiene una definición como constante, entonces $ FOO ["abc"] no es semánticamente equivalente.