Git diff con números de línea (registro de Git con números de línea)

93

Cuando hago una git diffo una git log -p, ¿cómo obtengo los números de línea de los archivos de origen alineados con la salida?

Traté de buscarlo man git-diff | grep "line numbers"e intenté buscar en Google, pero no obtuve nada rápidamente.

Drew LeSueur
fuente

Respuestas:

92

No puede obtener números de línea legibles por humanos con git diff

Actualmente no hay opciones para que los números de línea se muestren verticalmente en el lado con git diff.

Formato de diferencia unificada

Sin embargo, esa información está disponible en los encabezados de hunk (c) para cada cambio en la diferencia, solo está en formato de diferencia unificada :

@@ -start,count +start,count @@

El estado original del archivo se representa con -y el nuevo estado se representa con +(no significan adiciones y eliminaciones en el encabezado del trozo.representa startel número de línea inicial de cada versión del archivo y countrepresenta cuántas líneas se incluyen , comenzando desde el punto de inicio.

Ejemplo

diff --git a/osx/.gitconfig b/osx/.gitconfig
index 4fd8f04..fcd220c 100644
--- a/osx/.gitconfig
+++ b/osx/.gitconfig
@@ -11,7 +11,7 @@ <== HERE!
 [color "branch"]
        upstream = cyan
 [color "diff"]
-       meta = yellow
+       meta = cyan
        plain = white dim
        old = red bold
        new = green bold

El encabezado del trozo

@@ -11,7 +11,7 @@

dice que la versión anterior del archivo comienza en la línea 11 e incluye 7 líneas:

11  [color "branch"]
12         upstream = cyan
13  [color "diff"]
14 -       meta = yellow
14 +       meta = cyan
15         plain = white dim
16         old = red bold
17         new = green bold

mientras que la siguiente versión del archivo también comienza en la línea 11 y también incluye 7 líneas.

El formato de diferencia unificada no es realmente para consumo humano

Como probablemente pueda ver, el formato de diferencia unificada no facilita el cálculo de los números de línea (al menos si no es una máquina). Si realmente desea números de línea que pueda leer, necesitará usar una herramienta de diferenciación que los muestre.

Lectura adicional

Jalid
fuente
4
Aquí hay un grep para extraer solo números de línea en archivos modificados, por ejemplo, para usarlo para filtrar un informe de estilo de verificacióngit diff --unified=0 | grep -Po '^\+\+\+ ./\K.*|^@@ -[0-9]+(,[0-9]+)? \+\K[0-9]+(,[0-9]+)?(?= @@)'
Jakub Bochenski
1
El comentario de @JakubBochenski resolvió mi problema bastante bien.
0xbe5077ed
Sin embargo, esto solo es realmente útil si especifica --unified=0o -U0.
caw
Acabo de terminar git diffn, un reemplazo directo (envoltorio) para el git diffque muestra los números de línea y tiene total compatibilidad con todos los usos y opciones de git diff: stackoverflow.com/questions/24455377/…
Gabriel Staples
22

Aquí hay dos soluciones más, ampliando el código de Andy Talkowski.

Texto sin formato:

  git diff | gawk 'match($0,"^@@ -([0-9]+),[0-9]+ [+]([0-9]+),[0-9]+ @@",a){left=a[1];right=a[2];next};\
   /^(---|\+\+\+|[^-+ ])/{print;next};\
   {line=substr($0,2)};\
   /^-/{print "-" left++ ":" line;next};\
   /^[+]/{print "+" right++ ":" line;next};\
   {print "(" left++ "," right++ "):"line}'

Texto en color, asumiendo que \033[66mes el formato de los códigos de color:

  git diff --color=always | \
    gawk '{bare=$0;gsub("\033[[][0-9]*m","",bare)};\
      match(bare,"^@@ -([0-9]+),[0-9]+ [+]([0-9]+),[0-9]+ @@",a){left=a[1];right=a[2];next};\
      bare ~ /^(---|\+\+\+|[^-+ ])/{print;next};\
      {line=gensub("^(\033[[][0-9]*m)?(.)","\\2\\1",1,$0)};\
      bare~/^-/{print "-"left++ ":" line;next};\
      bare~/^[+]/{print "+"right++ ":" line;next};\
      {print "("left++","right++"):"line;next}'

El código cambia líneas que comienzan con -y +a -1:-y +1:+, respectivamente, y las líneas que comienzan con nada a (5,6):. Los números son los números de línea del archivo respectivo.

PFudd
fuente
Noto que rompe la alineación (sangría) del código, mientras que el nativo git diffmantiene cuidadosamente la alineación. Este código está sobre mi cabeza en este momento, así que ¿estaría dispuesto a arreglarlo? En otras palabras, cuando una línea dice +240:+y la siguiente línea dice (241,257):, debe agregar algunos espacios adicionales a la línea superior para que su código mantenga la alineación y sangría adecuadas con el código de la línea inferior. ¿Quizás esto podría hacerse fácilmente con la impresión?
Gabriel Staples
... quiero decir con printf.
Gabriel Staples
No importa; ¡Lo tengo! Acabo de terminar git diffn. Vea aquí: stackoverflow.com/a/61997003/4561887 . Gracias @PFudd, por tu respuesta. Lo estudié y lo usé para aprender, luego comencé desde cero y escribí git diffn. Una vez formateado para poder leer su código (gracias @EdMorton), pude aprender algunas cosas geniales que me ayudaron.
Gabriel Staples
6

Aquí hay un script que intenta solucionar este problema, no lo probé con ira, pero parece estar bien. Se basa en los registros que produce git diff y usa awk para mantener el recuento de líneas.

# Massage the @@ counts so they are usable
function prep1() {
   cat | awk -F',' 'BEGIN { convert = 0; }
       /^@@ / { convert=1; }
       /^/  { if ( convert == 1 ) { print $1,$2,$3;
              } else { print $0;
              }
              convert=0;
             }'
}

# Extract all new changes added with the line count
function prep2() {
  cat | awk 'BEGIN { display=0; line=0; left=0; out=1;}
     /^@@ / { out=0; inc=0; line=$4; line--; display=line; left=line;        }
     /^[-]/   { left++; display=left; inc=0; }
     /^[+]/   { line++; display=line; inc=0; }
     /^[-+][-+][-+] / { out=0; inc=0; }
     /^/    { 
               line += inc;
               left += inc;
               display += inc;
               if ( out == 1 ) {
                   print display,$0;
               } else {
                   print $0;
               }
               out = 1;
               inc = 1;
               display = line;
            }'
} 

git diff $1 | prep1 | prep2 
Andy Talkowski
fuente
4

Puede utilizar git difftoolpara hacer la diferencia con un editor externo que mostrará los números de línea. He aquí cómo hacerlo con vim / vimdiff:

  1. Establecer vimdiff como difftool de git:

    git config --global diff.tool vimdiff
    
  2. Configure ~/.vimrcpara mostrar automáticamente los números de línea al usar vimdiff:

    if &diff
        set number
    endif
    
  3. Ejecute git difftool, que usará vimdiff con números de línea:

    git difftool
    
Wisbucky
fuente
Con solo hacer git difftool, me abrió la herramienta tkdiff, que tiene la función de número de línea. Gracias wisbucky
Richardd
3

Una forma rápida es usar git diff -U0. Eso establecerá las líneas de contexto en 0, lo que hará que los valores @@ coincidan con las líneas cambiadas reales. De forma predeterminada, los valores @@ incluyen 3 líneas de contexto antes / después, lo que no es conveniente para los humanos.

Ejemplo:

git diff # default
@@ -10,8 +10,8 @@

Es difícil calcular los números de línea de las líneas cambiadas porque la línea 10 se refiere a la primera línea del contexto anterior. El número de línea real de la primera línea modificada es 10 + 3 = 13. Para calcular el número de líneas cambiadas, también debe restar el contexto antes y después: 8-3-3 = 2.

git diff -U0
@@ -13,2 +13,2 @@

Como puede ver, establecer context = 0 hace que los valores @@ sean más fáciles de leer para los humanos. Puede ver que las líneas cambiadas comienzan en la línea 13 y hay 2 líneas cambiadas.

Esto no es perfecto, ya que solo muestra el número de línea de cada bloque. Si desea ver los números de línea para cada línea, utilice difftool para un editor externo. Ver https://stackoverflow.com/a/50049752

Wisbucky
fuente
3

Me gusta usar git difftoolcon MELD como mi difftool. Es más fácil de ver que git diff, tiene una buena comparación de interfaz gráfica de usuario y muestra los números de línea en cada lado.

Preparar:

  1. Instrucciones sobre cómo configurar meld como su difftool para Windows o Linux

Captura de pantalla de muestra:

ingrese la descripción de la imagen aquí

Actualización 24 de mayo de 2020:

Acabo de escribir git diffndurante los últimos días para ser un reemplazo git diffdirecto de la línea de comandos. Dale un tiro. Vea mi otra respuesta aquí .

Gabriel Staples
fuente
3

A partir del 24 de mayo de 2020, ahora puede usar la herramienta de terceros git diffn(divulgación completa: la escribí) para este propósito. Es un envoltorio ligero git diff, escrito en el awklenguaje de programación basado en patrones / acciones. Aquí hay una salida de muestra de la ejecución git diffn:

ingrese la descripción de la imagen aquí

1/3: ¿Qué es?

Desde lo alto degit-diffn.sh :

DESCRIPCIÓN:

git-diffn.sh

  1. ¡un reemplazo git diffdirecto para el que también muestra números de línea! Úselo exactamente igual git diff, excepto que verá estos hermosos números de línea también para ayudarlo a entender sus cambios.

  2. ya que es solo un contenedor ligero basado en el lenguaje awk git diff, acepta TODAS las opciones y parámetros que git diffacepta. Ejemplos:

  3. git diffn HEAD~

  4. git diffn HEAD~3..HEAD~2

  5. funciona con cualquiera de sus git diffconfiguraciones de color, incluso si está utilizando colores personalizados

  6. Vea mi respuesta aquí para saber cómo configurar colores de diferencia personalizados, así como para ver una captura de pantalla de la salida de color personalizado de git diffn: ¿Cómo se personaliza el color del encabezado de diferencias en git diff?

  7. Aquí hay algunos git configcomandos de muestra de mi respuesta anterior para establecer git diffcolores y atributos personalizados (formato de texto):

       git config --global color.diff.meta "blue"
       git config --global color.diff.old "black red strike"
       git config --global color.diff.new "black green italic"
       git config --global color.diff.context "yellow bold"
    
  8. adentro git diffn, la salida de color está activada de forma predeterminada; si desea deshabilitar el color de salida, debe usar --no-coloro --color=never. Consulte man git diffpara obtener más detalles. Ejemplos:

     git diffn --color=never HEAD~
     git diffn --no-color HEAD~3..HEAD~2
    

2/3: Instalación

  1. Windows (no probado): esto puede funcionar dentro del terminal bash que viene con Git para Windows , pero no está probado. Instale Git para Windows. Abra el terminal bash que viene con él e intente seguir las instrucciones a continuación. Necesito algunos probadores que prueben esto en Git para Windows. Consulte y responda aquí: https://github.com/git-for-windows/git/issues/2635 .
  2. Mac (no probado): use el terminal y siga las instrucciones a continuación. Es posible que deba instalar gawk. Si es así, trate de esta : brew install gawk.
  3. Linux (probado en Ubuntu 18.04 y funciona perfectamente): siga las instrucciones del terminal a continuación.

Opción 1 (mi recomendación): descargue el repositorio completo y luego cree un enlace simbólico al programa para que pueda recibir actualizaciones fácilmente haciendo una git pulldesde el repositorio cuando lo desee.

Primero, cda donde quieras instalar esto. Entonces corre:

git clone https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles.git
cd eRCaGuy_dotfiles/useful_scripts
mkdir -p ~/bin
ln -si "${PWD}/git-diffn.sh" ~/bin/git-diffn

¡Hecho! ¡Ahora solo haz el paso final a continuación!

Opción 2 (para aquellos que solo quieren el archivo 1): descargue solo el archivo una vez.

mkdir -p ~/bin
cd ~/bin
wget https://raw.githubusercontent.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles/master/useful_scripts/git-diffn.sh
chmod +x git-diffn.sh
mv git-diffn.sh git-diffn

¡Hecho! ¡Ahora solo haz el paso final a continuación!

Último paso:

Ahora cierre y vuelva a abrir su terminal, o recárguelo con . ~/.bashrc, ¡y listo!

git diffnahora funcionará como un reemplazo directo exacto de git diff!

Aquí hay una demostración:

3/3: Demo de git diffn:

Crea este archivo:

hello_world.c:

#include <stdio.h>

int main()
{
    printf("Hello World\n");

    return 0;
}

Comprométase:

git add hello_world.c
git commit -m "add hello_world.c"

Cámbielo a esto y guarde el archivo:

hello_world.c:

// Basic hello world example

#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("Hello Gabriel\n");
    
    int i = 700;
    printf("i = %i\n", i);
    return 0;
}

Ahora ejecuta:

git diff

Aquí está el resultado de git difffirst para fines de comparación:

$ git diff
diff --git a/hello_world.c b/hello_world.c
index e01704a..e971b73 100644
--- a/hello_world.c
+++ b/hello_world.c
@@ -1,8 +1,12 @@
+// Basic hello world example
+
 #include <stdio.h>
 
-int main()
+int main(int argc, char *argv[])
 {
-    printf("Hello World\n");
-
+    printf("Hello Gabriel\n");
+    
+    int i = 700;
+    printf("i = %i\n", i);
     return 0;
-}
\ No newline at end of file
+}

