Git: Como esmagar todos os commits no branch

315

Eu faço um novo ramo mastercom:

git checkout -b testbranch

Eu faço 20 commits nele.

Agora eu quero esmagar esses 20 commits. Eu faço isso com:

git rebase -i HEAD~20

E se eu não souber quantos commits? Existe alguma maneira de fazer algo como:

git rebase -i all on this branch
user3803850
fonte
6
Você pode fazer git rebase -i 58333012713fc168bd70ad00d191b3bdc601fa2dwich vai fazer um rebase interativo, onde o commitnumber é a última confirmação que permanece inalterada
denns
@denns Usando este método com a última confirmação no ramo que você está rebasing partir trabalhou fantástico. Muito obrigado!
Joshua Pinter

Respostas:

395

Outra maneira de esmagar todos os seus commits é redefinir o índice para master:

 git checkout yourBranch
 git reset $(git merge-base master yourBranch)
 git add -A
 git commit -m "one commit on yourBranch"

Isso não é perfeito, pois implica que você sabe de qual ramificação "yourBranch" vem.
Nota: descobrir que o ramo de origem não é fácil / possível com o Git (a maneira visual geralmente é a mais fácil , como visto aqui ).


EDIT: você precisará usar git push --force


Karlotcha Hoa acrescenta nos comentários :

Para a redefinição, você pode fazer

git reset $(git merge-base master $(git rev-parse --abbrev-ref HEAD)) 

[That] usa automaticamente a filial em que você está atualmente.
E se você usar isso, também poderá usar um alias, pois o comando não depende do nome do ramo .

VonC
fonte
2
Melhor fazer checkout para confirmar onde YourBranchestá atualmente. Isto irá manter YourBranchintacta quando você fazreset
Eugen Konkov
1
@Abdurrahim Ou abra um git bash e você poderá copiar e colar esses comandos!
VonC 26/06
3
Para a redefinição, você pode git reset $(git merge-base master $(git rev-parse --abbrev-ref HEAD))usar para usar automaticamente a filial em que está atualmente. E se você usar isso, também poderá usar um alias, pois o comando não depende do nome do ramo.
Karlotcha Hoa
1
@Druska Para casos de ramificação simlpe, não, deve funcionar bem.
VonC 21/09
1
@Shimmy sim, desde que você force o push após a redefinição: git push --force(e avise seus colegas se houver várias pessoas trabalhando nesse ramo)
VonC
112

Faça check-out da ramificação para a qual você deseja compactar todas as confirmações em uma confirmação. Vamos dizer que é chamado feature_branch.

git checkout feature_branch

Passo 1:

Faça uma redefinição suave origin/feature_branchcom sua masterfilial local (dependendo de suas necessidades, você também pode redefinir com origem / mestre). Isso redefinirá todas as confirmações extras no feature_branchseu arquivo, mas sem alterar nenhuma alteração no seu arquivo localmente.

git reset --soft master

Passo 2:

Adicione todas as alterações no diretório git repo ao novo commit que será criado. E comprometa o mesmo com uma mensagem.

git add -A && git commit -m "commit message goes here"

shanky
fonte
6
Essa foi a solução mais confiável para mim - sem causar erros de rebase nem mesclar conflitos.
ANTARA
1
Aviso: o git add -A add TUDO que você tem na pasta local - para o ramo.
David H
adoro esta solução! isto é exatamente o que eu queria!
jacoballenwood
1
Melhor solução para um noob - não destrutivo e só oops momento pode estar verificando em demasia, como segredos de aplicativos etc, que não deve importar se você tem um arquivo gitignore adequada
kkarakk
@NSduToit Resposta curta: Não, você não precisa. Depois de executar as etapas acima mencionadas na minha resposta, você terminará com um commit com algumas alterações de código. Você pode pensar nisso como qualquer outro commit com algumas alterações de código. Você pode enviar isso para sua filial remota sem a -fbandeira.
Shanky 18/07/19
110

O que você está fazendo é propenso a erros. Apenas faça:

git rebase -i master

que rebase automaticamente apenas as confirmações de sua filial no mestre mais recente atual.

Eevee
fonte
5
Obrigado, eu tenho isso, mas porque é o meu erro de sistema propenso
user3803850
10
Provavelmente porque é fácil errar o número?
Daniel Scott
13
Concordou que esta é sua melhor solução. mas siga este link , pois explica melhor o que você precisa fazer.
Christo
3
Em vez de espremer confirmações, você pode mesclar a ramificação para dominar e fazer uma redefinição do git para origem / mestre para desestabilizar todas as confirmações. Que deixaria de cometer o seu código unstaged existente comcommit -am "the whole thing!"
nurettin
2
@ nettettin Eu acho que o reset origin/mastermétodo é realmente ruim, pois é o mesmo que fazer confirmações diretamente no master - não há histórico de 'junção de ramo', nenhuma opção de solicitação de recebimento. A resposta por @WaZaA é muito mais de acordo com git normal de fluxo de trabalho eu acho
Drenai
79

Outra maneira simples de fazer isso: vá no ramo de origem e faça a merge --squash. Este comando não faz o commit "esmagado". quando você fizer isso, todas as mensagens de confirmação do yourBranch serão coletadas.

$ git checkout master
$ git merge --squash yourBranch
$ git commit # all commit messages of yourBranch in one, really useful
 > [status 5007e77] Squashed commit of the following: ...
