Comparando alterações com o git diff

A comparação é uma função que recebe dois conjuntos de dados de entrada e gera as alterações entre eles. O git diff é um comando Git multiuso que, quando executado, realiza uma função de comparação nas fontes de dados Git. Essas fontes de dados podem ser commits, ramificações, arquivos e outros. Este documento vai discutir solicitações comuns de git diff e comparações de padrões de fluxo de trabalho. O comando git diff é com frequência usado junto com o git status e o git log para analisar o estado atual de um repositório Git.

Leitura de comparações: resultados

Formato de resultado bruto

Os exemplos a seguir vão ser executados em um repositório simples. O repositório é criado com os comandos abaixo:

$:> mkdir diff_test_repo
$:> cd diff_test_repo
$:> touch diff_test.txt
$:> echo "this is a git diff test example" > diff_test.txt
$:> git init .
Initialized empty Git repository in /Users/kev/code/test/.git/
$:> git add diff_test.txt
$:> git commit -am"add diff test file"
[master (root-commit) 6f77fc3] add diff test file
1 file changed, 1 insertion(+)
create mode 100644 diff_test.txt

Se o git diff for executado neste ponto, não vai gerar resultado. Esse é o comportamento esperado, pois não há alterações no repositório para comparações. Com o repositório criado e o arquivo diff_test.txt adicionado, é possível mudar o conteúdo do arquivo para começar a experimentar o resultado da comparação.

$:> echo "this is a diff example" > diff_test.txt

A execução deste comando vai alterar o conteúdo do arquivo diff_test.txt. Uma vez modificado, podemos visualizar uma comparação e analisar o resultado. Agora, a execução do git diff vai produzir o seguinte resultado:

diff --git a/diff_test.txt b/diff_test.txt
index 6b0c6cf..b37e70a 100644
--- a/diff_test.txt
+++ b/diff_test.txt
@@ -1 +1 @@
-this is a git diff test example
+this is a diff example

Vamos agora examinar uma análise com mais informações sobre o resultado da comparação.

1. Entrada da comparação

diff --git a/diff_test.txt b/diff_test.txt

Esta linha exibe as fontes de entrada da comparação. A gente pode ver que o a/diff_test.txt e o b/diff_test.txt foram aprovados para a comparação.

2. Meta dados

index 6b0c6cf..b37e70a 100644

Essa linha exibe alguns metadados internos do Git. Você com certeza não vai precisar dessas informações. Os números neste resultado correspondem aos identificadores de hash da versão do objeto Git.

3. Marcadores para alterações

--- a/diff_test.txt
+++ b/diff_test.txt

Essas linhas são uma legenda que atribui símbolos a cada fonte de entrada de comparação. Nesse caso, as alterações de a/diff_test.txt são marcadas com --- e as alterações de b/diff_test.txt são marcadas com o símbolo +++.

4. Fragmentos de comparação

O resultado restante da comparação é uma lista de "fragmentos" de comparação. Uma comparação exibe apenas as seções do arquivo que têm alterações. No exemplo atual, temos apenas um fragmento, pois estamos trabalhando com um cenário simples. Os fragmentos têm semântica granular de saída própria.

@@ -1 +1 @@
-this is a git diff test example
+this is a diff example

A primeira linha é o cabeçalho do fragmento. Cada fragmento é precedido por um cabeçalho inserido entre os símbolos @@. O conteúdo do cabeçalho é um resumo das alterações feitas no arquivo. No exemplo simplificado, temos -1 +1, significando que a linha um teve alterações. Em uma comparação mais realista, você veria um cabeçalho como:

@@ -34,6 +34,8 @@

Neste exemplo de cabeçalho, 6 linhas foram extraídas a partir da linha número 34. Além disso, 8 linhas foram adicionadas começando na linha número 34.

O conteúdo restante do fragmento de comparação exibe as alterações recentes. Cada linha alterada é anexada com um símbolo de + ou - indicando de qual versão da entrada de comparação as alterações vêm. Conforme discutimos anterior, o símbolo, - indica alterações do a/diff_test.txt e o + indica alterações do b/diff_test.txt.

Destacando as alterações

1. git diff --color-words

O git diff também tem um modo especial para destacar alterações com granularidade muito melhor: ‐‐color-words. Esse modo simboliza as linhas adicionadas e removidas por espaços em branco e depois as compara.

$:> git diff --color-words
diff --git a/diff_test.txt b/diff_test.txt
index 6b0c6cf..b37e70a 100644
--- a/diff_test.txt
+++ b/diff_test.txt
@@ -1 +1 @@
this is agit difftest example

Agora, o resultado exibe apenas as palavras codificadas por cores que foram alteradas.

2. destaque de comparação do git

Se você clonar a fonte do git, você vai encontrar um subdiretório chamado contrib. Ele contém várias ferramentas relacionadas ao git e outras informações interessantes que ainda não foram promovidos ao núcleo do git. Um deles é um script Perl chamado destaque da comparação. O destaque da comparação emparelha as linhas correspondentes do resultado da comparação e destaca os fragmentos de sub-palavras que foram alterados.

$:> git diff | /your/local/path/to/git-core/contrib/diff-highlight/diff-highlight
diff --git a/diff_test.txt b/diff_test.txt
index 6b0c6cf..b37e70a 100644
--- a/diff_test.txt
+++ b/diff_test.txt
@@ -1 +1 @@
-this is a git diff test example
+this is a diff example

Agora, reduzimos a comparação para a menor alteração possível.