Y una captura de pantalla para mostrar el color. Tenga en cuenta que la sección resaltada en rojo simplemente muestra espacios en blanco vacíos (espacios en este caso) que podrían eliminarse:

ingrese la descripción de la imagen aquí

Ahora aquí está la salida de git diffn . ¡Observe que muestra todos los números de línea perfectamente!

  • Los números de línea de las líneas eliminadas están a la izquierda y muestran un- signo tanto en el extremo izquierdo como en el derecho del :para ayudarlo a ver mejor, ya sea que a sus ojos les guste escanear hacia la derecha del colon o hacia abajo en el extremo a la izquierda de la pantalla.
  • Los números de línea para las líneas agregadas están más a la derecha y muestran un+ signo tanto a la izquierda como a la derecha del :.
  • Los números de línea de las líneas sin cambios que se muestran para el contexto se muestran tanto para la izquierda (archivo antiguo) como para la derecha (archivo nuevo),, .

Salida de git diffn:

$ git diffn
diff --git a/hello_world.c b/hello_world.c
index e01704a..e971b73 100644
--- a/hello_world.c
+++ b/hello_world.c
@@ -1,8 +1,12 @@
+        1:+// Basic hello world example
+        2:+
    1,   3: #include <stdio.h>
    2,   4: 
-   3     :-int main()
+        5:+int main(int argc, char *argv[])
    4,   6: {
-   5     :-    printf("Hello World\n");
-   6     :-
+        7:+    printf("Hello Gabriel\n");
+        8:+    
+        9:+    int i = 700;
+       10:+    printf("i = %i\n", i);
    7,  11:     return 0;
-   8     :-}
\ No newline at end of file
+       12:+}

