Mostrar solo trozos relevantes de un diff / patch basado en una expresión regular


20

git log -G<regex> -pes una herramienta maravillosa para buscar cambios en el historial de una base de código que coincidan con el patrón especificado. Sin embargo, puede ser abrumador localizar el trozo relevante en la salida diff / patch en un mar de trozos en su mayoría irrelevantes.

Por supuesto, es posible buscar la salida de git logla cadena / expresión regular original, pero eso hace poco para reducir el ruido visual y la distracción de muchos cambios no relacionados.

Leyendo git log, veo que está el --pickaxe-all, que es exactamente lo contrario de lo que quiero: amplía la salida (a todo el conjunto de cambios), mientras que quiero limitarlo (al trozo específico).

Esencialmente, estoy buscando una manera de analizar "inteligentemente" el diff / patch en trozos individuales y luego ejecutar una búsqueda contra cada trozo (apuntando solo a las líneas cambiadas), descartar los trozos que no coinciden y generar los Esto hace.

¿Existe una herramienta como la que describo? ¿Existe un mejor enfoque para obtener los trozos emparejados / afectados?

Algunas investigaciones iniciales que he hecho ...

  • Si fuera posible grepla salida diff / patch y hacer que los valores de las opciones de contexto sean dinámicos, digamos, a través de expresiones regulares en lugar de recuentos de líneas, eso podría ser suficiente. Pero grepno está exactamente construido de esa manera (ni necesariamente estoy solicitando esa función).

  • Encontré la suite patchutils , que inicialmente sonaba como si pudiera satisfacer mis necesidades. Pero después de leer sus manpáginas, las herramientas no parecen manejar trozos coincidentes basados ​​en expresiones regulares. (Sin embargo, pueden aceptar una lista de trozos ...)

  • Finalmente me encontré con splitpatch.rb , que parece manejar bien el análisis del parche, pero necesitaría un aumento significativo para manejar parches de lectura stdin, emparejar los trozos deseados y luego generar los trozos.


1
No es exactamente lo que pediste, pero prueba git log -Gfoo | menos + / foo
James Youngman

Respuestas:


7

aquí /programming//a/35434714/5305907 se describe una forma de hacer lo que está buscando. efectivamente:

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

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


Gracias. grepdiffes básicamente lo que quiero; Debo haber perdido su opción de coincidencia de trozos! sin embargo ... la información de confirmación de git se elimina grepdiff, por lo que una vez que localice el trozo relevante, debe adivinar el sha de confirmación del objeto / blob sha en el encabezado diff, una operación bastante costosa. (ver stackoverflow.com/a/223890/2284440 ) sería algo así comogit find-object SHA --reverse | head -1 | cut -c 1-7 | { read sha ; git log -1 $sha; }
wrksprfct

También tenga en cuenta que hay una versión de golanggrepdiff que es más básica en términos de argumentos aceptados. tenga en cuenta que cuando el trozo coincidente es el último trozo en un diff, incluye incorrectamente el encabezado git commit del siguiente commit, ¡algo que me confundió por completo hasta que me di cuenta de lo que está sucediendo!
wrksprfct

0

No es exactamente lo que está pidiendo, pero una forma de lidiar con los trozos es el modo de adición interactiva. Esto requiere que revises el commit después del parche que te interesa

git checkout COMMIT_ID

luego retroceda un paso más en el VCS, pero no en el directorio de trabajo

git reset --soft HEAD^

(En este punto, la diferencia entre el índice y el directorio de trabajo corresponderá al parche que le interese).

Ahora puedes ejecutar git add -p. Esto lanzará una sesión interactiva que tiene una /opción, que le permite localizar trozos en los que alguna línea coincide con una expresión regular. Particularmente útil si realmente desea procesar aún más esos parches (como, preparar una selección parcial de cereza).

Desafortunadamente, al menos en este momento, el /comando add -psolo funciona dentro de un solo archivo, por lo que es posible que deba omitir varios archivos no relevantes.


0

Sobre la base de la respuesta anterior de @nagu, y las otras respuestas vinculadas, pude llegar git log -Ga mostrar solo los tíos relevantes.

  1. Primero cree un script en algún lugar de su $ PATH con este contenido:

    #!/bin/bash
    
    # pickaxe-diff : external diff driver for Git.
    #                To be used with the pickaxe options (git [log|show|diff[.*] [-S|-G])
    #                to only show hunks containing the searched string/regex.
    
    path=$1
    old_file=$2
    old_hex=$3
    old_mode=$4
    new_file=$5
    new_hex=$6
    new_mode=$7
    
    filtered_diff=$(diff -u -p $old_file $new_file | \
                    grepdiff "$GREPDIFF_REGEX" --output-matching=hunk | \
                    grep -v -e '+++ ' -e '--- ')
    
    a_path="a/$path"
    b_path="b/$path"
    
    echo "diff --git $a_path $b_path"
    echo "index $old_hex..$new_hex $old_mode"
    echo "--- $a_path"
    echo "+++ $b_path"
    echo "$filtered_diff"
  2. Llame git log -Gy dígale a Git que use el pickaxe-diffscript como un controlador de diferencias externo:

    export GREPDIFF_REGEX=<string>; 
    GIT_EXTERNAL_DIFF=pickaxe-diff git log -p --ext-diff -G $GREPDIFF_REGEX

    Esto usará el script pickaxe-diff solo para generar los diffs, por lo que el resto de la git logsalida (commit hash, mensaje, etc.) no se tocará.

Advertencia
La forma en que funciona el pico Git es que limita la salida a los archivos cuyos trozos cambian la cadena / expresión regular dada. Esto significa que si otro trozo en estos archivos también contiene la cadena de búsqueda / expresión regular, pero no la cambia, todavía se mostrará con el script anterior. Esta es una limitación de grepdiff. Hay una solicitud de extracción abierta en el proyecto patchutils para agregar un --only-matchingindicador a grepdiff, que proporcionaría la funcionalidad necesaria para filtrar correctamente estos trozos.


Hice una reseña de mi solución en esta esencia .

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.