La pagina man per git-diff
è piuttosto lunga e spiega molti casi che non sembrano essere necessari per un principiante. Per esempio:
git diff origin/master
La pagina man per git-diff
è piuttosto lunga e spiega molti casi che non sembrano essere necessari per un principiante. Per esempio:
git diff origin/master
Risposte:
Diamo un'occhiata all'esempio della differenza avanzata dalla cronologia di git (in commit 1088261f nel repository 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] == '-') {
Analizziamo questa patch riga per riga.
La prima riga
diff --git a / builtin-http-fetch.cb / http-fetch.cè un'intestazione "git diff" nel modulo
diff --git a/file1 b/file2
. I nomi di file a/
e b/
sono gli stessi a meno che non sia coinvolto rinominare / copiare (come nel nostro caso). La --git
sta a significare che la diff è nel formato diff "git".Successivamente ci sono una o più righe di intestazione estese. I primi tre
indice di somiglianza 95% rinominare da builtin-http-fetch.c rinominare in http-fetch.cdicci che il file è stato rinominato da
builtin-http-fetch.c
a http-fetch.c
e che quei due file sono identici al 95% (che è stato utilizzato per rilevare questa ridenominazione). indice f3e63d7..e8f44ba 100644parlaci della modalità di un determinato file (
100644
significa che si tratta di un file ordinario e non di un collegamento simbolico e che non ha un bit di autorizzazione eseguibile) e di un hash accorciato di preimage (la versione del file prima della modifica) e di postimage (il versione del file dopo la modifica). Questa riga viene utilizzata git am --3way
per provare a eseguire un'unione a 3 vie se la patch non può essere applicata da sola.Il prossimo è l'intestazione diff unificata a due righe
--- a / builtin-http-fetch.c +++ b / http-fetch.cRispetto al
diff -U
risultato, non ha nomi di file di modifica del file né di modifica del file dopo i tempi di origine (preimage) e destinazione (postimage). Se il file è stato creato, l'origine è /dev/null
; se il file è stato eliminato, la destinazione è /dev/null
. diff.mnemonicPrefix
variabile di configurazione true, in luogo di a/
e b/
prefissi in questa intestazione due linee si può avere invece c/
, i/
, w/
e o/
come prefissi, rispettivamente a ciò che si confrontano; vedi git-config (1)Poi arrivano uno o più pezzi di differenze; ogni pezzo mostra un'area in cui i file differiscono. Gli hunk in formato unificato iniziano con la linea come
@@ -1,8 +1,9 @@o
@@ -18,6 +19,8 @@ int cmd_http_fetch (int argc, const char ** argv, ...È nel formato
@@ from-file-range to-file-range @@ [header]
. L'intervallo da file è nella forma -<start line>,<number of lines>
e l'intervallo a file è +<start line>,<number of lines>
. Sia la linea di partenza che il numero di linee si riferiscono rispettivamente alla posizione e alla lunghezza del pezzo in preimagine e postimage. Se il numero di righe non viene visualizzato significa che è 0.
L'intestazione opzionale mostra la funzione C in cui si verifica ogni modifica, se si tratta di un file C (come l' -p
opzione in GNU diff), o l'eventuale equivalente per altri tipi di file.
Segue la descrizione di dove differiscono i file. Le linee comuni ad entrambi i file iniziano con un carattere spazio. Le righe che differiscono effettivamente tra i due file hanno uno dei seguenti caratteri indicatore nella colonna di stampa a sinistra:
Quindi, ad esempio, il primo pezzo
#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 che è cmd_http_fetch
stato sostituito da main
e quella const char *prefix;
linea è stata aggiunta.
In altre parole, prima della modifica, il frammento appropriato del file 'builtin-http-fetch.c' appariva così:
#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;
Dopo la modifica, questo frammento del file 'http-fetch.c' appare invece come questo:
#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;
Ci potrebbe essere
\ Nessuna nuova riga alla fine del filelinea presente (non è ad esempio diff).
Come ha detto Donal Fellows , è meglio esercitarsi nella lettura di diff su esempi di vita reale, in cui si sa cosa è cambiato.
Riferimenti:
git blame -C -C
, ecco come funziona; è una decisione di progettazione Git. Il formato git diff mostra solo l'indice di somiglianza (o dissomiglianza) con l'utente.
[header]
è il precedente più vicino come con l'inizio della funzione che precede un pezzo. Nella maggior parte dei casi questa riga include il nome della funzione in cui si trova il blocco di diff. Questo è configurabile con diff
gitattribute impostato su driver diff e driver diff inclusa la xfuncname
variabile di configurazione.
@@ -1,2 +3,4 @@
parte del diff
Questa parte mi ha richiesto un po 'di tempo per capire, quindi ho creato un esempio minimo.
Il formato è sostanzialmente lo stesso del diff -u
diff unificato.
Per esempio:
diff -u <(seq 16) <(seq 16 | grep -Ev '^(2|3|14|15)$')
Qui abbiamo rimosso le righe 2, 3, 14 e 15. Output:
@@ -1,6 +1,4 @@
1
-2
-3
4
5
6
@@ -11,6 +9,4 @@
11
12
13
-14
-15
16
@@ -1,6 +1,4 @@
si intende:
-1,6
significa che questo pezzo del primo file inizia alla riga 1 e mostra un totale di 6 righe. Pertanto mostra le righe da 1 a 6.
1
2
3
4
5
6
-
significa "vecchio", come di solito lo invochiamo come diff -u old new
.
+1,4
significa che questo pezzo del secondo file inizia alla riga 1 e mostra un totale di 4 righe. Pertanto mostra le righe da 1 a 4.
+
significa "nuovo".
Abbiamo solo 4 righe anziché 6 perché sono state rimosse 2 righe! Il nuovo pezzo è solo:
1
4
5
6
@@ -11,6 +9,4 @@
per il secondo pezzo è analogo:
sul vecchio file, abbiamo 6 righe, a partire dalla riga 11 del vecchio file:
11
12
13
14
15
16
sul nuovo file, abbiamo 4 righe, a partire dalla riga 9 del nuovo file:
11
12
13
16
Nota che la riga 11
è la nona riga del nuovo file perché abbiamo già rimosso 2 righe nel precedente hunk: 2 e 3.
Intestazione Hunk
A seconda della versione e della configurazione di git, puoi anche ottenere una riga di codice accanto alla @@
riga, ad es. func1() {
In:
@@ -4,7 +4,6 @@ func1() {
Questo può essere ottenuto anche con la -p
bandiera della pianura diff
.
Esempio: vecchio file:
func1() {
1;
2;
3;
4;
5;
6;
7;
8;
9;
}
Se rimuoviamo la linea 6
, il diff mostra:
@@ -4,7 +4,6 @@ func1() {
3;
4;
5;
- 6;
7;
8;
9;
Nota che questa non è la linea corretta per func1
: ha saltato le linee 1
e 2
.
Questa fantastica funzionalità spesso dice esattamente a quale funzione o classe appartiene ciascun pezzo, il che è molto utile per interpretare il diff.
Il modo in cui l'algoritmo per scegliere l'intestazione funziona esattamente è discusso in: Da dove viene l'estratto nell'intestazione hunk git diff?
@@ -1,6 +1,4 @@
pls non leggere -1
come minus one
o +1
come plus one
invece leggi questo come line 1 to 6
nel vecchio (primo) file. Nota qui - implies "old"
non meno. A proposito, grazie per il chiarimento ... haash.
+1,4
dice che questo pezzo corrisponde alle righe da 1 a 4 del secondo file ". Questo perché +1,4
può riferirsi a linee di contesto non contingenti. Piuttosto, ciò che " +1,4
" significa in realtà è che " ci sono 4
linee (cioè linee di contesto) in quella" versione "del file ". E 'importante capire il significato della +
, -
e <whitespace>
all'inizio di quelle linee, in quanto si applica l'interpretazione di hunk. Un esempio più visivo: youtube.com/watch?v=1tqMjJeyKpw
Ecco il semplice esempio.
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
Ecco una spiegazione (vedi dettagli qui ).
--git
non è un comando, questo significa che è una versione git di diff (non unix)a/ b/
sono directory, non sono reali. è solo una comodità quando trattiamo lo stesso file (nel mio caso a / è in indice e b / è nella directory di lavoro)10ff2df..84d4fa2
sono gli ID BLOB di questi 2 file100644
sono i "bit di modalità", che indicano che si tratta di un file normale (non eseguibile e non un collegamento simbolico)--- a/file +++ b/file
i segni meno mostrano le linee nella versione a / ma mancano nella versione b /; e i segni più mostrano le righe mancanti in a / ma presenti in b / (nel mio caso --- significa righe eliminate e +++ significa righe aggiunte in b / e questo è il file nella directory di lavoro)@@ -1,5 +1,5 @@
per capirlo è meglio lavorare con un file di grandi dimensioni; se hai due modifiche in luoghi diversi otterrai due voci simili @@ -1,5 +1,5 @@
; supponiamo di avere il file line1 ... line100 e cancellato line10 e aggiungere nuova line100 - otterrai:@@ -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
) devono essere lette in ottale (valori: 1, 2, 4 rispettivamente autorizzazione eXecute, Write e Read) e corrispondono in quell'ordine al proprietario (utente), quindi al gruppo, quindi ad altre autorizzazioni. Quindi in breve 644
significherebbe se scritto simbolicamente u=rw,og=r
, è leggibile da tutti ma scrivibile solo dal proprietario. Le altre cifre a sinistra codificano altre informazioni, ad esempio se si tratta di un collegamento simbolico, ecc. I valori possono essere visualizzati github.com/git/git/blob/… , il primo 1 in questa posizione è "file normale".
Il formato di output predefinito (che originariamente proviene da un programma noto come diff
se si desidera cercare ulteriori informazioni) è noto come "diff unificato". Contiene essenzialmente 4 diversi tipi di linee:
+
,-
eTi consiglio di esercitarti a leggere le differenze tra due versioni di un file in cui sai esattamente cosa hai cambiato. In questo modo riconoscerai esattamente cosa sta succedendo quando lo vedi.
Sul mio mac:
info diff
quindi selezionare: Output formats
-> Context
-> Unified format
-> Detailed Unified
:
Oppure man online diff su gnu seguendo lo stesso percorso per la stessa sezione:
File: diff.info, nodo: dettagliato unificato, successivo: esempio unificato, su: formato unificato
Descrizione dettagliata del formato unificato ......................................
Il formato di output unificato inizia con un'intestazione a due righe, che assomiglia a questo:
--- FROM-FILE FROM-FILE-MODIFICATION-TIME +++ TO-FILE TO-FILE-MODIFICATION-TIME
Il timestamp appare come "2002-02-21 23: 30: 39.942229878 -0800" per indicare la data, l'ora con i secondi frazionari e il fuso orario.
Puoi cambiare il contenuto dell'intestazione con l'opzione `--label = LABEL '; vedi * Nota Nomi alternativi ::.
Poi arrivano uno o più pezzi di differenze; ogni pezzo mostra un'area in cui i file differiscono. Gli hunk in formato unificato si presentano così:
@@ FROM-FILE-RANGE TO-FILE-RANGE @@ LINE-FROM-EITHER-FILE LINE-FROM-EITHER-FILE...
Le linee comuni ad entrambi i file iniziano con un carattere spazio. Le righe che differiscono effettivamente tra i due file hanno uno dei seguenti caratteri indicatore nella colonna di stampa a sinistra:
`+ 'Una riga è stata aggiunta qui al primo file.
`- 'Una riga è stata rimossa qui dal primo file.
Non è chiaro dalla tua domanda quale parte delle differenze trovi confusa: le informazioni di intestazione effettivamente diff o l'intestazione extra vengono stampate. Per ogni evenienza, ecco una rapida panoramica dell'intestazione.
La prima riga è qualcosa del genere diff --git a/path/to/file b/path/to/file
- ovviamente ti sta solo dicendo a quale file è destinata questa sezione del diff. Se si imposta la variabile di configurazione booleana diff.mnemonic prefix
, a
e b
verrà modificato in lettere più descrittive come c
e w
(commit e albero di lavoro).
Successivamente, ci sono "righe di modalità": righe che forniscono una descrizione di eventuali modifiche che non comportano la modifica del contenuto del file. Ciò include file nuovi / eliminati, file rinominati / copiati e modifiche alle autorizzazioni.
Infine, c'è una linea come index 789bd4..0afb621 100644
. Probabilmente non ti interesserà mai, ma quei numeri esadecimali a 6 cifre sono gli hash SHA1 abbreviati dei vecchi e nuovi BLOB per questo file (un BLOB è un oggetto git che memorizza dati grezzi come il contenuto di un file). E, naturalmente, 100644
è la modalità del file: le ultime tre cifre sono ovviamente autorizzazioni; i primi tre forniscono ulteriori informazioni sui metadati del file ( post SO che lo descrive ).
Successivamente, si passa all'output diff unificato standard (proprio come il classico diff -U
). È suddiviso in blocchi: un blocco è una sezione del file che contiene le modifiche e il loro contesto. Ogni pezzo è preceduto da una coppia di ---
e +++
linee che indicano il file in questione, quindi la differenza effettiva è (per impostazione predefinita) tre linee di contesto su entrambi i lati delle linee -
e +
che mostrano le linee rimosse / aggiunte.
index
linea. Confermato congit hash-object ./file