No git, qual é a diferença entre mesclagem - squash e rebase?

363

Eu sou novo no git e estou tentando entender a diferença entre squash e rebase. Pelo que entendi, você executa uma abóbora ao fazer um rebase.

GiH
fonte

Respostas:

360

Ambos git merge --squashe git rebase --interactivepodem produzir um commit "esmagado".
Mas eles servem a propósitos diferentes.

produzirá uma confirmação compactada na ramificação de destino, sem marcar nenhum relacionamento de mesclagem.
(Nota: ele não produz um commit imediatamente: você precisa de um adicional git commit -m "squash branch")
Isso é útil se você deseja descartar completamente o ramo de origem, saindo de (esquema retirado da pergunta do SO ):

 git checkout stable

      X                   stable
     /                   
a---b---c---d---e---f---g tmp

para:

git merge --squash tmp
git commit -m "squash tmp"

      X-------------------G stable
     /                   
a---b---c---d---e---f---g tmp

e excluindo tmpramificação.


Nota: git mergetem uma --commitopção , mas não pode ser usada com --squash. Nunca foi possível usar --commite --squashjuntos.
Desde o Git 2.22.1 (terceiro trimestre de 2019), essa incompatibilidade é explicitada:

Veja commit 1d14d0c (24 de maio de 2019) por Vishal Verma ( reloadbrain) .
(Incorporado por Junio ​​C Hamano - gitster- in commit 33f2790 , 25 de jul de 2019)

merge: recusar --commitcom--squash

Anteriormente, quando --squashera fornecido ' option_commit', era silenciosamente descartado. Isso pode ter sido surpreendente para um usuário que tentou substituir o comportamento de não confirmação da squash usando --commitexplicitamente.

git/git builtin/merge.c#cmd_merge() agora inclui:

if (option_commit > 0)
    die(_("You cannot combine --squash with --commit."));

repete alguns ou todos os seus commits em uma nova base, permitindo que você esmague (ou mais recentemente "conserte", consulte esta pergunta SO ), indo diretamente para:

git checkout tmp
git rebase -i stable

      stable
      X-------------------G tmp
     /                     
a---b

Se você optar por esmagar todos os commits de tmp(mas, ao contrário de merge --squash, poderá repetir alguns e esmagar outros).

Então as diferenças são:

  • squashnão toca na ramificação de origem ( tmpaqui) e cria um único commit onde você deseja.
  • rebasepermite que você continue no mesmo ramo de origem (ainda tmp) com:
    • uma nova base
    • uma história mais limpa
VonC
fonte
11
Gé c--d--e--f--gesmagado junto?
Wayne Conrad
8
@Wayne: sim, G nesses exemplos representa os tmpcommits compactados juntos.
VonC 11/03/10
3
@ Th4wn: Como o Git raciocina com os instantâneos de um projeto all, Gnão representará o mesmo conteúdo que g, devido às alterações introduzidas por X.
VonC 23/05
11
@VonC: não tenho certeza sobre esse último comentário. Se você tem um em git merge --no-ff tempvez de git merge --squash temp, obtém uma história mais confusa, mas também pode fazer coisas como git revert e, com muito mais facilidade. É uma história confusa, mas honesta e pragmática, e o ramo principal ainda permanece bastante limpo.
naught101
2
@ naught101 eu concordo. Conforme explicado em stackoverflow.com/a/7425751/6309 , porém, também se trata de não quebrar git bisectou git blamequando usado com muita frequência (como em git pull --no-ff: stackoverflow.com/questions/12798767/… ). Não há uma abordagem de qualquer maneira, é por isso que este artigo descreve três ( stackoverflow.com/questions/9107861/... )
VonC
183

Mesclar confirmações: retém todas as confirmações em sua ramificação e as intercala com confirmações na ramificação baseinsira a descrição da imagem aqui

Merge Squash: retém as alterações, mas omite o indivíduo confirma o histórico insira a descrição da imagem aqui

Rebase: move a ramificação inteira do recurso para começar na ponta da ramificação principal, incorporando efetivamente todas as novas confirmações no mestre

insira a descrição da imagem aqui

Mais aqui

Md Ayub Ali Sarker
fonte
81

O squash de mesclagem mescla uma árvore (uma sequência de confirmações) em uma única confirmação. Ou seja, esmaga todas as alterações feitas em n confirma em um único commit.

Rebasear é basear novamente, ou seja, escolher uma nova base (confirmação pai) para uma árvore. Talvez o termo mercurial para isso seja mais claro: eles chamam de transplante porque é exatamente isso: escolher um novo terreno (confirmação dos pais, raiz) para uma árvore.

Ao fazer uma nova reformulação interativa, você terá a opção de esmagar, selecionar, editar ou pular as confirmações que você irá refazer.

Espero que isso esteja claro!

Mauricio Scheffer
fonte
7
Quando devo me refazer e quando devo esmagar?
Martin Thoma
31

Vamos começar pelo seguinte exemplo:

insira a descrição da imagem aqui

Agora temos 3 opções para mesclar alterações da ramificação do recurso na ramificação principal :

  1. Confirmação de mesclagem Manterá
    todo o histórico de confirmações da ramificação de recursos e as moverá para a ramificação principal
    .

  2. Rebase and mesclagem
    Anexará todo o histórico de confirmações da ramificação de recursos na frente da ramificação mestre
    . NÃO adicionará confirmação fictícia extra.

  3. Squash e mesclagem
    Agrupam todas as confirmações de ramificação de recursos em uma confirmação e depois anexam-na na frente da ramificação principal
    .

Você pode encontrar abaixo como o ramo mestre cuidará de cada um deles.

insira a descrição da imagem aqui

Em todos os casos:
podemos excluir com segurança o ramo do recurso .

ahmednabil88
fonte
11
você pode explicar o que é dummy commit na segunda foto ?? Eu sou iniciante no git.
Yusuf
11
@Yusuf, é apenas uma confirmação extra que contém as atualizações de ambas as ramificações, é a mensagem de confirmação padrão = "Megre ramificação XYZ no mestre"
ahmednabil88