A página de manual git-diff
é bastante longa e explica muitos casos que não parecem necessários para um iniciante. Por exemplo:
git diff origin/master
A página de manual git-diff
é bastante longa e explica muitos casos que não parecem necessários para um iniciante. Por exemplo:
git diff origin/master
Respostas:
Vamos dar uma olhada no exemplo diff avançado do histórico do git (no commit 1088261f no repositório 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] == '-') {
Vamos analisar esse patch linha por linha.
A primeira linha
diff --git a / builtin-http-fetch.cb / http-fetch.cé um cabeçalho "git diff" no formulário
diff --git a/file1 b/file2
. Os nomes de arquivo a/
e b/
são os mesmos, a menos que renomear / copiar esteja envolvido (como no nosso caso). A --git
é para significar que diff está no formato diff "git".A seguir, estão uma ou mais linhas de cabeçalho estendidas. Os três primeiros
índice de similaridade 95% renomeie de builtin-http-fetch.c renomeie para http-fetch.cdiga-nos que o arquivo foi renomeado de
builtin-http-fetch.c
para http-fetch.c
e que esses dois arquivos são 95% idênticos (que foram usados para detectar essa renomeação). índice f3e63d7..e8f44ba 100644informe-nos sobre o modo de um determinado arquivo (
100644
significa que ele é um arquivo comum e não, por exemplo, link simbólico, e que não possui um bit de permissão executável) e sobre um hash reduzido de pré-imagem (a versão do arquivo antes da alteração) e a pós-imagem (a versão do arquivo após a alteração). Essa linha é usada git am --3way
para tentar fazer uma mesclagem de 3 vias se o patch não puder ser aplicado.Em seguida é o cabeçalho diff unificado de duas linhas
--- a / builtin-http-fetch.c +++ b / http-fetch.cComparado ao
diff -U
resultado, ele não possui nomes de arquivo de tempo de modificação de arquivo nem de tempo de modificação de arquivo após os nomes dos arquivos de origem (pré-imagem) e de destino (pós-imagem). Se o arquivo foi criado, a fonte é /dev/null
; se o arquivo foi excluído, o destino é /dev/null
. diff.mnemonicPrefix
variável de configuração para true, no lugar de a/
e b/
prefixos neste cabeçalho de duas linhas que você pode ter ao invés c/
, i/
, w/
e o/
como prefixos, respectivamente para o que você comparar; veja git-config (1)Em seguida, vêm um ou mais pedaços de diferenças; cada pedaço mostra uma área em que os arquivos diferem. Pedaços de formato unificado começam com linhas como
@@ -1,8 +1,9 @@ou
@@ -18,6 +19,8 @@ int cmd_http_fetch (int argc, const char ** argv, ...É no formato
@@ from-file-range to-file-range @@ [header]
. O intervalo from-file está no formato -<start line>,<number of lines>
e to-file-range +<start line>,<number of lines>
. Tanto a linha inicial quanto o número de linhas referem-se à posição e comprimento do pedaço na pré-imagem e pós-imagem, respectivamente. Se o número de linhas não mostrado, significa que é 0.
O cabeçalho opcional mostra a função C em que cada alteração ocorre, se for um arquivo C (como -p
opção no GNU diff) ou o equivalente, se houver, para outros tipos de arquivos.
Em seguida, vem a descrição de onde os arquivos diferem. As linhas comuns aos dois arquivos começam com um caractere de espaço. As linhas que realmente diferem entre os dois arquivos têm um dos seguintes caracteres indicadores na coluna de impressão esquerda:
Então, por exemplo, primeiro pedaço
#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
foi substituído por main
e essa const char *prefix;
linha foi adicionada.
Em outras palavras, antes da mudança, o fragmento apropriado do arquivo 'builtin-http-fetch.c' era assim:
#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;
Após a alteração, este fragmento do arquivo 'http-fetch.c' se parece com o seguinte:
#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;
Pode haver
\ Nenhuma nova linha no final do arquivolinha presente (não é no exemplo diff).
Como Donal Fellows disse , é melhor praticar a leitura de diferenças em exemplos da vida real, onde você sabe o que mudou.
Referências:
git blame -C -C
, é assim que funciona; é uma decisão de design do Git. O formato git diff mostra apenas o índice de semelhança (ou dissimilaridade) com o usuário.
[header]
é o precedente mais próximo, como no início da função que precede um pedaço. Na maioria dos casos, essa linha inclui o nome da função na qual está o pedaço de diff. Isso é configurável com o diff
gitattribute definido como driver diff, e driver diff incluindo a xfuncname
variável de configuração.
@@ -1,2 +3,4 @@
parte do diff
Essa parte demorou um pouco para entender, então criei um exemplo mínimo.
O formato é basicamente o mesmo que o diff -u
diff unificado.
Por exemplo:
diff -u <(seq 16) <(seq 16 | grep -Ev '^(2|3|14|15)$')
Aqui removemos as linhas 2, 3, 14 e 15. Saída:
@@ -1,6 +1,4 @@
1
-2
-3
4
5
6
@@ -11,6 +9,4 @@
11
12
13
-14
-15
16
@@ -1,6 +1,4 @@
significa:
-1,6
significa que esta parte do primeiro arquivo começa na linha 1 e mostra um total de 6 linhas. Portanto, mostra as linhas 1 a 6.
1
2
3
4
5
6
-
significa "antigo", como normalmente chamamos diff -u old new
.
+1,4
significa que esta parte do segundo arquivo começa na linha 1 e mostra um total de 4 linhas. Portanto, mostra as linhas 1 a 4.
+
significa "novo".
Temos apenas 4 linhas em vez de 6 porque 2 linhas foram removidas! O novo pedaço é apenas:
1
4
5
6
@@ -11,6 +9,4 @@
para o segundo pedaço é análogo:
no arquivo antigo, temos 6 linhas, começando na linha 11 do arquivo antigo:
11
12
13
14
15
16
no novo arquivo, temos 4 linhas, começando na linha 9 do novo arquivo:
11
12
13
16
Observe que a linha 11
é a 9a linha do novo arquivo, porque já removemos duas linhas no pedaço anterior: 2 e 3.
Cabeçalho do pedaço
Dependendo da versão e configuração do git, você também pode obter uma linha de código próxima à @@
linha, por exemplo, func1() {
in:
@@ -4,7 +4,6 @@ func1() {
Isso também pode ser obtido com a -p
bandeira da planície diff
.
Exemplo: arquivo antigo:
func1() {
1;
2;
3;
4;
5;
6;
7;
8;
9;
}
Se removermos a linha 6
, o diff mostrará:
@@ -4,7 +4,6 @@ func1() {
3;
4;
5;
- 6;
7;
8;
9;
Observe que esta não é a linha correta para func1
: pulou as linhas 1
e 2
.
Esse recurso impressionante geralmente informa exatamente a qual função ou classe cada pedaço pertence, o que é muito útil para interpretar o diff.
Como o algoritmo para escolher o cabeçalho funciona exatamente é discutido em: De onde vem o trecho do cabeçalho do git diff hunk?
@@ -1,6 +1,4 @@
pls, não leia -1
como minus one
ou, +1
em plus one
vez disso, leia isso como line 1 to 6
no antigo (primeiro) arquivo. Observe aqui - implies "old"
não menos. BTW, obrigado pelo esclarecimento ... haash.
+1,4
diz que esta peça corresponde à linha 1 a 4 do segundo arquivo ". Isso ocorre porque +1,4
pode se referir a linhas de contexto não contingentes. Pelo contrário, o que " +1,4
" realmente significa é que " existem 4
linhas (isto é, linhas de contexto) nessa 'versão' do arquivo ". É importante compreender o significado do +
, -
e <whitespace>
no início dessas linhas, que se aplica à interpretação dos pedaços. Um exemplo mais visual: youtube.com/watch?v=1tqMjJeyKpw
Aqui está o exemplo simples.
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
Aqui está uma explicação (veja detalhes aqui ).
--git
não é um comando, isso significa que é uma versão git do diff (não unix)a/ b/
são diretórios, eles não são reais. é apenas uma conveniência quando lidamos com o mesmo arquivo (no meu caso, a / está no índice eb / está no diretório de trabalho)10ff2df..84d4fa2
são IDs de blob desses 2 arquivos100644
são os "bits de modo", indicando que este é um arquivo comum (não executável e não um link simbólico)--- a/file +++ b/file
sinais de menos mostra linhas na versão a / mas ausentes na versão b /; e sinais de mais mostram linhas ausentes em a / mas presentes em b / (no meu caso --- significa linhas excluídas e +++ significa linhas adicionadas em b / e este é o arquivo no diretório de trabalho)@@ -1,5 +1,5 @@
para entender isso, é melhor trabalhar com um arquivo grande; se você tiver duas alterações em lugares diferentes, receberá duas entradas como @@ -1,5 +1,5 @@
; suponha que você tenha o arquivo line1 ... line100 e excluiu a line10 e adicione a nova line100 - você receberá:@@ -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
) devem ser lidos em octal (valores: 1, 2, 4 respectivamente, permissão eXecute, Write e Read) e correspondem nessa ordem a Proprietário (Usuário), Grupo e Outras permissões. Então, resumindo 644
, se escrito simbolicamente u=rw,og=r
, é legível para todos, mas é gravável apenas pelo proprietário. Os outros dígitos à esquerda codificam outras informações, como se fosse um link simbólico, etc. Os valores podem ser vistos em github.com/git/git/blob/… , o primeiro 1 nesta posição é "arquivo regular".
O formato de saída padrão (originalmente proveniente de um programa conhecido como diff
se você deseja procurar mais informações) é conhecido como "diff unificado". Ele contém essencialmente 4 tipos diferentes de linhas:
+
,-
, eAconselho que você pratique a leitura de diferenças entre duas versões de um arquivo em que você sabe exatamente o que mudou. Assim, você reconhecerá exatamente o que está acontecendo quando o vir.
No meu mac:
info diff
depois selecione: Output formats
-> Context
-> Unified format
-> Detailed Unified
:
Ou o homem online difere no gnu seguindo o mesmo caminho para a mesma seção:
Arquivo: diff.info, Nó: Unificado detalhado, Próximo: Exemplo unificado, Acima: Formato unificado
Descrição detalhada do formato unificado ......................................
O formato de saída unificado começa com um cabeçalho de duas linhas, parecido com este:
--- FROM-FILE FROM-FILE-MODIFICATION-TIME +++ TO-FILE TO-FILE-MODIFICATION-TIME
O registro de data e hora parece "2002-02-21 23: 30: 39.942229878 -0800" para indicar a data, a hora com segundos fracionários e o fuso horário.
Você pode alterar o conteúdo do cabeçalho com a opção `--label = LABEL '; veja * Nota Nomes alternativos ::.
Em seguida, vêm um ou mais pedaços de diferenças; cada pedaço mostra uma área em que os arquivos diferem. Pedaços de formato unificado são assim:
@@ FROM-FILE-RANGE TO-FILE-RANGE @@ LINE-FROM-EITHER-FILE LINE-FROM-EITHER-FILE...
As linhas comuns aos dois arquivos começam com um caractere de espaço. As linhas que realmente diferem entre os dois arquivos têm um dos seguintes caracteres indicadores na coluna de impressão esquerda:
`+ 'Uma linha foi adicionada aqui ao primeiro arquivo.
`- 'Uma linha foi removida aqui do primeiro arquivo.
Não está claro em sua pergunta qual parte das diferenças você considera confusa: as informações realmente diff ou extra, que o git imprime. Apenas no caso, aqui está uma rápida visão geral do cabeçalho.
A primeira linha é algo como diff --git a/path/to/file b/path/to/file
- obviamente, está apenas dizendo a você para qual arquivo esta seção do diff é. Se você definir a variável de configuração booleana diff.mnemonic prefix
, o a
e b
será alterado para letras mais descritivas como c
e w
(confirmação e árvore de trabalho).
Em seguida, existem "linhas de modo" - linhas que fornecem uma descrição de quaisquer alterações que não envolvam a alteração do conteúdo do arquivo. Isso inclui arquivos novos / excluídos, arquivos renomeados / copiados e alterações nas permissões.
Finalmente, há uma linha como index 789bd4..0afb621 100644
. Você provavelmente nunca se importará com isso, mas esses números hexadecimais de 6 dígitos são os hashes SHA1 abreviados dos blobs antigos e novos desse arquivo (um blob é um objeto git que armazena dados brutos como o conteúdo de um arquivo). E, claro, esse 100644
é o modo do arquivo - os três últimos dígitos são obviamente permissões; os três primeiros fornecem informações extras sobre metadados de arquivos ( publicação SO descrevendo isso ).
Depois disso, você estará na saída diff unificada padrão (como no clássico diff -U
). Ele é dividido em pedaços - um pedaço é uma seção do arquivo que contém alterações e seu contexto. Cada pedaço é precedido por um par de ---
e +++
linhas que indicam o arquivo em questão; o diff real é (por padrão) três linhas de contexto em ambos os lados das linhas -
e +
mostrando as linhas removidas / adicionadas.
index
linha. Confirmado comgit hash-object ./file