Como usar o git merge --squash?


1209

Eu tenho um servidor Git remoto, aqui está o cenário que eu quero executar:

  • Para cada bug / recurso, crio um ramo Git diferente

  • Continuo confirmando meu código nesse ramo do Git com mensagens não oficiais do Git

  • No repositório superior, precisamos fazer um commit para um bug com a mensagem oficial do Git

Então, como posso mesclar minha ramificação para ramificação remota para que eles obtenham apenas uma confirmação para todos os meus check-ins (eu quero fornecer uma mensagem de confirmação para isso)?


1
Não sei se entendi completamente você, mas você pode querer uma "fusão de polvos".
MatrixFrog

27
Normalmente, uso o git rebase -i para recolher todos os meus commits em um commit e reescrever a mensagem de commit. Então eu envio a montante.
Edward Falk

17
git merge --squashfaz tudo na linha de comando de uma só vez e você só espera que funcione. git rebase -iabre um editor e permite ajustar a rebase. É mais lento, mas você pode ver o que está fazendo. Além disso, há diferenças entre rebase e mesclagem que são um pouco envolvidas demais para serem abordadas em um comentário.
Edward Falk

4
o problema com todas essas respostas é que você precisa estar no ramo mestre localmente e executar o comando merge --squash ... Quero executar o merge --squash no ramo de recursos e não no ramo mestre ... para que quando terminar, posso enviar a ramificação do recurso para o controle remoto e enviar um PR, isso é possível?
Alexander Mills

2
@AlexanderMills, acho que você só precisa de um segundo ramo de recurso (clonado no ramo mestre). Faça o merge --squashdo antigo para o novo e mescle o novo ramo para dominar. O antigo ramo se torna obsoleto.
Gyromite 28/03

Respostas:


2002

Digamos que seu ramo de correção de bugs seja chamado bugfixe você deseja mesclá-lo em master:

git checkout master
git merge --squash bugfix
git commit

Isso pegará todos os commits do bugfixbranch, esmagará-os em 1 commit e os mesclará com o masterbranch.


Explicação :

git checkout master

Muda para o seu masterramo.

git merge --squash bugfix

Retira todas as confirmações da bugfixramificação e a mescla com sua ramificação atual.

git commit

Cria um único commit a partir das alterações mescladas.

Omitir o -mparâmetro permite modificar uma mensagem de confirmação de rascunho que contém todas as mensagens de suas confirmações esmagadas antes de finalizar sua confirmação.


222
Se você deseja manter referências às antigas mensagens de confirmação, você pode escrever git commit(sem -mparam) e poderá modificar uma mensagem de confirmação elaborada contendo todas as mensagens de confirmação que você esmagou.
Alex8/

12
Você pode conseguir o mesmo fazendo git commit --amend -m '...'mais tarde.
Janusz Lenar

19
Caso ocorram conflitos de mesclagem e você os resolva, git commitnão mostrará mais a útil mensagem de confirmação contendo todas as mensagens de confirmação que você esmagou. Nesse caso, tente git commit --file .git/SQUASH_MSG(via stackoverflow.com/a/11230783/923560 ).
Abdull

23
Lembre-se de que a compressão, por padrão, atribui as confirmações ao squasher . Para manter o autor original, você precisa especificá-lo explicitamente da seguinte forma:git commit -a --author="Author" --message="Issue title #id"
gaborous

5
git merge --squashpermite criar uma única confirmação em cima da ramificação atual, cujo efeito é o mesmo que mesclar outra ramificação. Mas ele não produzirá o registro de mesclagem, o que significa que sua solicitação de recebimento como resultado não teria alterações, mas não será marcada como mesclada! Portanto, você precisará apenas excluir o ramo a ser executado.
Am0wa

129

O que finalmente esclareceu isso para mim foi um comentário mostrando que:

git checkout main
git merge --squash feature

é o equivalente a fazer:

git checkout feature
git diff main > feature.patch
git checkout main
patch -p1 < feature.patch
git add .

Quando eu quero mesclar um ramo de recurso com confirmações 105 (!!) e colocá-los todos compactados em um, não quero git rebase -i origin/master porque preciso resolver separadamente conflitos de mesclagem para cada confirmação intermediária (ou pelo menos as que o git não consegue descobrir por si mesmo). Usar git merge --squashme dá o resultado que eu quero de um único commit para mesclar um ramo de recurso inteiro. E, eu só preciso fazer no máximo uma resolução manual de conflitos.


75
Eu sugiro realizar a mesclagem no ramo de recursos primeiro git merge mastere somente depois git merge --squash featureno ramo mestre.
dotancohen 10/09/14

8
@dotancohen Desculpe por cavar um comentário antigo :) O que é ganho com a fusão no ramo de recursos antes de executar git merge --squash featureno ramo mestre?
bitsmack

57
Você deseja mesclar o mestre no ramo de recursos primeiro e lidar com as correções manuais em seu ramo de recursos. Isso também permite que você execute testes e verifique se o ramo de recursos funciona corretamente. Então, você tem a garantia de que pode fazer uma mesclagem automática da ramificação de recursos no mestre.
Dan Kohn

4
@dankohn Eu sugiro que você adicione a explicação no seu comentário acima na sua resposta.
guntbert

3
@bitsmack: você mesclaria o mestre no recurso primeiro. Isto dar-lhe a oportunidade de resolver conflitos sobre o recurso antes de se fundir o recurso para mestre
Mike

97

Você deseja mesclar com a opção squash. Ou seja, se você quiser fazer um ramo por vez.

git merge --squash feature1

Se você deseja mesclar todas as ramificações ao mesmo tempo que as confirmações únicas, primeiro rebase de forma interativa e esmague cada recurso e, em seguida, junte polvo:

git checkout feature1
git rebase -i master

Squash em um commit e repita para os outros recursos.

git checkout master
git merge feature1 feature2 feature3 ...

Essa última mesclagem é uma "mesclagem de polvo" porque está mesclando muitos ramos ao mesmo tempo.

Espero que isto ajude


3
Por que você está rebaseando?
Umair A.

12
O @UmairAshraf é um rebase interativo que oferece a opção de fazer uma abóbora dentro de sua filial.
andho

1
Rebasing é uma má ideia. Não rebase os commits já publicados #
Sebi2020 16/16

1
@ Sebi2020 git merge --squash rebase seus commits já publicados de uma maneira que é pior do que uma rebase interativa. Um rebase interativo (em uma ramificação de recursos) traz pouco ou nenhum efeito adverso.
Xiix 5/03/19

1
@xiix Isso é válido apenas se você for o único que trabalha com o ramo de recursos. Esta não é uma suposição que você pode fazer. Eu recomendo ler as páginas relacionadas ao rebasing no Git-SCM . Ele declara " Não refazer a consolidação de confirmações que existem fora do seu repositório e as pessoas podem ter baseado em trabalho nelas. " natureza do git) você não deve fazer isso.
precisa saber é o seguinte

23

Se você já tem git merge bugfixem main, você pode esmagar sua mala comprometer em um com:

git reset --soft HEAD^1
git commit

git reset --soft HEAD^1parece desfazer a última confirmação executada antes da mesclagem, pelo menos no caso de a mesclagem ser um avanço rápido.
Jesper Matthiesen

@JesperMatthiesen no caso de um avanço rápido, você não recebe um commit de mesclagem, então você faria git reset --soft HEAD^<number-of-commits-to-squash>.
Qwertzguy

Isso me ajudou a compactar tudo em um único commit após uma mesclagem downstream.
killjoy

18

Mesclar newFeatureramificação mastercom uma confirmação personalizada:

git merge --squash newFeature && git commit -m 'Your custom commit message';

Se sim, você faz

git merge --squash newFeature && git commit

você receberá uma mensagem de confirmação que incluirá todas as newFeatureconfirmações de ramificação, que você pode personalizar.

Explico-o aqui: https://youtu.be/FQNAIacelT4


10

Sei que esta pergunta não é especificamente sobre o Github, mas como o Github é tão amplamente usado e esta é a resposta que eu estava procurando, vou compartilhá-la aqui.

O Github tem a capacidade de realizar mesclagens de squash, dependendo das opções de mesclagem ativadas para o repositório.

Se a mesclagem de squash estiver ativada, a opção "Squash e mesclagem" deve aparecer no menu suspenso no botão "Mesclar".

Captura de tela do recurso Github "Squash e mesclagem"


O GitHub usa o email padrão associado à sua conta. Se você tiver vários endereços de email e precisar usar um secundário, não poderá usar a interface do usuário do GH.
Luca Guidi

4

Suponha que você trabalhou no recurso / tarefa1 com várias confirmações.

  1. Vá para o ramo do seu projeto (projeto / meu_projeto)

    git checkout project/my_project
    
  2. Crie uma nova ramificação (feature / task1_bugfix)

    git checkout -b feature/task1_bugfix
    
  3. Marge com a --squashopção

    git merge --squash feature/task1
    
  4. Crie uma única confirmação

    git commit -am "add single comments"
    
  5. Empurre seu ramo

    git push --set-upstream origin feature/task1_bugfix
    

1

Para Git

Crie um novo recurso

via Terminal / Shell:

git checkout origin/feature/<featurename>
git merge --squash origin/feature/<featurename>

Isso não confirma, permite que você revise primeiro.

Em seguida, confirme e finalize o recurso desse novo ramo e exclua / ignore o antigo (o que você fez no desenvolvimento).


@ Melebius A única referência a "SourceTree" está na sua frase, se fosse uma tag ou uma pergunta anterior: ela não existe mais.
Jordan Stefanelli

1
O @JordanStefanelli SourceTree foi usado na versão original desta resposta . Obrigado por notificar que está consertado!
Melebius 13/02/19

1

se você receber um erro: Não é possível confirmar porque você possui arquivos não mesclados.

git checkout master
git merge --squash bugfix
git add .
git commit -m "Message"

corrigido todos os arquivos de conflito

git add . 

você também pode usar

git add [filename]

0

Para esmagar sua filial local antes de pressioná-la:

  1. faça o check-out da filial em questão para trabalhar, se ainda não estiver em check-out.

  2. Encontre o sha do commit mais antigo que você deseja manter.

  3. Crie / efetue o check-out de uma nova ramificação (tmp1) a partir dessa confirmação.

    git checkout -b tmp1 <sha1-of-commit>

  4. Mesclar o ramo original no novo esmagamento.

    git merge --squash <original branch>

  5. Confirme as alterações que foram criadas pela mesclagem, com uma mensagem de confirmação resumida.

    git commit -m <msg>

  6. Faça o checkout do ramo original que você deseja esmagar.

    git checkout <branch>

  7. Redefina para o commit original que você deseja manter.

    git reset --soft <sha1>

  8. Rebase esse ramo com base no novo ramo tmp1.

    git rebase tmp1

  9. É isso aí - agora exclua o ramo tmp1 temporário quando tiver certeza de que está tudo bem.


0

Você pode usar a ferramenta que eu criei para facilitar esse processo: git-squash . Por exemplo, para esmagar todas as confirmações na ramificação de recurso ramificada da ramificação principal, escreva:

git squash master
git push --force
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.