Como você squash se compromete em um patch com o git format-patch?


163

Tenho oito commits em um ramo que gostaria de enviar por e-mail para algumas pessoas que ainda não estão esclarecidas. Até agora, tudo o que faço me fornece 8 arquivos de patch ou começa a fornecer arquivos de patch para todos os commit no histórico do ramo, desde o início dos tempos. Usei o git rebase --interactive para esmagar os commits, mas agora tudo o que tento me dá zilhões de patches desde o início dos tempos. O que estou fazendo de errado?

git format-patch master HEAD # yields zillions of patches, even though there's 
                             # only one commit since master

Estou curioso sobre o método que você acabará usando entre as proposições abaixo. Deixe-nos saber;)
VonC

4
Usarei o git diff como sugerido por Rob Di Marco. Mas estou fora do trabalho por duas semanas, tendo testemunhado o nascimento da minha segunda filha na noite passada, então levará algum tempo antes de usá-la! :) #
3188 skiphoppy

2
Eu adoraria ver git formato-patch --squash mestre CABEÇA
schoetbi

1
Tente master..HEAD para especificar um intervalo de rotação.
21978 Konrad Kleine

Respostas:


186

Eu recomendo fazer isso em um ramo descartável da seguinte maneira. Se seus commits estão na ramificação "newlines" e você já voltou para a ramificação "master", isso deve fazer o truque:

[adam@mbp2600 example (master)]$ git checkout -b tmpsquash
Switched to a new branch "tmpsquash"

[adam@mbp2600 example (tmpsquash)]$ git merge --squash newlines
Updating 4d2de39..b6768b2
Fast forward
Squash commit -- not updating HEAD
 test.txt |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

[adam@mbp2600 example (tmpsquash)]$ git commit -a -m "My squashed commits"
[tmpsquash]: created 75b0a89: "My squashed commits"
 1 files changed, 2 insertions(+), 0 deletions(-)

[adam@mbp2600 example (tmpsquash)]$ git format-patch master
0001-My-squashed-commits.patch

Espero que isto ajude!


2
É isso que eu uso quando quero manter o histórico localmente (caso precise editar o patch). Caso contrário, eu apenas uso rebase -i e esmago os commits.
sebnow 9/03/09

5
para mim, ele trabalhou mais confiável com git comit -m "My squashed commits"caso contrário, seria adicionar outros arquivos untracked
Sebastian

Additonally, você pode mudar para um commit específico em vez do master e fazer isso para criar um patch de commit para commit:git checkout 775ec2a && git checkout -b patch && git merge --squash branchname
Berry M.

131

Apenas para adicionar mais uma solução ao pote: Se você usar isso:

git format-patch master --stdout > my_new_patch.diff

Ainda haverá 8 patches ... mas todos eles estarão em um único arquivo de patches e serão aplicados como um:

git am < my_new_patch.diff

13
Eu gosto desta solução. Vale ressaltar que às vezes pode criar um patch muito maior do que o método descrito por @Adam Alexander. Isso ocorre porque alguns arquivos podem ser editados mais de uma vez através de confirmações. Este método trata cada confirmação separadamente, mesmo que algum arquivo tenha sido revertido. Mas na maioria das vezes isso não é um problema.
Gmik

1
Essa opção é ótima se você está tentando evitar a fusão! (por exemplo, você deseja pular algumas confirmações). Você ainda pode git rebase -i ...esmagá-las e reduzi-las a uma.
Jorge Orpinel

21

Eu sempre uso git diff, então no seu exemplo, algo como

git diff master > patch.txt

15
Exceto que você perde todas as mensagens e metadados de confirmação. A beleza do patch de formato git é que é possível reconstruir todo o ramo a partir de um conjunto de patches.
mcepl

o método de criar-branch-and-abóbora tem a vantagem de combinar todas as mensagens comprometer em um, mas este método é muito mais rápido se você quer escrever sua própria mensagem de commit
woojoo666

