Crie um patch git a partir das alterações no diretório de trabalho atual

880

Digamos que tenho alterações não confirmadas no meu diretório de trabalho. Como posso fazer um patch daqueles sem ter que criar um commit?

vrish88
fonte
29
A resposta aceita provavelmente deve ser alterada, pois a segunda resposta é quase quatro vezes mais popular.
Tim Ogilvy
5
@TimOgilvy concordou. OP deve fazê-lo. Segunda resposta é muito mais popular e dá mais informações
John Demetriou
1
Eu acho que vale a pena mencionar que você também precisa de correções de alterações não confirmadas no título.
2i3r 04/02

Respostas:

401

git diffpara alterações sem etapas. git diff --cachedpara mudanças em etapas.

sigjuice
fonte
12
sim, git diff é o inverso do git apply #
Spike Gronim 01-01
33
git format-patchtambém inclui diferenças binárias e algumas informações meta. Na verdade, essa seria a melhor aposta para a criação de um patch, mas depois disso isso funciona apenas para fontes / alterações verificadas, certo?
Eric
20
Às vezes, pode ser útil criar um patch em relação ao diretório atual. Para conseguir isso, use git diff --relative
ejboy
30
git diff> a.patch para escrevê-lo para um arquivo
qasimzee
139
Contornando a fronteira sarcástica, a resposta abaixo é mais útil.
Air
1865

Se você ainda não confirmou as alterações, então:

git diff > mypatch.patch

Mas às vezes acontece que parte das coisas que você está fazendo são novos arquivos que não são rastreados e não estarão na sua git diffsaída. Portanto, uma maneira de fazer um patch é preparar tudo para um novo commit ( git addcada arquivo ou apenas git add .), mas não faça o commit e, em seguida:

git diff --cached > mypatch.patch

Adicione a opção 'binário' se desejar adicionar arquivos binários ao patch (por exemplo, arquivos mp3):

git diff --cached --binary > mypatch.patch

Posteriormente, você pode aplicar o patch:

git apply mypatch.patch

Nota: Você também pode usar --stagedcomo sinônimo de --cached.

jcarballo
fonte
128
Muito obrigado pelo exemplo. Ao contrário da resposta aceita, você mostra os comandos como fazê-lo e não apenas fala. Muito útil e trabalhou impecável para mim :)
Nuala
4
Fiz exatamente isso e obtive "fatal: entrada não reconhecida" ao executar o git apply. Alguma idéia do que pode causar isso e como corrigi-lo?
Vitaly
6
@ Vitaly: o seu patch pode ser lido se você o abrir com um editor de texto? deve estar limpo sem caracteres estranhos, por exemplo, se a configuração color.diff estiver definida, seu patch terá alguns 'caracteres coloridos' que podem fazer com que 'git apply' falhe, nesse caso, tente git diff --no-color. Caso contrário, parece um problema de codificação.
jcarballo
3
Relacionado a "novos arquivos que não são rastreados": "git diff" e "git diff --cached" funcionam apenas se "git add <file>" tiver sido chamado primeiro. (Eu sou novo para git e se perguntou por que eu tenho uma toda área vazia)
Anônimo
5
Isso me fez fora de uma estranha inferno merge / rebase muito facilmente, graças :)
John Hunt
86

git diffe git applyfuncionará para arquivos de texto, mas não funcionará para arquivos binários.

Você pode criar facilmente um patch binário completo, mas precisará criar uma confirmação temporária. Depois de fazer seu commit temporário, você pode criar o patch com:

git format-patch <options...>

Depois de fazer o patch, execute este comando:

git reset --mixed <SHA of commit *before* your working-changes commit(s)>

Isso reverterá suas confirmações temporárias. O resultado final deixa sua cópia de trabalho (intencionalmente) suja com as mesmas alterações que você teve originalmente.

No lado do recebimento, você pode usar o mesmo truque para aplicar as alterações na cópia de trabalho, sem ter o histórico de confirmação. Simplesmente aplique o (s) remendo (s) e git reset --mixed <SHA of commit *before* the patches>.

Observe que talvez você precise estar bem sincronizado para que toda essa opção funcione. Eu vi alguns erros ao aplicar patches quando a pessoa que os fazia não havia retirado tantas alterações quanto eu. Provavelmente existem maneiras de fazê-lo funcionar, mas eu não olhei muito para isso.


Veja como criar os mesmos patches no Tortoise Git (não que eu recomendo usar essa ferramenta):

  1. Confirme suas alterações de trabalho
  2. Clique com o botão direito do mouse no diretório raiz da ramificação e clique em Tortoise Git->Create Patch Serial
    1. Escolha o intervalo que fizer sentido ( Since: FETCH_HEADfuncionará se você estiver bem sincronizado)
    2. Crie os patches
  3. Clique com o botão direito do mouse no diretório raiz da ramificação e clique em Tortise Git->Show Log
  4. Clique com o botão direito do mouse no commit antes do seu commit temporário e clique emreset "<branch>" to this...
  5. Selecione a Mixedopção

E como aplicá-los:

  1. Clique com o botão direito do mouse no diretório raiz da ramificação e clique em Tortoise Git->Apply Patch Serial
  2. Selecione os patches corretos e aplique-os
  3. Clique com o botão direito do mouse no diretório raiz da ramificação e clique em Tortise Git->Show Log
  4. Clique com o botão direito do mouse na confirmação antes da confirmação do patch e clique emreset "<branch>" to this...
  5. Selecione a Mixedopção
Merlyn Morgan-Graham
fonte
5
Tecnicamente, isso requer a criação de uma confirmação que o OP pediu para evitar, mas é temporária e a resposta é útil, independentemente.
Davidpcj
33

Para criar um patch com os arquivos novos e modificados (em etapas), você pode executar:

git diff HEAD > file_name.patch
Ionel Sirbu
fonte
Obrigado, no meu caso, esta resposta funciona, mas git diff --cached > mypatch.patchnão está funcionando.
mining
Eu tenho uma pergunta: pode file_name.patchser usado pelo patchcomando? Eles são compatíveis um com o outro?
Rakshith Ravi 04/04/19
git diff + git diff --cached / staged == git diff HEAD (mostra todas as alterações desde o último commit)
K. Symbol
20

Eu gosto:

git format-patch HEAD~<N>

onde <N>é o número do último commit para salvar como patches.

Os detalhes de como usar o comando estão no DOC

UPD
Aqui você pode encontrar como aplicá-los.

UPD Para quem não teve a ideia de format-patch
Adicionar alias:

git config --global alias.make-patch '!bash -c "cd ${GIT_PREFIX};git add .;git commit -m ''uncommited''; git format-patch HEAD~1; git reset HEAD~1"'

Em qualquer diretório do repositório do projeto, execute:

git make-patch

Este comando será criado 0001-uncommited.patchno seu diretório atual. O patch conterá todas as alterações e arquivos não rastreados visíveis para o próximo comando:

git status .
Eugen Konkov
fonte
@ jcarballo: Eu atualizei a resposta. Sinta-se à vontade para me enviar quaisquer avisos que você tiver.
Eugen Konkov
2
Há uma maneira mais simples do que criar uma confirmação e não comprometer. git diff --cached --binary
Gaurav Agarwal
9

Se você deseja fazer binário, dê uma --binaryopção ao executar git diff.

gitster
fonte
0

Também podemos especificar os arquivos, para incluir apenas os arquivos com alterações relativas, principalmente quando eles abrangem vários diretórios ex

git diff ~/path1/file1.ext ~/path2/file2.ext...fileN.ext > ~/whatever_path/whatever_name.patch

Achei que isso não estava especificado nas respostas ou nos comentários, que são relevantes e corretos, então decidi adicioná-lo. Explícito é melhor que implícito!

Anshu Kumar
fonte