Como esmagar todos os commits do git em um?
Como você compacta todo o seu repositório até o primeiro commit?
Posso mudar para o primeiro commit, mas isso me deixaria com 2 commits. Existe uma maneira de referenciar o commit antes do primeiro?
— Verhogen
"o commit antes do primeiro"?
— InnaM 01/11/2009
@innaM - É o commit primordial que gerou o git . (O humor das esperanças passa bem o suficiente pela interweb).
Para aqueles que vierem mais tarde a esta pergunta, use a resposta mais moderna .
Relacionado, mas não duplicado ( --rootna verdade, não é a melhor solução para esmagar todos os commits, se houver muitos deles para esmagar): Combine os dois primeiros commits de um repositório Git? .
Imo: este é o melhor do @MrTux: stackoverflow.com/questions/30236694/… .
Talvez a maneira mais fácil seja apenas criar um novo repositório com o estado atual da cópia de trabalho. Se você deseja manter todas as mensagens de confirmação, você pode primeiro fazer git log > original.loge editar isso para sua mensagem de confirmação inicial no novo repositório:
mas você está perdendo ramos com este método
O Git evoluiu desde que essa resposta foi dada. Não, não existe uma maneira mais simples e melhor: git rebase -i --root. Veja: stackoverflow.com/a/9254257/109618
Isso pode funcionar para alguns casos, mas essencialmente não é a resposta para a pergunta. Com esta receita, você perde toda a sua configuração e todos os outros ramos também.
Esta é uma solução horrível que é desnecessariamente destrutiva. Por favor, não use.
também quebrará submódulos. -1
A partir do git 1.6.2 , você pode usar git rebase --root -i.
Para cada confirmação, exceto a primeira, altere pickpara squash.
— Jordan Lewis
Adicione um exemplo de comando completo e funcional que responda à pergunta original.
Eu gostaria de ler isso antes de explodir todo o meu repositório, como a resposta aceita diz: /
Esta resposta é ok , mas se você está rebasing interativamente mais do que, digamos, 20 commits, o rebase interativo provavelmente será muito lento e pesado. Você provavelmente terá dificuldade em tentar esmagar centenas ou milhares de confirmações. Eu aceitaria uma redefinição suave ou mista da confirmação raiz e, em seguida, a confirmação novamente nesse caso.
@Pred Não use squashpara todas as confirmações. O primeiro precisa ser pick.
Se você tiver muitos commits, é difícil alterar 'pick' para 'squash' manualmente. Use :% s / pick / squash / g na linha de comando do VIM para fazer isso mais rapidamente.
— eilas
Eu fiz um pseudônimo git squash-all.
Exemplo de utilização : git squash-all "a brand new start".
Embargo : lembre-se de fornecer um comentário, caso contrário, a mensagem de confirmação padrão "Um novo começo" seria usada.
Nota : aqui "A new start " é apenas um exemplo, fique à vontade para usar seu próprio idioma.
Não há necessidade de esmagar, use git commit-tree para criar um commit órfão e siga em frente.
crie uma única confirmação via git commit-tree
O que git commit-tree HEAD^{tree} -m "A new start"faz é:
Cria um novo objeto de confirmação com base no objeto em árvore fornecido e emite o novo ID do objeto de confirmação no stdout. A mensagem de log é lida a partir da entrada padrão, a menos que sejam fornecidas as opções -m ou -F.
A expressão HEAD^{tree}significa o objeto de árvore correspondente a HEAD, ou seja, a ponta do seu ramo atual. veja Árvore-objetos e commit-Objects .
redefinir a ramificação atual para o novo commit
Em seguida, git resetbasta redefinir a ramificação atual para o objeto de confirmação recém-criado.
Dessa forma, nada no espaço de trabalho é tocado, nem há necessidade de rebase / squash, o que o torna muito rápido. E o tempo necessário é irrelevante para o tamanho do repositório ou a profundidade do histórico.
Variação: novo repositório a partir de um modelo de projeto
Isso é útil para criar o "commit inicial" em um novo projeto usando outro repositório como modelo / arquétipo / semente / esqueleto. Por exemplo:
Isso evita adicionar o repositório de modelo como um controle remoto ( originou não) e recolhe o histórico do repositório de modelo no seu commit inicial.
A sintaxe revisão git (HEAD ^ {tree}) sintaxe é explicado aqui no caso de alguém estava me perguntando: jk.gs/gitrevisions.html
Isso redefine o repositório local e remoto, ou apenas um deles?
— Aleclarson
@aleclarson, isso redefine apenas a ramificação atual no repositório local, use git push -fpara propagação.
— Ryenus # 28/14
Encontrei esta resposta enquanto procurava uma maneira de iniciar um novo projeto a partir de um repositório de modelos de projeto que não envolvesse git clone. Se você adicionar --harda git resete alternar HEADcom FETCH_HEADno git commit-treevocê pode criar cometer um inicial após buscar o repo modelo. Editei a resposta com uma seção no final demonstrando isso.
Você pode se livrar desse "aviso", mas apenas usando #${1?Please enter a message}
Se tudo o que você deseja fazer é compactar todos os seus commit até o commit raiz, então enquanto
pode funcionar, é impraticável para um grande número de confirmações (por exemplo, centenas de confirmações), porque a operação de rebase provavelmente será executada muito lentamente para gerar a lista de confirmação do editor de rebase interativo, bem como executar a rebase.
Aqui estão duas soluções mais rápidas e eficientes quando você está esmagando um grande número de confirmações:
Solução alternativa nº 1: filiais órfãs
Você pode simplesmente criar um novo ramo órfão na ponta (ou seja, o commit mais recente) do seu ramo atual. Esse ramo órfão forma o commit raiz inicial de uma árvore de histórico de commit totalmente nova e separada, que é efetivamente equivalente a esmagar todos os seus commit:
Página de manual do git-checkout (1) .
Solução alternativa nº 2: redefinição suave
Outra solução eficiente é simplesmente usar uma redefinição mista ou suave para o commit raiz <root>:
Manual do git-reset (1) .
Solução alternativa # 1: galhos órfãos - rochas!
Solução alternativa # 1 FTW. Apenas para adicionar, se você deseja enviar suas alterações para o controle remoto, faça git push origin master --force.
— Eddy Verbruggen
não se esqueçagit push --force
— NecipAllef
Não faça uma ramificação órfã no código (por exemplo, não faça a solução alternativa nº 1 acima) se estiver prestes a enviar para uma solicitação de recebimento aberta do Github !!! O Github fechará o seu PR porque a cabeça atual não é descendente da cabeça armazenada sha .
— Andrew Mackie
A solução alternativa nº 1 também evita os conflitos de mesclagem que podem ocorrer quando o squash é confirmado
— FernAndr
Isso criará um commit órfão com a árvore do HEAD e produzirá seu nome (SHA-1) no stdout. Em seguida, basta redefinir sua filial lá.
git reset $(git commit-tree HEAD^{tree} -m "commit message")tornaria mais fácil.
^ ISTO! - deve ser uma resposta. Não tenho certeza se era a intenção do autor, mas era minha (precisava de um repo intocado com um único commit, e isso faz o trabalho).
— chesterbr
@ryenus, sua solução fez exatamente o que eu estava procurando. Se você adicionar seu comentário como resposta, eu o aceito.
O motivo pelo qual eu não sugeri a variante subshell, é que ela não funcionará no cmd.exe no Windows.
Nos prompts do Windows, pode ser necessário citar o último parâmetro: echo "message" | git commit-tree "HEAD^{tree}"
Eis como acabei fazendo isso, caso funcione para outra pessoa:
Lembre-se de que sempre existe o risco de fazer coisas assim, e nunca é uma má idéia criar uma ramificação salva antes de iniciar.
Role para confirmar primeiro, copie SHA
Substitua <#sha#>com o SHA copiado do log
Verifique se tudo está verde, caso contrário, execute git add -A
Alterar todas as alterações atuais no primeiro commit atual
Agora force o push deste ramo e ele substituirá o que está lá.
Excelente opção! Realmente simples.
Isso é mais do que fantástico! Obrigado!
— 275166 Matt Comarlinicki
Observe que isso realmente parece deixar a história por aí. Você ficou órfão, mas ainda está lá.
Resposta muito útil ... mas você deve estar ciente de que, após o comando de correção, você se encontrará no editor vim com sua sintaxe especial. ESC, ENTER,: x é seu amigo.
— Erich Kuester
— Danivicario 19/07/19
De qualquer forma, você pode esmagar os últimos 2 commits manualmente com algo como isto:
Esta é realmente a resposta que eu estava procurando, gostaria que fosse a aceita!
Esta é uma resposta incrível
A maneira mais fácil é usar o comando 'encanamento' update-ref para excluir a ramificação atual.
Você não pode usar git branch -D , pois possui uma válvula de segurança para impedir a exclusão da ramificação atual.
Isso coloca você de volta ao estado 'commit inicial', onde você pode começar com um commit inicial novo.
Primeiro, junte todos os seus commits em um único commit usando git rebase --interactive. Agora você tem dois commits para esmagar. Para fazer isso, leia qualquer um dos
Como combinar os dois primeiros commits de um repositório Git?
@AlexanderMills, você deve ler git help checkoutsobre--orphan
você pode vincular os documentos para que todos os que leem não precisem procurar manualmente?
fácil. aqui estágit help checkout --orphan
— kyb 10/05/19
redefinir para confirmação especificada
depois adicione todos os arquivos ao teste
confirmar sem atualizar a mensagem
empurrar novo ramo com squashed compromete-se a repo
Isso preservará as mensagens de confirmação anteriores?
@ not2qubit no isso não preservará as mensagens de confirmação anteriores, em vez de confirmar # 1, confirmar # 2, confirmar # 3, você receberá todas as alterações nesses commit agrupadas em um único commit # 1. A confirmação nº 1 será a <root>confirmação para a qual você redefinirá. git commit --amend --no-editconfirmará todas as alterações na confirmação atual, <root>sem a necessidade de editar a mensagem de confirmação.
Adicione um arquivo .git/info/grafts, coloque lá o hash de confirmação que você deseja que seja seu root
git log agora começará a partir desse commit
Para torná-lo 'real' executado git filter-branch
— dimus
Esta resposta é aprimorada em algumas das opções acima (vote-as), assumindo que, além de criar o único commit (sem pais sem histórico), você também deseja manter todos os dados de commit desse commit:
Confirmar mensagem de log
É claro que o commit-SHA do novo / único commit será alterado, pois representa um novo (não) histórico, tornando-se um commit sem pai / root.
Isso pode ser feito lendo git loge configurando algumas variáveis ​​para git commit-tree. Supondo que você deseja criar uma única confirmação masterem uma nova ramificação one-commit, mantendo os dados de confirmação acima:
— javabrett
Para fazer isso, você pode redefinir seu repositório git local para a primeira hashtag de confirmação, para que todas as suas alterações após essa confirmação sejam desassistidas, e você pode confirmar com a opção --amend.
E edite o primeiro nome de confirmação, se necessário, e salve o arquivo.
— T.EL MOUSSAOUI
Para mim, funcionou assim: eu tinha 4 confirmações no total e usei o rebase interativo:
O primeiro commit permanece e eu fiz 3 commit mais recentes.
Caso você esteja preso no editor que aparece a seguir, verá algo como:
Você precisa primeiro confirmar e esmagar os outros. O que você deve ter é:
Para isso, use a tecla INSERT para alterar o modo 'inserir' e 'editar'.
Para salvar e sair do editor, use :wq. Se o cursor estiver entre essas linhas de confirmação ou em outro lugar, pressione ESC e tente novamente.
Como resultado, tive dois commits: o primeiro que permaneceu e o segundo com a mensagem "Esta é uma combinação de 3 commits".
Verifique os detalhes aqui: https://makandracards.com/makandra/527-squash-several-git-commits-into-a-single-commit
Verifique se tudo está confirmado e anote o último ID de confirmação, caso algo dê errado, ou crie uma ramificação separada como backup.
Execute git reset --soft `git rev-list --max-parents=0 --abbrev-commit HEAD`para redefinir sua cabeça para o primeiro commit, mas deixe seu índice inalterado. Todas as alterações desde o primeiro commit agora parecerão prontas para serem confirmadas.
Execute git commit --amend -m "initial commit"para alterar seu commit no primeiro commit e altere a mensagem de commit ou, se desejar manter a mensagem de commit existente, você poderá executargit commit --amend --no-edit