Básico de diff e patch - Gerando e Aplicando Diferenças

Básico de diff e patch - Gerando e Aplicando Diferenças

O Que Você Vai Aprender

  • Como comparar dois arquivos com diff e interpretar a saída
  • Como interpretar o formato unified diff (diff -u)
  • Como aplicar um arquivo de patch com patch
  • Como reverter um patch com patch -R

Resumo Rápido

  • Ver diff: diff -u arquivo_antigo arquivo_novo
  • Salvar patch: diff -u arquivo_antigo arquivo_novo > changes.patch
  • Aplicar patch: patch -p0 < changes.patch
  • Reverter patch: patch -R -p0 < changes.patch

Pré-requisitos

  • SO: Ubuntu ou qualquer distribuição Linux
  • diff e patch já vêm instalados por padrão na maioria dos sistemas Linux

O Que é o diff?

diff compara dois arquivos linha por linha e mostra o que mudou entre eles. É usado diariamente para revisar alterações em código-fonte, comparar arquivos de configuração com backups e gerar arquivos de patch para distribuição.

Como Usar o diff

Comparação Básica

$ diff old.txt new.txt

Se não houver diferenças, nada é impresso. Quando há diferenças, a saída no formato "normal" padrão se parece com isto:

2c2
< conteudo antigo
---
> conteudo novo

O formato normal é difícil de ler e não é adequado para o patch. Use o formato unificado em vez disso.

Formato Unificado (-u)

A opção -u produz saída em formato unificado, o formato padrão para arquivos de patch.

$ diff -u old.txt new.txt

Exemplo de saída:

--- old.txt	2026-06-01 10:00:00.000000000 +0000
+++ new.txt	2026-06-01 10:05:00.000000000 +0000
@@ -1,5 +1,5 @@
 line1 (unchanged)
-old line2
+new line2
 line3 (unchanged)

Como interpretar:

Símbolo Significado
--- Arquivo original (antes)
+++ Arquivo modificado (depois)
@@ Cabeçalho do hunk com números de linha
- Linha removida
+ Linha adicionada
(espaço) Linha de contexto (sem alteração)

O cabeçalho do hunk @@ -1,5 +1,5 @@ significa: começando na linha 1, mostrando 5 linhas do arquivo antigo / 5 linhas do arquivo novo. Três linhas de contexto antes e depois de cada alteração são incluídas por padrão.

Comparação Recursiva de Diretórios (-r)

Use -r com -u para comparar árvores de diretórios inteiras:

$ diff -ur dir_old/ dir_new/

Cada arquivo alterado aparece como um bloco unified diff separado na saída.

Opções Úteis do diff

Opção Descrição
-u Formato unificado (necessário para patch)
-r Recursivo (comparar diretórios)
-i Ignorar diferenças de maiúsculas/minúsculas
-w Ignorar todos os espaços em branco
-b Ignorar alterações na quantidade de espaços
--color Colorir a saída (GNU diff)

Salvando o Diff em um Arquivo de Patch

Redirecione a saída do diff para um arquivo:

# Arquivo unico
$ diff -u original.txt modified.txt > changes.patch

# Diretorio inteiro
$ diff -ur dir_old/ dir_new/ > project.patch

Este arquivo é o que você passa para o patch ao aplicar as alterações.

O Que é o patch?

patch recebe um arquivo diff produzido pelo diff e aplica essas alterações a um arquivo ou diretório alvo. É assim que correções de bugs e patches de segurança são distribuídos em software de código aberto: o mantenedor executa diff, envia o arquivo .patch, e os usuários executam patch para aplicá-lo.

Como Usar o patch

Entendendo o Nível de Remoção -p

A opção -p controla quantos componentes iniciais do caminho devem ser removidos dos nomes de arquivos dentro do cabeçalho do patch.

--- a/src/config.txt    ← com -p1, interpretado como "src/config.txt"
+++ b/src/config.txt
Opção Comportamento
-p0 Usar o caminho completo como está
-p1 Remover um componente inicial (remove a/ ou b/)

Patches gerados pelo Git sempre incluem os prefixos a/ e b/, então -p1 é a escolha mais comum para patches do Git. Para patches criados com diff -u simples (sem prefixo), use -p0.

Dry Run Primeiro

Sempre faça uma prévia antes de aplicar:

$ patch --dry-run -p0 < changes.patch

--dry-run verifica se o patch pode ser aplicado sem problemas sem modificar nenhum arquivo. Se não reportar erros, prossiga com a aplicação real.

Aplicando um Patch

Para patches criados com diff -u (simples, sem prefixo a//b/):

$ patch -p0 < changes.patch

Para patches gerados pelo Git ou patches com prefixos a//b/:

$ patch -p1 < project.patch

Se o patch reportar "Hunk FAILED", o patch não corresponde ao estado atual do arquivo alvo. O arquivo pode já ter sido patcheado ou foi modificado independentemente. Use --dry-run para diagnosticar antes de tentar.

Rejeição de Hunks

Quando um hunk falha, o patch grava as partes rejeitadas em um arquivo .rej (ex.: config.txt.rej). Inspecione-o para aplicar as alterações manualmente.

Revertendo um Patch

A flag -R reverte um patch, aplicando-o desfaz a alteração original:

$ patch -R -p0 < changes.patch

# Patch em formato Git
$ patch -R -p1 < project.patch

Reverter requer que as linhas de contexto no patch ainda correspondam ao arquivo alvo. Se o arquivo foi alterado após o patch ter sido aplicado, a reversão pode falhar ou produzir resultados incorretos.

Fluxos de Trabalho Práticos

Compartilhando uma Alteração em Arquivo de Configuração

# 1. Salvar o original
$ cp nginx.conf nginx.conf.orig

# 2. Editar o arquivo
$ vim nginx.conf

# 3. Gerar o patch
$ diff -u nginx.conf.orig nginx.conf > nginx-fix.patch

# 4. Destinatario aplica o patch
$ patch --dry-run -p0 < nginx-fix.patch
$ patch -p0 < nginx-fix.patch

Aplicando um Patch de Código Aberto

# Executar a partir do diretorio raiz do projeto
$ patch --dry-run -p1 < bugfix.patch
$ patch -p1 < bugfix.patch

# Desfazer se algo der errado
$ patch -R -p1 < bugfix.patch

Gerando um Patch Compatível com Git

Ao trabalhar em um repositório Git, git diff produz uma saída que o patch -p1 pode consumir diretamente:

$ git diff > my-changes.patch
$ patch -p1 < my-changes.patch

Para alterações já commitadas, git format-patch é mais apropriado pois preserva os metadados do commit.

Resumo

Comando Propósito
diff -u old new Mostrar diff unificado
diff -ur dir1/ dir2/ Comparar diretórios recursivamente
diff -u old new > fix.patch Gerar um arquivo de patch
patch --dry-run -p0 < fix.patch Prévia da aplicação do patch
patch -p0 < fix.patch Aplicar patch (formato simples)
patch -p1 < fix.patch Aplicar patch (formato Git)
patch -R -p0 < fix.patch Reverter um patch

Modelos para Copiar e Colar

# Gerar patch
diff -u original.txt modified.txt > changes.patch

# Previa
patch --dry-run -p0 < changes.patch

# Aplicar
patch -p0 < changes.patch

# Reverter
patch -R -p0 < changes.patch

Próximas Leituras