Mesclar (com squash) todas as alterações de outro ramo como uma única confirmação

479

No Git, existe uma maneira de mesclar todas as alterações de um ramo para outro, mas esmagar para um único commit ao mesmo tempo?

Costumo trabalhar em um novo recurso em uma ramificação separada e confirma / envia regularmente - principalmente para backup ou para transferir o que estou trabalhando para outra máquina. Na maioria das vezes, esses commits dizem "Feature xxx WIP" ou algo redundante.

Depois que o trabalho estiver concluído e eu desejar mesclar a ramificação WIP novamente no mestre, eu gostaria de descartar todas essas confirmações intermediárias e ter apenas uma confirmação limpa.

Existe uma maneira fácil de fazer isso?

Como alternativa, que tal um comando que esmaga todos os commit em um branch desde o ponto em que ele foi ramificado?

Brad Robinson
fonte

Respostas:

601

Outra opção é git merge --squash <feature branch>finalmente fazer a git commit.

A partir da mesclagem Git

--squash

--no-squash

Produza a árvore de trabalho e o estado do índice como se uma mesclagem real tivesse acontecido (exceto as informações de mesclagem), mas na verdade não faça uma confirmação ou mova a HEAD, nem registre $GIT_DIR/MERGE_HEADpara fazer com que o próximo git commitcomando crie uma confirmação de mesclagem. Isso permite criar uma única confirmação sobre a ramificação atual, cujo efeito é o mesmo que mesclar outra ramificação (ou mais no caso de um polvo).

fseto
fonte
1
Recurso legal! Eu amo idiota. Embora eu definitivamente esteja usando isso no futuro agora, ainda assim eu recomendaria conhecer o seu caminho para rebase -i. É uma boa habilidade ter, caso você realmente queira torná-los mais do que apenas um commit.
Will Buck
4
Uma palavra de cautela: isso funciona, mas a mensagem de confirmação padrão inclui o log da filial que está sendo mesclada. O problema é que ele se parece com o formato que você normalmente vê, onde o texto inteiro mostrado não se torna parte da mensagem de confirmação, mas, nesse caso, sim. Portanto, se você não quiser tudo isso, precisará remover manualmente tudo isso da sua mensagem de confirmação. Eu deveria ter testado isso antes de usá-lo ...
still_dreaming_1 13/08
23
Isso e lembre-se de que a ramificação não será vista como mesclada. stackoverflow.com/questions/19308790/…
Ryan
3
IMHO isso deveria ter sido chamadorebase --squash
Andy
portanto (como ele realmente não mescla o ramo do recurso), isso seria apropriado se você fosse excluir o ramo do recurso após a confirmação. Isso está correto? (Eu não sou um especialista em git)
Andrew Spencer
214

Encontrei! O comando Mesclar possui uma --squashopção

git checkout master
git merge --squash WIP

neste ponto, tudo está mesclado, possivelmente em conflito, mas não comprometido. Então agora eu posso:

git add .
git commit -m "Merged WIP"
Brad Robinson
fonte
2
o que git add .faz?
Michael Potter
1
@MichaelPotter Ele adiciona todos os arquivos e muda
Daksh Shah
2
git add .adiciona todos os arquivos não ignorados no diretório atual, eu seria cauteloso ao pegar arquivos indesejados dessa maneira.
Jake Cobb
7
Como alternativa, git add .você pode usar git add -upara adicionar apenas arquivos que já foram adicionados à árvore.
Brandon Ogle
19
Sugerindo que um "git add". ser feito também é confuso. Quando eu faço o "git merge --squash WIP", ele já possui as alterações compactadas no índice. Tudo o que é necessário é comprometê-los. Fazendo um "git add". adicionará alterações que estão no diretório ativo, mas que não faziam parte da ramificação do recurso. A questão era como confirmar as alterações no ramo do recurso como uma confirmação.
John Pankowicz
30

Experimente o git rebase -i masterseu ramo de recursos. Você pode alterar todos, exceto um 'pick' para 'squash', para combinar os commits. Veja squashing confirma com rebase

Finalmente, você pode fazer a mesclagem da ramificação principal.

fseto
fonte
8
Sim, isso funciona, mas não quero o aborrecimento da rebase interativa. Eu só quero tudo, desde que o galho se achatou.
Brad Robinson
2
+1 Isso cria um histórico limpo. É muito mais fácil de identificar e gerenciar commits como manchas individuais, cartões, histórias, etc.
Ryan
2

