Saltar al contenido

¿Cómo leer la salida de git diff?

Solución:

Echemos un vistazo al ejemplo de diff avanzado del historial de git (en el compromiso 1088261f en el repositorio de git.git):

diff --git a/builtin-http-fetch.c b/http-fetch.c
similarity index 95%
rename from builtin-http-fetch.c
rename to http-fetch.c
index f3e63d7..e8f44ba 100644
--- a/builtin-http-fetch.c
+++ b/http-fetch.c
@@ -1,8 +1,9 @@
 #include "cache.h"
 #include "walker.h"

-int cmd_http_fetch(int argc, const char **argv, const char *prefix)
+int main(int argc, const char **argv)
 {
+       const char *prefix;
        struct walker *walker;
        int commits_on_stdin = 0;
        int commits;
@@ -18,6 +19,8 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix)
        int get_verbosely = 0;
        int get_recover = 0;

+       prefix = setup_git_directory();
+
        git_config(git_default_config, NULL);

        while (arg < argc && argv[arg][0] == '-') {

Analicemos este parche línea por línea.

  • La primera linea

    diff --git a/builtin-http-fetch.c b/http-fetch.c

    es un encabezado “git diff” con el formato diff --git a/file1 b/file2. los a/ y b/ los nombres de archivo son los mismos a menos que se trate de cambiar el nombre / copiar (como en nuestro caso). los --git significa que diff está en el formato diff “git”.

  • A continuación, se encuentran una o más líneas de encabezado extendidas. Los primeros tres

    similarity index 95%
    rename from builtin-http-fetch.c
    rename to http-fetch.c

    díganos que el nombre del archivo se cambió de builtin-http-fetch.c para http-fetch.c y que esos dos archivos son 95% idénticos (que se utilizó para detectar este cambio de nombre).

    La última línea en el encabezado diff extendido, que es

    index f3e63d7..e8f44ba 100644

    cuéntenos sobre el modo del archivo dado (100644 significa que es un archivo ordinario y no, por ejemplo, un enlace simbólico, y que no tiene un bit de permiso ejecutable), y sobre el hash abreviado de preimage (la versión del archivo antes del cambio dado) y postimage (la versión del archivo después del cambio). Esta línea es utilizada por git am --3way para intentar hacer una combinación de 3 vías si el parche no se puede aplicar por sí mismo.

  • El siguiente es el encabezado diferencial unificado de dos líneas

    --- a/builtin-http-fetch.c
    +++ b/http-fetch.c

    En comparación con diff -U El resultado no tiene tiempo de modificación de archivo ni tiempo de modificación de archivo después de los nombres de archivo de origen (preimagen) y destino (postimagen). Si el archivo fue creado, la fuente es /dev/null; si el archivo fue eliminado, el destino es /dev/null.
    Si pones diff.mnemonicPrefix variable de configuración a verdadero, en lugar de a/ y b/ prefijos en este encabezado de dos líneas que puede tener en su lugar c/, i/, w/ y o/ como prefijos, respectivamente, a lo que compara; ver git-config (1)

  • Luego vienen uno o más trozos de diferencias; cada trozo muestra un área donde los archivos difieren. Los trozos de formato unificado comienzan con una línea como

    @@ -1,8 +1,9 @@

    o

    @@ -18,6 +19,8 @@ int cmd_http_fetch(int argc, const char **argv, ...

    Está en el formato @@ from-file-range to-file-range @@ [header]. El rango desde el archivo tiene la forma -<start line>,<number of lines>y to-file-range es +<start line>,<number of lines>. Tanto la línea de inicio como el número de líneas se refieren a la posición y longitud del trozo en preimagen y posimagen, respectivamente. Si no se muestra el número de líneas, significa que es 0.

    El encabezado opcional muestra la función C donde ocurre cada cambio, si es un archivo C (como -p opción en GNU diff), o el equivalente, si lo hubiera, para otros tipos de archivos.

  • Luego viene la descripción de dónde difieren los archivos. Las líneas comunes a ambos archivos comienzan con un carácter de espacio. Las líneas que realmente difieren entre los dos archivos tienen uno de los siguientes caracteres indicadores en la columna de impresión de la izquierda:

    • ‘+’: Aquí se agregó una línea al primer archivo.
    • ‘-‘ – Aquí se eliminó una línea del primer archivo.

    Entonces, por ejemplo, primer fragmento

     #include "cache.h"
     #include "walker.h"
    
    -int cmd_http_fetch(int argc, const char **argv, const char *prefix)
    +int main(int argc, const char **argv)
     {
    +       const char *prefix;
            struct walker *walker;
            int commits_on_stdin = 0;
            int commits;
    

    significa que cmd_http_fetch fue reemplazado por main, y eso const char *prefix; Se agregó la línea.

    En otras palabras, antes del cambio, el fragmento apropiado del archivo ‘builtin-http-fetch.c’ se veía así:

    #include "cache.h"
    #include "walker.h"
    
    int cmd_http_fetch(int argc, const char **argv, const char *prefix)
    {
           struct walker *walker;
           int commits_on_stdin = 0;
           int commits;
    

    Después del cambio, este fragmento del archivo ‘http-fetch.c’ ahora se ve así:

    #include "cache.h"
    #include "walker.h"
    
    int main(int argc, const char **argv)
    {
           const char *prefix;
           struct walker *walker;
           int commits_on_stdin = 0;
           int commits;
    
  • Podría haber

     No newline at end of file

    línea presente (no está en el ejemplo diff).

Como dijo Donal Fellows, es mejor practicar la lectura de diferencias en ejemplos de la vida real, donde se sabe lo que ha cambiado.

Referencias:

  • página de manual de git-diff (1), sección “Generación de parches con -p”
  • (diff.info) Nodo unificado detallado, “Descripción detallada del formato unificado”.

@@ -1,2 +3,4 @@ parte de la diferencia

Me tomó un tiempo entender esta parte, así que he creado un ejemplo mínimo.

El formato es básicamente el mismo que el diff -u diferencia unificada

Por ejemplo:

diff -u <(seq 16) <(seq 16 | grep -Ev '^(2|3|14|15)$')

Aquí eliminamos las líneas 2, 3, 14 y 15. Salida:

@@ -1,6 +1,4 @@
 1
-2
-3
 4
 5
 6
@@ -11,6 +9,4 @@
 11
 12
 13
-14
-15
 16

@@ -1,6 +1,4 @@ medio:

  • -1,6 significa que esta parte del primer archivo comienza en la línea 1 y muestra un total de 6 líneas. Por tanto, muestra las líneas 1 a 6.

    1
    2
    3
    4
    5
    6
    

    - significa “antiguo”, ya que normalmente lo invocamos como diff -u old new.

  • +1,4 significa que esta parte del segundo archivo comienza en la línea 1 y muestra un total de 4 líneas. Por tanto, muestra las líneas 1 a 4.

    + significa “nuevo”.

    ¡Solo tenemos 4 líneas en lugar de 6 porque se eliminaron 2 líneas! El nuevo galán es simplemente:

    1
    4
    5
    6
    

@@ -11,6 +9,4 @@ porque el segundo trozo es análogo:

  • en el archivo anterior, tenemos 6 líneas, comenzando en la línea 11 del archivo anterior:

    11
    12
    13
    14
    15
    16
    
  • en el nuevo archivo, tenemos 4 líneas, comenzando en la línea 9 del nuevo archivo:

    11
    12
    13
    16
    

    Tenga en cuenta esa línea 11 es la novena línea del nuevo archivo porque ya hemos eliminado 2 líneas en el trozo anterior: 2 y 3.

Encabezado de hunk

Dependiendo de su versión y configuración de git, también puede obtener una línea de código junto al @@ línea, por ejemplo, el func1() { en:

@@ -4,7 +4,6 @@ func1() {

Esto también se puede obtener con el -p bandera de llanura diff.

Ejemplo: archivo antiguo:

func1() {
    1;
    2;
    3;
    4;
    5;
    6;
    7;
    8;
    9;
}

Si quitamos la línea 6, la diferencia muestra:

@@ -4,7 +4,6 @@ func1() {
     3;
     4;
     5;
-    6;
     7;
     8;
     9;

Tenga en cuenta que esta no es la línea correcta para func1: saltó líneas 1 y 2.

Esta asombrosa característica a menudo dice exactamente a qué función o clase pertenece cada trozo, lo cual es muy útil para interpretar la diferencia.

Cómo funciona exactamente el algoritmo para elegir el encabezado se discute en: ¿De dónde proviene el extracto en el encabezado de git diff hunk?

Aquí está el ejemplo simple.

diff --git a/file b/file 
index 10ff2df..84d4fa2 100644
--- a/file
+++ b/file
@@ -1,5 +1,5 @@
 line1
 line2
-this line will be deleted
 line4
 line5
+this line is added

Aquí hay una explicación (vea los detalles aquí).

  • --git no es un comando, esto significa que es una versión git de diff (no unix)
  • a/ b/ son directorios, no son reales. es solo una conveniencia cuando tratamos con el mismo archivo (en mi caso, a / está en el índice yb / está en el directorio de trabajo)
  • 10ff2df..84d4fa2 son ID de blobs de estos 2 archivos
  • 100644 son los “bits de modo”, lo que indica que se trata de un archivo normal (no ejecutable ni un enlace simbólico)
  • --- a/file +++ b/file los signos menos muestran líneas en la versión a / pero faltan en la versión b /; y los signos más muestran líneas que faltan en a / pero están presentes en b / (en mi caso — significa líneas eliminadas y +++ significa líneas agregadas en b / y este es el archivo en el directorio de trabajo)
  • @@ -1,5 +1,5 @@ para entender esto es mejor trabajar con un archivo grande; si tiene dos cambios en diferentes lugares, obtendrá dos entradas como @@ -1,5 +1,5 @@; suponga que tiene el archivo line1 … line100 y eliminó la línea10 y agrega una nueva línea100; obtendrá:
@@ -7,7 +7,6 @@ line6
 line7
 line8
 line9
-this line10 to be deleted
 line11
 line12
 line13
@@ -98,3 +97,4 @@ line97
 line98
 line99
 line100
+this is new line100
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *