La página de manual git-diff
es bastante larga y explica muchos casos que no parecen ser necesarios para un principiante. Por ejemplo:
git diff origin/master
La página de manual git-diff
es bastante larga y explica muchos casos que no parecen ser necesarios para un principiante. Por ejemplo:
git diff origin/master
Respuestas:
Veamos un ejemplo de diferencia avanzada del historial de git (en commit 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 línea
diff --git a / builtin-http-fetch.cb / http-fetch.ces un encabezado "git diff" en el formulario
diff --git a/file1 b/file2
. Los nombres de archivo a/
y b/
son los mismos a menos que se trate de renombrar / copiar (como en nuestro caso). Esto --git
significa que diff está en el formato diff "git".A continuación hay una o más líneas de encabezado extendidas. Los primeros tres
índice de similitud 95% cambiar el nombre de builtin-http-fetch.c renombrar a http-fetch.cdíganos que se cambió el nombre del archivo
builtin-http-fetch.c
a http-fetch.c
y que esos dos archivos son 95% idénticos (que se utilizó para detectar este cambio de nombre). índice f3e63d7..e8f44ba 100644cué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 hash acortado de preimagen (la versión del archivo antes del cambio dado) y postimagen (el versión del archivo después del cambio). Esta línea se utiliza git am --3way
para intentar hacer una fusión de 3 vías si el parche no se puede aplicar por sí mismo.El siguiente es el encabezado diff unificado de dos líneas
--- a / builtin-http-fetch.c +++ b / http-fetch.cEn comparación con el
diff -U
resultado, no tiene el tiempo de modificación de archivo ni el tiempo de modificación de archivo después de los nombres de los archivos de origen (imagen previa) y destino (imagen posterior). Si se creó el archivo, la fuente es /dev/null
; si el archivo fue eliminado, el objetivo es /dev/null
. diff.mnemonicPrefix
la variable de configuración de verdad, en lugar de a/
y b/
prefijos en esta cabecera de dos líneas que puede tener lugar c/
, i/
, w/
y o/
como prefijos, respectivamente, a lo que se compara; ver git-config (1)Luego vienen uno o más trozos de diferencias; cada trozo muestra un área donde los archivos difieren. Los formatos unificados comienzan con líneas 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]
. From-file-range tiene el formato -<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 la longitud del trozo en preimagen y postimagen, respectivamente. Si no se muestra el número de líneas, significa que es 0.
El encabezado opcional muestra la función C donde se produce cada cambio, si es un archivo C (como la -p
opción en GNU diff), o el equivalente, si lo hay, 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 izquierda:
Entonces, por ejemplo, primer trozo
#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 que const char *prefix;
se agregó esa 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 ahora archivo 'http-fetch.c' se ve así en su lugar:
#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 hay nueva línea al final del archivolínea presente (no es, por ejemplo, diff).
Como dijo Donal Fellows , es mejor practicar diferencias de lectura en ejemplos de la vida real, donde sabes lo que has cambiado.
Referencias
git blame -C -C
, así es como funciona; Es la decisión de diseño de Git. El formato git diff solo muestra el índice de similitud (o disimilitud) para el usuario.
[header]
es el precedente más cercano, como el comienzo de la función que precede a un trozo. En la mayoría de los casos, esta línea incluye el nombre de la función en la que se encuentra el fragmento de diff. Esto es configurable con diff
gitattribute establecido en el controlador diff, y el controlador diff incluyendo la xfuncname
variable de configuración.
@@ -1,2 +3,4 @@
parte de la diferencia
Esta parte me llevó un tiempo comprender, así que he creado un ejemplo mínimo.
El formato es básicamente el mismo que el diff -u
diff unificado.
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 lo tanto, muestra las líneas 1 a 6.
1
2
3
4
5
6
-
significa "viejo", como solemos invocarlo 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 lo 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 trozo es solo:
1
4
5
6
@@ -11,6 +9,4 @@
para 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 que la 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 Hunk
Dependiendo de su versión y configuración de git, también puede obtener una línea de código junto a la @@
línea, por ejemplo, func1() {
en:
@@ -4,7 +4,6 @@ func1() {
Esto también se puede obtener con la -p
bandera de la llanura diff
.
Ejemplo: archivo antiguo:
func1() {
1;
2;
3;
4;
5;
6;
7;
8;
9;
}
Si eliminamos 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
: omitió líneas 1
y 2
.
Esta característica impresionante a menudo dice exactamente a qué función o clase pertenece cada trozo, lo cual es muy útil para interpretar la diferencia.
La forma en que funciona exactamente el algoritmo para elegir el encabezado se analiza en: ¿De dónde proviene el extracto del encabezado git diff hunk?
@@ -1,6 +1,4 @@
pls, no lea -1
como minus one
o +1
en su plus one
lugar, lea esto como line 1 to 6
en el archivo anterior (primero). Tenga en cuenta aquí - implies "old"
no menos. Por cierto, gracias por la aclaración ... haash.
+1,4
dice que esta pieza corresponde a las líneas 1 a 4 del segundo archivo ". Esto se debe a que +1,4
puede referirse a líneas de contexto no contingentes. Más bien, lo que " +1,4
" significa en realidad es que " hay 4
líneas (es decir, líneas de contexto) en esa 'versión' del archivo ". Es importante entender el significado de la +
, -
y <whitespace>
al principio de estas líneas, ya que se aplica a la interpretación de los trozos. Un ejemplo más visual: youtube.com/watch?v=1tqMjJeyKpw
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 (ver 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 y b / está en el directorio de trabajo)10ff2df..84d4fa2
son ID de blob de estos 2 archivos100644
son los "bits de modo", que indican que se trata de un archivo normal (no ejecutable y no 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 las 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 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 @@
; supongamos que tiene el archivo line1 ... line100 y line10 eliminado 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
644
) deben leerse en octal (valores: 1, 2, 4 respectivamente permisos de Ejecución, Escritura y Lectura) y corresponden en ese orden al Propietario (Usuario), luego al Grupo, luego a Otros permisos. En resumen 644
, significaría que si está escrito simbólicamente u=rw,og=r
, eso es legible para todos, pero solo el propietario puede escribirlo. Los otros dígitos de la izquierda codifican otra información, como si se trata de un enlace simbólico, etc. Los valores se pueden ver en github.com/git/git/blob/… , el primer 1 en esta posición es "archivo normal".
El formato de salida predeterminado (que originalmente proviene de un programa conocido como diff
si desea buscar más información) se conoce como "diff unificado". Contiene esencialmente 4 tipos diferentes de líneas:
+
,-
, yLe aconsejo que practique la lectura de diferencias entre dos versiones de un archivo donde sepa exactamente lo que cambió. Así reconocerás lo que está sucediendo cuando lo veas.
En mi mac:
info diff
luego seleccione: Output formats
-> Context
-> Unified format
-> Detailed Unified
:
O man diff en línea en gnu siguiendo la misma ruta a la misma sección:
Archivo: diff.info, Nodo: Unificado detallado, Siguiente: Ejemplo unificado, Arriba: Formato unificado
Descripción detallada del formato unificado ......................................
El formato de salida unificado comienza con un encabezado de dos líneas, que se ve así:
--- FROM-FILE FROM-FILE-MODIFICATION-TIME +++ TO-FILE TO-FILE-MODIFICATION-TIME
La marca de tiempo se ve como '2002-02-21 23: 30: 39.942229878 -0800' para indicar la fecha, la hora con segundos fraccionarios y la zona horaria.
Puede cambiar el contenido del encabezado con la opción `--label = LABEL '; ver * Nota nombres alternativos ::.
Luego vienen uno o más trozos de diferencias; cada trozo muestra un área donde los archivos difieren. Los trozos de formato unificado se ven así:
@@ FROM-FILE-RANGE TO-FILE-RANGE @@ LINE-FROM-EITHER-FILE LINE-FROM-EITHER-FILE...
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 izquierda:
`+ 'Aquí se agregó una línea al primer archivo.
`- 'Aquí se eliminó una línea del primer archivo.
No está claro a partir de su pregunta qué parte de los diferenciales encuentra confusa: la diferencia real o la información adicional del encabezado que imprime git. Por si acaso, aquí hay una descripción rápida del encabezado.
La primera línea es algo así como diff --git a/path/to/file b/path/to/file
, obviamente, solo te dice para qué archivo es esta sección del diff. Si establece la variable de configuración booleana diff.mnemonic prefix
, el a
y b
se cambiará a letras más descriptivas como c
y w
(commit y work tree).
A continuación, hay "líneas de modo": líneas que proporcionan una descripción de cualquier cambio que no implique cambiar el contenido del archivo. Esto incluye archivos nuevos / eliminados, archivos renombrados / copiados y cambios de permisos.
Finalmente, hay una línea como index 789bd4..0afb621 100644
. Probablemente nunca te importe, pero esos números hexadecimales de 6 dígitos son los hashes SHA1 abreviados de los blobs viejos y nuevos para este archivo (un blob es un objeto git que almacena datos sin procesar como el contenido de un archivo). Y, por supuesto, este 100644
es el modo del archivo: los últimos tres dígitos son obviamente permisos; los primeros tres dan información adicional de metadatos del archivo ( publicación SO que describe eso ).
Después de eso, pasará a la salida diferencial unificada estándar (al igual que la clásica diff -U
). Se divide en trozos: un trozo es una sección del archivo que contiene los cambios y su contexto. Cada trozo está precedido por un par de ---
y +++
líneas que denotan el archivo en cuestión, luego la diferencia real es (por defecto) tres líneas de contexto a cada lado de las líneas -
y +
que muestran las líneas eliminadas / agregadas.
index
línea. Confirmado congit hash-object ./file