Combine os dois primeiros commits de um repository Git?

Suponha que você tenha um histórico contendo os três commits A, B e C :

ABC 

Eu gostaria de combinar os dois commits A e B para um commit AB :

 AB-C 

eu tentei

 git rebase -i A 

que abre meu editor com o seguinte conteúdo:

 pick e97a17b B pick asd314f C 

Eu mudo isso para

 squash e97a17b B pick asd314f C 

Então o Git 1.6.0.4 diz:

 Cannot 'squash' without a previous commit 

Existe uma maneira ou isso é simplesmente impossível?

Use git rebase -i --root partir do Git versão 1.7.12 .

No arquivo de repository interativo, altere a segunda linha do commit B para squash e deixe as outras linhas no pick :

 pick f4202da A squash bea708e B pick a8c6abc C 

Isto irá combinar os dois commits A e B para um commit AB .

Encontrado nesta resposta .

Você tentou:

 git rebase -i A 

É possível começar assim se continuar com a edit em vez da squash :

 edit e97a17b B pick asd314f C 

então corra

 git reset --soft HEAD^ git commit --amend git rebase --continue 

Feito.

A foi o commit inicial, mas agora você quer que B seja o commit inicial. git commits são trees inteiras, não diffs, mesmo que sejam normalmente descritas e visualizadas em termos do diff que elas introduzem.

Esta receita funciona mesmo se houver vários commits entre A e B e B e C.

 # Go back to the last commit that we want # to form the initial commit (detach HEAD) git checkout  # reset the branch pointer to the initial commit, # but leaving the index and working tree intact. git reset --soft  # amend the initial tree using the tree from 'B' git commit --amend # temporarily tag this new initial commit # (or you could remember the new commit sha1 manually) git tag tmp # go back to the original branch (assume master for this example) git checkout master # Replay all the commits after B onto the new initial commit git rebase --onto tmp  # remove the temporary tag git tag -d tmp 

No caso de rebase interativo, você tem que fazer isso antes de A, para que a lista seja:

 pick A pick B pick C 

tornar-se:

 pick A squash B pick C 

Se A é o commit inicial, você tem que ter um commit inicial diferente antes de A. Git pensar em diferenças, ele funcionará na diferença entre (A e B) e (B e C). Por isso a abóbora não funciona no seu exemplo.

No caso de você ter centenas ou milhares de commits, usando a resposta do kostmo

 git rebase -i --root 

pode ser impraticável e lento, apenas devido ao grande número de confirmações que o script rebase precisa processar duas vezes , uma vez para gerar a lista de editoração de repository interativo (onde você seleciona qual ação executar para cada confirmação) e uma vez para executar realmente re-aplicação de commits.

Aqui está uma solução alternativa que evitará o custo de tempo de gerar a lista de editoras de repository interativo ao não usar um rebase interativo em primeiro lugar. Desta forma, é semelhante à solução de Charles Bailey . Você simplesmente cria uma ramificação órfã da segunda confirmação e, em seguida, rebaixa todas as confirmações descendentes sobre ela:

 git checkout --orphan orphan  git commit -m "Enter a commit message for the new root commit" git rebase --onto orphan  master 

Documentação

  • git-checkout (1) Página do manual
  • git-rebase (1) Página do manual

Em uma questão relacionada, eu consegui chegar a uma abordagem diferente para a necessidade de esmagar o primeiro commit, que é, bem, para torná-lo o segundo.

Se você estiver interessado: git: como inserir um commit como o primeiro, mudando todos os outros?

Você tem que executar um pouco de magia de linha de comando.

 git checkout -ba A git checkout B  git commit --amend git checkout master git rebase a 

Isso deve deixar você com um branch que tenha AB e C como commits.