Git diff para mostrar solo las líneas que han sido modificadas

128

Cuando hago un git diff, muestra líneas que se han agregado:

+ this line is added

líneas que se han eliminado:

- this line is removed

pero también muestra muchas líneas que no se modifican:

this line is not modified
this line is also not modified

Esto da como resultado que el git diff real se vea así:

+ this line is added
  this line is not modified
- this line is removed
  this line is not modified

¿Puedo pedirle a git que muestre solo las líneas que han sido modificadas e ignore el resto del código que no ha sido modificado? He escrito un método que eliminará todas las líneas que no tengan un signo "+" o "-" delante de ellas, pero estoy seguro de que debe haber una forma más sencilla de hacerlo.

En mi git diff, solo estoy interesado en ver las líneas que se han modificado.

Gracias por adelantado.

r3b00t
fuente

Respuestas:

182

Lo que quieres es un diff con 0 líneas de contexto. Puede generar esto con:

git diff --unified=0

o

git diff -U0

También puede establecer esto como una opción de configuración para ese repositorio:

git config diff.context 0

Para tenerlo configurado globalmente, para cualquier repositorio:

 git config --global diff.context 0
Chris Hayes
fuente
44
Gracias por responder rapido. Esto resuelve la mitad de mi problema, pero todavía recibo algunas líneas como "@@ -1 +1 @@" en mi diff y la parte superior de mi git diff tienen "diff --git a / db / xxxxxxx b / db / xxxx index xxxxx..aaaaaaa bbbbbbbb
r3b00t
3
No creo que git proporcione ninguna forma de evitar generar esas líneas, porque la diferencia no tendría sentido sin ellas (no podría saber qué archivo estaba mirando ni dónde estaba en el archivo).
Chris Hayes
8
@Rakesh: para expandirse, git-diff intenta crear diferencias que realmente se puedan usar como parches para los archivos de origen, lo cual es imposible sin esa información. La única forma de eliminarlo sería postprocesarlo usted mismo, como a través de git diff | egrep "^(\+|-) ".
Chris Hayes
1
git config --global diff.context 0 tenerlo configurado globalmente
Andrzej Rehmann
Si quieres ver en un directorio particular, prueba git diff -U0 <dir>
Eswar Yaganti
41

Otro truco (en un * x) para mostrar solo las líneas que comienzan con +y -:

git diff -U0 | grep '^[+-]' | grep -Ev '^(--- a/|\+\+\+ b/)'

El código anterior hace lo siguiente:

  • git diff -U0: elija 0 líneas de contexto
  • El primer grep solo incluye todas las líneas que comienzan con +o-
  • El segundo grep excluye líneas que comienzan con --- a/o+++ b/

Color

Para mostrar diferencias de color, intente lo siguiente:

git diff -U0 --color | grep '^\e\[[^m]*m[-+]' | grep -Ev '(--- a/|\+\+\+ b/)'
  • La expresión, ^\e\[[^m]*m[-+]busca el inicio de la línea ( ^), luego el carácter de escape ( \e) seguido por el [cual juntos comienzan la secuencia de escape, luego cualquier carácter que no sea una "m" (números, punto y coma o nada), seguido de un " m "que finaliza la secuencia de escape.
  • Tenga en cuenta que todas las siguientes son secuencias de escape válidas: \e[0m(restablecer), \e[m(también restablecer), \e[1m(en negrita), \e[31m(rojo), \e[32m(verde), \e[9;31m(tachar + rojo), \e[31;9m(rojo + tachar), \e[1;4;9;31m(negrita + subrayado + tachado + rojo). Los colores git predeterminados usan rojo y verde, pero se pueden reconfigurar.
  • --colores el mismo que --color=always.
  • La restricción en --- a/o +++ b/para aparecer al comienzo de la línea se ha eliminado para acomodar las secuencias de escape y esto podría conducir a un caso límite.

Notas adicionales:

  • La solución anterior se debe modificar si utiliza opciones adicionales git diff tales como -R, --src-prefix, --dst-prefix, --no-prefix, etc.
  • Los dos greps se pueden combinar en uno solo grep -E -v '^(\+\+\+ b/|--- a/|@@ |diff --git|index )', pero creo que la versión de doble grep es más fácil de entender.
usuario650654
fuente
2
Buena esa. Vota por la explicación clara de cada filtro.
henrebotha
Veo muchas git difflíneas de tipo "encabezado" que comienzan con @@, pero ¿cuáles son las git difflíneas que comienzan con ---o +++? No estaba al tanto de esos.
Gabriel Staples
Ah no importa. Esos denotan nombres de archivos para archivos que contienen adiciones ( +++) o eliminaciones ( ---). Veo eso aquí ahora: git-scm.com/docs/git-diff#_combined_diff_format .
Gabriel Staples
Corrección una vez más: --- a/filenameparece denotar el "archivo de la izquierda", o el archivo como era antes, y +++ b/filenameparece denotar el "archivo de la derecha", o el archivo como está ahora con sus cambios. Estoy tan acostumbrado a usar git difftoolcon meld , que muestra hermosas comparaciones de lado a lado, que nunca me acostumbré a mirar git diff, por lo que todavía me parece extraño, y nunca antes había visto estos matices.
Gabriel Staples
1
@GabrielStaples, se ha agregado soporte para el color. Gracias.
user650654
6

Siguiendo el último comentario de Chris, el principal problema con el postprocesamiento es que desea mantener las líneas que comienzan -|+pero también quiere filtrar las que comienzan ---|+++. Si está almacenando archivos de parche en su repositorio (lo hago, en Pydoop ), por otro lado, desea mantener las líneas que comienzan --|++, por lo que la expresión regular se involucra un poco:

git diff | grep -P '^\+(?:(?!\+\+))|^-(?:(?!--))'

La expresión regular usa una mirada negativa hacia adelante: vea la respuesta de Peter Boughton a esta pregunta para una explicación detallada.

Si hace esto a menudo, es posible que desee configurar un alias git para ello:

git config --global alias.diffonly '!git diff | grep -P "^\+(?:(?!\+\+))|^-(?:(?!--))"'
simleo
fuente
1
esto no funcionó para mí en Windows git bash. No sé por qué (grep dijo la opción inválida P), no tengo el chutzpah para investigarlo en este momento.
Dennis
1
-Po --perl-regexpse usa para interpretar el patrón como una expresión regular de Perl, pero no siempre se implementa. No me funcionó en OSX. gnu.org/software/grep/manual/grep.html#grep-Programs
Willington Vega
5

Creo que para casos simples, la expresión regular puede ser mucho más corta y fácil de recordar, con la advertencia de que esto no funcionará si tiene cambios de línea donde la línea comienza con +o-

$ git diff | grep '^[+|-][^+|-]'

La expresión regular dice que la línea debe comenzar con +o -, y el carácter que sigue inmediatamente no debe ser ninguno de esos. Obtuve los mismos resultados si escapé +o no aquí, por cierto ...


Ejemplo:

$ cat testfile
A
B
C
D
E
F
G

Digamos que cambio Ca X, Ea Yy Ga Z.

$ git diff | grep '^[+|-][^+|-]'
-C
+X
-E
+Y
-G
+Z

Sin embargo, como dije anteriormente, esto es solo para la mayoría de los casos. Si canaliza esa salida a un archivo dout, intente la misma expresión regular, no funcionará.

$ git diff dout | grep '^[+|-][^+|-]'
$

De todos modos, espero que eso ayude en tu caso

galois
fuente
Para los casos en que la línea comienza con "-" no funcionará. Ejemplo: - name: No pdben un archivo yaml.
anapaulagomes
3

Esta respuesta conservará los colores rojo / verde originales para facilitar la lectura. Proporcioné algunas variaciones en la sintaxis:

git diff --color | grep --color=never $'^\e\[3[12]m'
git diff --color | grep --color=never $'^\033\[3[12]m'
git diff --color | grep --color=never -P '^\e\[3[12]m'
git diff --color | grep --color=never -P '^\033\[3[12]m'

Explicación:

  • Se git diff --colornecesita para evitar que git desactive el color cuando se está canalizando.
  • El grep --color=neverobjetivo es evitar que grep elimine el color original y resalte la cadena coincidente.
  • Estamos haciendo coincidir las líneas que comienzan con los códigos de escape rojo ( \e[31m) o verde ( \e[32m).
  • La $'...'(sintaxis de comillas ANSI-C) o -P(sintaxis perl) es dejar grepde interpretar \eo \033como un ESCcarácter.
Wisbucky
fuente
Gracias por esto. Aquí hay una forma alternativa que se me ocurrió. Tu $''parte me ayudó especialmente. stackoverflow.com/a/61929887/4561887
Gabriel Staples
1

Cómo usar awkpara mostrar solo las líneas +y -, teniendo en cuenta cualquier color o formato de texto, git diffse puede generar:

Ninguna de las otras respuestas aquí (incluida mi otra respuesta ) hará exactamente lo que quieres 100% correctamente. Esta respuesta, sin embargo, lo hará. Aquí hay un 1-liner que puede copiar y pegar en su terminal. Acabo de hacer varias líneas para facilitar la lectura: puede copiarlo y pegarlo de la misma manera, ¡así que podría hacerlo legible! Se basa en el awklenguaje de programación:

git diff --color=always "$@" | awk '
# 1. Match and then skip "--- a/" and "+++ b/" lines
/^(\033\[(([0-9]{1,2};?){1,10})m)?(--- a\/|\+\+\+ b\/)/ {
    next 
} 
# 2. Now print the remaining "+" and "-" lines ONLY! Note: doing step 1 above first was required or
# else those lines would have been matched by this matcher below too since they also begin with 
# the "+" and "-" symbols.
/^(\033\[(([0-9]{1,2};?){1,10})m)?[-+]/ {
    print $0 
}
' | less -RFX

Aquí están sus características. Todas estas características, cuando se toman juntas, resuelven las deficiencias de cualquier otra respuesta aquí:

  1. Maneja la salida de color Y sin color. Eso es lo que hace esta expresión regular:^(\033\[(([0-9]{1,2};?){1,10})m)?
  2. Maneja TODOS LOS COLORES y TODAS LAS OPCIONES DE FORMATO DE TEXTO, incluyendo negrita, cursiva, tachado, etc., que puede configurar en su git configconfiguración . Es por eso que la expresión regular anterior tiene;? y {1,10}en ella: si detecta el inicio de un código de formato de color o texto, coincidirá con hasta 10 secuencias de estos códigos ANSI combinados.
  3. NO incluye líneas que comienzan con @@la palabra diff, como lo hace la respuesta aceptada . Si desea esas líneas (que francamente, creo que son útiles :)), haga esto en su lugar:

    git diff --unified=0
    

    o

    git diff -U0
    
  4. Muestra la salida de la misma manera que lo git diffharía: en el lessbuscapersonas con salida de color opcional ( -R), y solo si el texto es> 1 página ( -F), y al mismo tiempo que retiene la página de texto actual en la pantalla cuando qusa ( -X) .

También tiene la ventaja de ser potente y fácil de configurar, ya que utiliza el lenguaje de programación awk.

Si está interesado en aprender awk , aquí hay algunos recursos:

  1. gawk(GNU awk) manual: https://www.gnu.org/software/gawk/manual/html_node/index.html#SEC_Contents
  2. Estudio git diffny los comentarios allí: https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles/blob/master/useful_scripts/git-diffn.sh
    1. Si lo desea git diffntambién, que es git diffcon números de línea, consulte aquí: Git diff con números de línea (Git log con números de línea)
  3. Algunos ejemplos de prueba de sintaxis y "hello world" de awk: https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/tree/master/awk

Como git diffcbeneficio adicional, también envolví lo anterior para usarlo , lo que significa "git diff para mostrar SOLO 'cambios'". El uso es idéntico a git diff; solo use git diffcen su lugar! Es compatible con TODAS las opciones. El color está activado por defecto. Para apagarlo, simplemente use git diffc --no-coloro git diffc --color=never. Ver man git diffpara más detalles.

Desde que acabo de terminar git diffn(una herramienta para mostrargit diff con líneas y números) anoche, escribir git diffcfue trivial. Pensé que sería mejor hacerlo ahora mientras el conocimiento está fresco en mi cabeza.

Instalar en pc git diffc :

Siga las instrucciones al final de esta respuesta aquí , excepto en todas partes que vea git-diffnen las instrucciones, use git-diffcen su lugar. Eso incluye en el wgetcomando también. Descargar e instalar git diffces fácil: solo son unos pocos comandos.

Gabriel Staples
fuente
0

Aquí hay otra forma más simple de encontrar solo líneas que se hayan modificado y, por lo tanto, comenzar con una sola +o -, mientras se conserva la salida de color:

git diff -U0 --color=always HEAD~ | grep --color=never -E $'^\e\[(32m\+|31m-)'
  1. El -U0dice que incluya 0 líneas de contexto en torno a las líneas cambiadas - es decir: incluir sólo las propias líneas cambiadas. Ver man git diff.
  2. El -Efor grep le permite trabajar con expresiones regulares extendidas
  3. La $''sintaxis aparentemente permite las citas ANSI, que interpreta correctamente el carácter ESC (escape o 0x1b) correctamente. Ver aquí .
  4. Y aquí está la descripción de expresiones regulares de https://www.regex101.com :ingrese la descripción de la imagen aquí
  5. Básicamente, ^coincide con el comienzo de la línea, \ecoincide con el carácter de escape, que es el comienzo de un código de color en el terminal, \[coincide con el siguiente carácter en el código de color, que es [, y luego la (this|that)sintaxis coincide con "this" o "that" , donde "esto" es 32m+, que es una línea verde +, y31m- es una línea roja.
  6. Los colores son así: \e[32mes verde y \e[31mes rojo.
  7. +muestra líneas marcadas git diffcomo agregadas, por supuesto, y -muestra líneas marcadas porgit diff como eliminadas.
  8. Tenga en cuenta que --color=neverse requiere en la segunda grepexpresión para evitar que resalte sus coincidencias, lo que de otro modo arruinaría los códigos de color que provienen degit diff la izquierda.
  9. También +debe escaparse \+porque, de lo contrario, +es un carácter especial de expresión regular (expresión regular) que especifica una o más ocurrencias del elemento anterior . Ver aquí: https://en.wikipedia.org/wiki/Regular_expression#Basic_concepts .

Referencias

  1. https://git-scm.com/docs/git-diff#_combined_diff_format
  2. Respuesta de @ user650654: Git diff para mostrar solo las líneas que se han modificado
  3. Respuesta de @wisbucky: Git diff para mostrar solo las líneas que se han modificado

Relacionado:

  1. [mi propia respuesta] Git diff con números de línea (Git log con números de línea)
  2. [la respuesta de otra persona] Git diff con números de línea (Git log con números de línea)
  3. git diff con números de línea y alineación / sangría de código adecuado
  4. git-filechange-search.sh- un script que le permite buscar en un archivo una variable o nombre de función y descubrir qué confirmaciones contienen cambios con esa variable o nombre de función. Ex. uso: ./git-filechange-search.sh path/to/my/file.cpp variable_nameencontrará todos los commits con cambios en file.cpp que contienen variable_nameen ellos. Esto es útil para ver dónde y cuándo se modificaron ciertas características. Es como si fuera una búsqueda que pudiera observar secciones de un archivo que se muestran a través del git blametiempo.
Gabriel Staples
fuente