Como gerar um patch git para um commit específico?


1233

Preciso escrever um script que crie patches para uma lista de números de confirmação SHA1.

Eu tentei usar git format-patch <the SHA1>, mas isso gerou um patch para cada confirmação desde o SHA1. Depois que algumas centenas de patches foram geradas, tive que interromper o processo.

Existe uma maneira de gerar um patch apenas para o SHA1 específico?

Respostas:


1990

Tentar:

git format-patch -1 <sha>

ou

git format-patch -1 HEAD

De acordo com o link da documentação acima, o -1sinalizador informa ao git quantos commits devem ser incluídos no patch;

- <n>

     Prepare patches a partir das confirmações mais altas.


Aplique o patch com o comando:

git am < file.patch

211
Aplicando o patch: git apply --stat file.patch# show stats. git apply --check file.patch# verifique se há erros antes de aplicar. git am < file.patch# aplique o patch finalmente.
Adrian

3
Parece não funcionar se o último commit for uma mesclagem de outro branch.
Lex Li

2
Para aplicar o patch em arquivos usando terminações de linha CRLF:git am --keep-cr < mypatch.patch
Michael Schmeißer

40
Use git am -3 < file.patchpara aplicar usando uma mesclagem de três vias que permitirá resolver conflitos usando git mergetoolposteriormente (ou editando manualmente) encontrados aqui .
Matt

6
Este comando também funciona para apenas um arquivo específico (s) do commit: git format-patch -1 <sha> path/to/file.jsIsto irá criar um patch contendo apenas os diffs para os file.js
Kristóf Dombi

281

Para gerar os patches a partir dos commits superiores, a partir de um hash sha1 específico:

git format-patch -<n> <SHA1>

Os últimos 10 patches da cabeça em um único arquivo de patches:

git format-patch -10 HEAD --stdout > 0001-last-10-commits.patch

2
você pode por favor seja gentil o suficiente para fornecer um exemplo para o primeiro comando
Kasun Siyambalapitiya

1
git format-patch -1 HEADirá gerar patch para o mais recente comprometer
Sriram Murali

1
perdoem-me por perguntar isso, então quando é -2que geram manchas para a maioria dos últimos 2 commits é, e mais uma coisa para esclarecimentos é o comando got format-patch -2 HEADé o mesmo que a linhagit format-patch HEAD~2
Kasun Siyambalapitiya

85

Digamos que você tenha cometido o id 2 após o commit 1, você seria capaz de executar:

git diff 2 1 > mypatch.diff

onde 2 e 1 são hashes SHA.


Obrigado dookehster pela resposta. Isso significa que eu preciso do script para encontrar os commits que antecederam aqueles em que estou interessado. Eu esperava poder evitar isso.
elle

11
@elle, não, você não - git diff hash^ hash . o "hash ^" fornece o commit precedido. (mas, é claro, a resposta de manojlds é melhor)
J-16 SDiZ

2
git show HEAD > mypatch.diff enquanto você estiver no commit, deve fazer o mesmo.
andho

1
@dookehester está correto ou é o contrário,git diff 1 2
Kasun Siyambalapitiya

1
Isso não incluirá nenhum arquivo binário no diff.
stuckj

55

Este comando (como já sugerido por @ Naftuli Tzvi Kay ):

git format-patch -1 HEAD

Substitua HEADpor hash ou intervalo específico.

irá gerar o arquivo de correção para a confirmação mais recente formatada para se parecer com o formato da caixa de correio UNIX.

-<n> - Prepare os patches a partir dos commits mais altos.

Em seguida, você pode reaplicar o arquivo de patch em um formato de caixa de correio:

git am -3k 001*.patch

Veja: man git-format-patch.


Obrigado! Eu acho que vale a pena notar que a aplicação do patch criará uma confirmação com uma mensagem de confirmação prefixada por [PATCH]. Isso é fácil de corrigir, embora
Mike S

2
Fenomenal. OP, você não aceitou isso, porque ...? @MikeS Não, não funciona mais do que qualquer outro gitpatch formatado, pelo menos se o usuário o aplicar da maneira correta.
Underscore_d

2
@ MikeS Eu realmente não investiguei o porquê, mas deixar de fora a -kflag ( git am -3) me corrigiu esse formulário (sem PATCH[0/10]enviar mensagens). Git versão 2.20.1.windows.1
jannis

31
git format-patch commit_Id~1..commit_Id  
git apply patch-file-name

Solução rápida e simples.


5
Também não se esqueça de ligar git apply --check patch-file-nameantes de aplicar um patch. Isso ajudará a evitar problemas.
precisa saber é

16

Se você quiser ter certeza de que o patch (confirmação única) será aplicado sobre uma confirmação específica, use a nova opção git 2.9 (junho de 2016) git format-patch --base

git format-patch --base=COMMIT_VALUE~ -M -C COMMIT_VALUE~..COMMIT_VALUE

# or
git format-patch --base=auto -M -C COMMIT_VALUE~..COMMIT_VALUE

# or
git config format.useAutoBase true
git format-patch -M -C COMMIT_VALUE~..COMMIT_VALUE

Consulte commit bb52995 , commit 3de6651 , commit fa2ab86 , commit ded2c09 (26 de abril de 2016) por Xiaolong Ye (``) .
(Mesclado por Junio ​​C Hamano - gitster- na commit 72ce3ff , 23 de maio de 2016)