na verdade, numa mensagem combinada, pode ser feito usando git log, veja a minha resposta para um exemplo
woojoo666

2
Boa opção, mas considere que 'git diff' não pode incluir diferenças binárias (talvez haja uma opção para fazê-lo).
Santiago Villafuerte 16/02

18

Esta é uma adaptação da resposta de Adam Alexander, caso suas alterações estejam no ramo principal. Faça o seguinte:

  • Cria um novo ramo descartável "tmpsquash" a partir do ponto que queremos (procure a chave SHA executando "git --log" ou com gitg. Selecione o commit que você deseja que seja o cabeça do tmpsquash, os commits que estão depois do master serão o squash comete).
  • Mescla as alterações do mestre para o tmpsquash.
  • Confirma as alterações esmagadas no tmpsquash.
  • Cria o patch com as confirmações esmagadas.
  • Volta ao ramo principal

laura@rune:~/example (master)$ git branch tmpsquash ba3c498878054e25afc5e22e207d62eb40ff1f38
laura@rune:~/example (master)$ git checkout tmpsquash
Switched to branch 'tmpsquash'
laura@rune:~/example (tmpsquash)$ git merge --squash master
Updating ba3c498..40386b8
Fast-forward
Squash commit -- not updating HEAD

[snip, changed files]

11 files changed, 212 insertions(+), 59 deletions(-)
laura@rune:~/example  (tmpsquash)$ git commit -a -m "My squashed commits"
[test2 6127e5c] My squashed commits
11 files changed, 212 insertions(+), 59 deletions(-)
laura@rune:~/example  (tmpsquash)$ git format-patch master
0001-My-squashed-commits.patch
laura@rune:~/example  (tmpsquash)$ git checkout master
Switched to branch 'master'
laura@rune:~/example  (master)$

Fazer alterações no mestre é um anti-padrão se você não forçar o controle remoto. E se você quiser, provavelmente não precisará gerar arquivos de correção para eles.
precisa saber é o seguinte

18

Como você já sabe, a git format-patch -8 HEADfornecerá oito patches.

Se você deseja que seus 8 commits apareçam como um e não se importe em reescrever o histórico de sua ramificação ( o-o-X-A-B-C-D-E-F-G-H), você pode:

git rebase -i
// squash A, B, C, D, E ,F, G into H

ou, e seria uma solução melhor, repita todas as suas 8 confirmações de X(a confirmação antes de suas 8 confirmações) em uma nova ramificação

git branch delivery X
git checkout delivery
git merge --squash master
git format-patch HEAD

Dessa forma, você só tem um commit na ramificação "delivery" e representa todos os seus últimos 8 commits


git merge masterapenas faz um avanço rápido e não se esmaga em um. Altere para git merge --squash masterobter todos os commits compactados e visíveis na área preparada. Seu fluxo funcionará com essa alteração. (Estou usando git versão 2.1.0.)
Stunner

5

Patch de formato entre duas tags:

git checkout <source-tag>
git checkout -b <tmpsquash>
git merge --squash <target-tag>
git commit -a -m "<message>"
git format-patch <source-tag>

5

A maneira mais fácil é usar git diffe adicionar git logse você quiser a mensagem de confirmação combinada que o método squash produziria. Por exemplo, para criar o patch entre commit abcde 1234:

git diff abcd..1234 > patch.diff
git log abcd..1234 > patchmsg.txt

Então, ao aplicar o patch:

git apply patch.diff
git add -A
git reset patch.diff patchmsg.txt
git commit -F patchmsg.txt

Não se esqueça do --binaryargumento ao git difflidar com arquivos que não são de texto, como imagens ou vídeos.


0

Com base na resposta de Adam Alexander:

git checkout newlines
## must be rebased to master
git checkout -b temporary
# squash the commits
git rebase -i master
git format-patch master
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.