Y una captura de pantalla para mostrar el color. Tenga en cuenta que los dos puntos NO están coloreados ni estilizados para que coincidan con el texto circundante a la izquierda y a la derecha. Este es un comportamiento intencional y diseñado para actuar como un separador visual entre los números de línea agregados a la izquierda y la git diffsalida original a la derecha.

ingrese la descripción de la imagen aquí

Gabriel Staples
fuente
1

Puedes probar

git blame

en el archivo. Le muestra el confirmador, la identificación del compromiso y el número de línea para cada línea en el archivo.

Juan
fuente
4
El problema con esto es que no muestra una diferencia , que es lo que pedía el póster original. git blamesolo mostrará el estado actual del archivo con números de línea.
5
Sabía de la culpa, pero alguien que buscaba en Google podría no haberlo hecho. Podría ayudar a alguien. Gracias por responder.
Drew LeSueur
git blamede ninguna manera responde la pregunta; Estoy bastante desconcertado por los votos a favor aquí
Michael Mrozek
No envíe spam al stackoverflow con respuestas que no estén relacionadas con las preguntas.
Ahmed
0

Primero, configure su herramienta git diff, por ejemplo, Meld

git config --global diff.tool meld

Luego, tira de tu difftool en algún archivo:

git difftool -y config.rb

Recuerde configurar el número de línea en la preferencia de su herramienta de diferencias.

HaxtraZ
fuente