format-patch: adicionar '--base ' opção para registrar informações da árvore base

Mantenedores ou testadores de terceiros podem querer saber a árvore base exata à qual a série de patches se aplica. Ensinar git format-patch a '--base opção ' para registrar as informações da árvore base e anexá-las no final da primeira mensagem (a carta de apresentação ou o primeiro patch da série).

As informações da árvore base consistem no "commit de base", que é um commit conhecido que faz parte da parte estável do histórico do projeto em que todos os outros trabalham, e zero ou mais "patches de pré-requisito", conhecidos correções em andamento que ainda não fazem parte do "commit básico" que precisam ser aplicadas sobre o "commit básico" em ordem topológica antes que os patches possam ser aplicados.

O "commit base" é mostrado como " base-commit:" seguido pelo hexadecimal 40 do nome do objeto commit.
Um "patch de pré-requisito" é mostrado como " prerequisite-patch-id:" seguido pelo "id do patch" de 40 hexadecimais, que pode ser obtido passando o patch pelo git patch-id --stablecomando " ".


O Git 2.23 (terceiro trimestre de 2019) melhorará isso, porque a --baseopção " " de " format-patch" calculou os patch-idspatches de pré-requisito de maneira instável, que foi atualizada para calcular de forma compatível com " git patch-id --stable".

Veja commit a8f6855 , commit 6f93d26 (26 abr 2019) por Stephen Boyd ( akshayka) .
(Incorporado por Junio ​​C Hamano - gitster- in commit 8202d12 , 13 jun 2019)

format-patch: tornar a --base patch-idsaída estável

Não estávamos liberando o contexto toda vez que processamos um pedaço no patch-idcódigo de geração diff.c, mas estávamos fazendo isso quando geramos IDs de patch "estáveis" com a patch-idferramenta ' '.

Vamos portar essa lógica semelhante do patch-id.cpara, diff.cpara que possamos obter o mesmo hash quando estivermos gerando IDs de patch para format-patch --base=tipos de chamadas de comando.


Antes do Git 2.24 (quarto trimestre de 2019), " git format-patch -o <outdir>" fazia o equivalente a " mkdir <outdir>" não " mkdir -p <outdir>", que estava sendo corrigido.

Veja commit edefc31 (11 de out de 2019) de Bert Wesarg ( bertwesarg) .
(Incorporado por Junio ​​C Hamano - gitster- in commit f1afbb0 , 18 out 2019)

format-patch: criar componentes principais do diretório de saída

Assinado por: Bert Wesarg

'git format-patch -o' fez o equivalente a 'mkdir' e não 'mkdir -p', que está sendo corrigido.

Evite o uso de ' adjust_shared_perm' nos diretórios principais, que podem ter implicações de segurança. Conseguido desativando temporariamente o ' config.sharedRepository' like ' git init' faz.


Com o Git 2.25 (primeiro trimestre de 2020), " git rebase" não funcionou bem quandoformat.useAutoBase variável de configuração foi definida, o que foi corrigido.

Consulte commit cae0bc0 , commit 945dc55 , commit 700e006 , commit a749d01 , commit 0c47e06 (04 dez 2019) por Denton Liu ( Denton-L) .
(Incorporado por Junio ​​C Hamano - gitster- no commit 71a7de7 , 16 de dezembro de 2019)

rebase: corrigir format.useAutoBasequebra

Reportado por: Christian Biesinger
Assinado por: Denton Liu

Com format.useAutoBase = true, executar a rebase resultou em um erro:

fatal: failed to get upstream, if you want to record base commit automatically,
please use git branch --set-upstream-to to track a remote branch.
Or you could specify base commit by --base=<base-commit-id> manually
error:
git encountered an error while preparing the patches to replay
these revisions:

ede2467cdedc63784887b587a61c36b7850ebfac..d8f581194799ae29bf5fa72a98cbae98a1198b12

As a result, git cannot rebase them.

Corrija isso sempre passando --no-basepara o patch de formato a partir da rebase, para que o efeito de format.useAutoBaseseja negado.


8

Para gerar o caminho de uma confirmação específica (não a última confirmação):

git format-patch -M -C COMMIT_VALUE~1..COMMIT_VALUE

5

se você quiser apenas diferenciar o arquivo especificado, você pode:

git diff master 766eceb - connections /> 000-mysql-connector.patch


0

Com minha formação mercurial, eu usaria:

git log --patch -1 $ID > $file

Mas estou pensando em usar git format-patch -1 $IDagora.


-5

Qual é a maneira de gerar um patch apenas para o SHA1 específico?

É bem simples:

Opção 1. git show commitID > myFile.patch

Opção 2. git commitID~1..commitID > myFile.patch

Nota: Substitua commitIDpelo ID de confirmação real (código de confirmação SHA1).


3
A opção 1 é totalmente errada e não está relacionada à questão.
Anshuman Manral

3
A opção 2 também é um comando inválido. Você receberá um erro como: git a5f4bcaeb7fa7de27ae79d9522332e872889bbf0 ~ 1..a5f4bcaeb7fa7de27ae79d9522332e872889bbf0 git: 'a5f4bcaeb7fa7de27ae79d95223328287a7a7a7aaaaaaaaaaaa' Veja 'git --help'. Por favor, verifique antes de postar respostas
Anshuman Manral
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.