WaZaA
fonte
1
Verdade. I mencionados a diferença entre --squash intercalação e alteração de base -i em stackoverflow.com/a/2427520/6309
VonC
1
Isso funciona se você não quiser esmagar a ramificação pai, basta criar e alternar para uma nova ramificação baseada na ramificação pai e fazer a mesclagem com a squash.
Charlotte
Cheers companheiro, ótima dica!
Nestor Milyaev 21/02/19
legais! eu crio uma ramificação "temp" fora de "master" primeiro para esmagar "yourBranch" em, depois mesclo "temp" em "master".
lazieburd 25/09/19
34

Supondo que você estava ramificação do mestre, você não precisa entrar yourBranchna etapa de reset o tempo todo:

git checkout yourBranch
git reset --soft HEAD~$(git rev-list --count HEAD ^master)
git add -A
git commit -m "one commit on yourBranch"

Explicação :

  • git rev-list --count HEAD ^masterconta as confirmações desde que você fez sua ramificação de recursos do mestre, por exemplo, 20
  • git reset --soft HEAD~20fará uma redefinição suave dos últimos 20 commits. Isso deixa suas alterações nos arquivos, mas remove as confirmações.

Uso :

No meu .bash_profile, adicionei um alias para gisquashfazer isso com um comando:

# squash all commits into one
alias gisquash='git reset --soft HEAD~$(git rev-list --count HEAD ^master)'

Após redefinir e confirmar, você precisa fazer a git push --force.

Dica :

Se você estiver usando o Gitlab> = 11.0, não precisará mais fazer isso, pois ele tem uma opção de esmagamento ao mesclar ramificações. Opção Gitlab Squashing

mles
fonte
15

Com base na leitura de várias perguntas e respostas do Stackoverflow sobre esmagamento, acho que este é um bom argumento para esmagar todos os commits em um ramo:

git reset --soft $(git merge-base master YOUR_BRANCH) && git commit -am "YOUR COMMIT MESSAGE" && git rebase -i master

Isso supõe que o mestre seja o ramo base.

Travis Reeder
fonte
1
Muito obrigado, a empresa possui muitas restrições em vigor e não pôde refazer a maneira usual com um editor, pois não era possível salvar em voz alta. Também não foi possível usar o recurso squash e mesclagem no git, pois esse ramo vai para Lead dev para mesclagem e ele não gosta. Este forro 1 trabalhou e salvou dores de cabeça. Trabalho incrível.
L1ghtk3ira
10

Solução para pessoas que preferem clicar:

  1. Instale o sourcetree (é grátis)

  2. Verifique como são os seus commits. Provavelmente você tem algo semelhante a este insira a descrição da imagem aqui

  3. Clique com o botão direito do mouse em commit pai . No nosso caso, é o ramo principal.

insira a descrição da imagem aqui

  1. Você pode esmagar o commit com o anterior clicando em um botão. No nosso caso, temos que clicar duas vezes. Você também pode alterar a mensagem de confirmação insira a descrição da imagem aqui

  2. Os resultados são impressionantes e estamos prontos para avançar! insira a descrição da imagem aqui

Nota lateral: Se você estava enviando suas confirmações parciais para o controle remoto, você deve usar o push forçado após o squash

Marcin Szymczak
fonte
Obrigado por isso!
Crystal
0

Outra solução seria salvar todos os logs de confirmação em um arquivo

git log> branch.log

Agora branch.log terá todos os IDs de confirmação desde o início. Role para baixo e pegue o primeiro commit (isso será difícil no terminal) usando o primeiro commit

git reset --soft

todas as confirmações serão esmagadas

pranav
fonte
0

A redefinição do Git, como mencionado em muitas respostas anteriores, é de longe a melhor e mais simples maneira de alcançar o que você deseja. Eu o uso no seguinte fluxo de trabalho:

(no ramo de desenvolvimento)

git fetch
git merge origin/master  #so development branch has all current changes from master
git reset origin/master  #will show all changes from development branch to master as unstaged
git gui # do a final review, stage all changes you really want
git commit # all changes in a single commit
git branch -f master #update local master branch
git push origin master #push it
Marcus
fonte
0

Todo esse git reset, rígido, suave e tudo o mais mencionado aqui provavelmente está funcionando (não funcionou para mim) se você executar as etapas corretamente e algum tipo de gênio.
Se você é o Joe smo médio, tente o seguinte:
Como usar o git merge --squash?


Salvei minha vida, e vou ser a minha squash, usei isso 4 vezes desde que descobri. Simples, limpo e basicamente 1 comamnd. Resumindo:


se você estiver em uma ramificação, vamos chamá-la de "my_new_feature" e desenvolva e sua solicitação de recebimento tem 35 confirmações (ou muitas) e você deseja que seja 1.

A. Certifique-se de que sua ramificação esteja atualizada, Continue desenvolva, obtenha as últimas e mescle e resolva quaisquer conflitos com "my_new_feature"
(esta etapa realmente deve ser executada assim que possível o tempo todo)

B. Receba as últimas novidades sobre o desenvolvimento e ramifique para uma nova ramificação: "my_new_feature_squashed"

C. magia está aqui.
Você quer levar o seu trabalho de "my_new_feature" para "my_new_feature_squashed"
Então, basta fazer (enquanto em seu novo ramo criamos o develop):
git merge --squash my_new_feature

Todas as suas alterações agora estarão em seu novo ramo, fique à vontade para testá-lo e faça apenas um único commit, push, novo PR desse ramo - e aguarde a repetição no dia seguinte.
Você não gosta de codificar? :)

ItaiRoded
fonte