Comparando arquivos binários

Além dos utilitários de arquivos de texto que demonstramos até agora, a git diff pode ser executada em arquivos binários. Por infelicidade, o resultado padrão não é muito útil.

$:> git diff
Binary files a/script.pdf and b/script.pdf differ

O Git tem um recurso que permite especificar um comando shell para transformar o conteúdo de arquivos binários em texto antes de executar a comparação. No entanto, é preciso configurar algumas coisas. Primeiro, você precisa especificar um filtro textconv descrevendo como converter um certo tipo de binário em texto. Estamos usando um utilitário simples chamado pdftohtml (disponível via Homebrew) para converter meus PDFs em HTML legível por humanos. Você pode usar a configuração de um único repositório editando o arquivo .git/config ou por inteiro por meio da edição de ~ /.gitconfig

[diff "pdfconv"]
textconv=pdftohtml -stdout

Então, tudo o que você precisa fazer é associar um ou mais padrões de arquivo ao filtro pdfconv. Você pode fazer essa configuração criando um arquivo .gitattributes na raiz do repositório.

*.pdf diff=pdfconv

Uma vez configurado, o git diff primeiro vai executar o arquivo binário através do script do conversor configurado e vai comparar o resultado do conversor. A mesma técnica pode ser aplicada para obter comparações úteis de todos os tipos de arquivos binários, por exemplo: zips, jars e outros arquivos: usar o unzip -l (ou similar) em vez do pdf2html vai mostrar os caminhos que foram adicionados ou removidos entre as imagens de commits: o exiv2 pode ser usado para mostrar alterações de metadados, como documentos de dimensões de imagem: existem ferramentas de conversão para transformar .odf, .doc e outros formatos de documento em texto sem formatação. Em último caso, as strings em geral funcionam para arquivos binários onde não existe um conversor formal.

Comparando arquivos: arquivo git diff

O comando git diff pode passar uma opção explícita do caminho do arquivo. Quando um caminho de arquivo é passado para o git diff, a operação de comparação vai ter o escopo definido no arquivo especificado. Os exemplos abaixo demonstram esse uso.

git diff HEAD ./path/to/file

Este exemplo tem como escopo o ./path/to/file quando solicitado, ele vai comparar as alterações específicas no diretório ativo, com o índice, mostrando as alterações que ainda não foram testadas. Por padrão, o git diff vai realizar a comparação com o HEAD. Omitindo HEAD no exemplo acima, o git diff ./path/to/file tem o mesmo efeito.

git diff --cached ./path/to/file

Quando o git diff é solicitado com a opção --cached, a comparação vai utilizar as alterações em etapas com o repositório local. A opção --cached é sinônimo de --staged.

Comparando todas as alterações

Solicitar o git diff sem um caminho de arquivo vai comparar as alterações em todo o repositório. Os exemplos específicos acima, do arquivo, podem ser solicitados sem o argumento ./path/to/file e têm os mesmos resultados de saída em todos os arquivos no repositório local.

Alterações desde o último commit

Por padrão, o git diff vai mostrar todas as alterações que não passaram por commit desde o último commit.

git diff

Comparando arquivos entre dois commits diferentes

O git diff pode passar de refs do Git para fazer commit da comparação. Alguns exemplos de refs são HEAD, marcadores e nomes de ramificações. Cada commit no Git tem um ID de commit que você pode obter quando executa o GIT LOG. Você também pode passar esse ID de commit para o git diff.

git log --prety=oneline
957fbc92b123030c389bf8b4b874522bdf2db72c add feature
ce489262a1ee34340440e55a0b99ea6918e19e7a rename some classes
6b539f280d8b0ec4874671bae9c6bed80b788006 refactor some code for feature
646e7863348a427e1ed9163a9a96fa759112f102 add some copy to body

$:> git diff 957fbc92b123030c389bf8b4b874522bdf2db72c ce489262a1ee34340440e55a0b99ea6918e19e7a

Comparando ramificações

Comparando duas ramificações

As ramificações são comparadas como todas as outras entradas ref no git diff

git diff branch1..other-feature-branch

Este exemplo apresenta o operador de ponto. Os dois pontos neste exemplo indicam que a entrada de comparação é a extremidade das duas ramificações. O mesmo efeito ocorre se os pontos forem omitidos e for usado um espaço entre as ramificações. Além disso, há um operador de três pontos:

git diff branch1...other-feature-branch

O operador de três pontos inicia a comparação alterando o primeiro parâmetro de entrada branch1. Ela altera o branch1 em um ref do commit ancestral comum compartilhado entre as duas entradas de comparação, o ancestral compartilhado do branch1 e a other-feature-branch. O último parâmetro de entrada do parâmetro permanece inalterado como a extremidade do other-feature-branch.

Comparando arquivos de outras ramificações

Para comparar um arquivo específico entre ramificações, aprove o caminho do arquivo como o terceiro argumento do git diff

git diff master new_branch ./diff_test.txt

Resumo

Esta página discutiu o processo de comparação do Git e o comando git diff. Discutimos como ler a saída git diff e os vários dados incluídos na saída. Foram viabilizados exemplos de como alterar a saída git diff com o destaque e cores das palavras. Discutimos várias estratégias de comparação, por exemplo, como comparar arquivos em ramificações e commits específicos. Além do comando git diff, usamos também o git log e o git checkout.

Pronto(a) para aprender Git?

Tente este tutorial interativo.

Comece agora mesmo