Usar git merge --squash <feature branch>como a resposta aceita sugere o truque, mas não mostra o ramo mesclado como realmente mesclado.

Portanto, uma solução ainda melhor é:

  • Crie uma nova ramificação a partir do mestre mais recente
  • Mesclar <feature branch>no acima usandogit merge --squash
  • Mesclar a ramificação recém-criada no mestre

Este wiki explica o procedimento em detalhes.

raratiru
fonte
0

Eu criei meu próprio alias do git para fazer exatamente isso. Estou chamando git freebase! Ele pegará sua ramificação de recurso desarrumado e irrecuperável existente e a recriará para que ela se torne uma nova ramificação com o mesmo nome, com seus commits compactados em um commit e reestruturados no branch que você especificar (master por padrão). No final, ele permitirá que você use qualquer mensagem de confirmação que desejar para o seu ramo "freebased".

Instale-o colocando o seguinte alias no seu .gitconfig:

[alias]
  freebase = "!f() { \
    TOPIC="$(git branch | grep '\\*' | cut -d ' ' -f2)"; \
    NEWBASE="${1:-master}"; \
    PREVSHA1="$(git rev-parse HEAD)"; \
    echo "Freebaseing $TOPIC onto $NEWBASE, previous sha1 was $PREVSHA1"; \
    echo "---"; \
    git reset --hard "$NEWBASE"; \
    git merge --squash "$PREVSHA1"; \
    git commit; \
  }; f"

Use-o na ramificação de recursos executando: git freebase <new-base>

Eu só testei isso algumas vezes, então leia-o primeiro e verifique se deseja executá-lo. Como uma pequena medida de segurança, ele imprime o sha1 inicial, para que você possa restaurar sua ramificação antiga se algo der errado.

Vou mantê-lo no meu repositório dotfiles no github: https://github.com/stevecrozz/dotfiles/blob/master/.gitconfig

Stephen Crosby
fonte
trabalhou como uma felicidade! assim como você pode dar uma olhada em evernote.com/shard/s52/sh/7f8f4ff1-9a68-413f-9225-c49e3ee2fafd/...
Ilya Sheershoff
-1

git merge --squash <feature branch> é uma boa opção. O "git commit" informa todas as mensagens de confirmação do ramo de recursos com sua escolha para mantê-lo.

Por menos consolidação de consolidação.

git merge faça x vezes --git reset HEAD ^ --soft e git commit.

Arquivos excluídos por risco podem voltar.

Arjun Mullick
fonte
-5

Você pode fazer isso com o comando "rebase". Vamos chamar os ramos "principal" e "recurso":

git checkout feature
git rebase main

O comando rebase repetirá todas as confirmações no "recurso" como uma confirmação com um pai igual a "principal".

Você pode executar git merge mainantes git rebase mainse "main" mudou desde que o "feature" foi criado (ou desde a mesclagem mais recente). Dessa forma, você ainda tem seu histórico completo caso tenha um conflito de mesclagem.

Após a reformulação, você pode mesclar sua ramificação para principal, o que resultará em uma mesclagem de avanço rápido:

git checkout main
git merge feature

Consulte a página de rebase de Entendendo o Git conceitualmente para obter uma boa visão geral.

NamshubWriter
fonte
Isso não funcionou para mim. Acabei de criar um repositório de teste simples, com uma ramificação WIP, tentei o acima e obtive conflitos de mesclagem (mesmo que eu não tenha feito nenhuma alteração no mestre).
Brad Robinson
Se o recurso foi criado a partir principal (git checkout -b característica principal) e você tinha uma fusão recente do principal, você não deve ter conflitos do rebase
NamshubWriter
OK, tentei novamente. Desta vez, não houve conflitos, mas a história não foi esmagada.
Brad Robinson
Olhando novamente a documentação do git-merge, você está certo, alguns dos commits permanecerão. Se você fez mesclagens anteriores do "principal" para o "recurso", a rebase removerá algumas delas, mas não todas.
NamshubWriter
Lembre-se de que a reformulação pode ser bastante perigosa se o ramo do recurso tiver sido publicado anteriormente. Mais informações sobre esta questão SO .
Robert Rossmann 11/01