Como você remove uma revisão específica do histórico do git?

StackOverflow https://stackoverflow.com/questions/37219

  •  09-06-2019
  •  | 
  •  

Pergunta

Suponha que seu histórico do git seja assim:

1 2 3 4 5

1–5 são revisões separadas.Você precisa remover 3 enquanto mantém 1, 2, 4 e 5.Como isso pode ser feito?

Existe um método eficiente quando há centenas de revisões após aquela a ser excluída?

Foi útil?

Solução

Para combinar as revisões 3 e 4 em uma única revisão, você pode usar git rebase.Se quiser remover as alterações na revisão 3, você precisa usar o comando de edição no modo rebase interativo.Se você quiser combinar as alterações em uma única revisão, use squash.

Usei essa técnica de squash com sucesso, mas nunca precisei remover uma revisão antes.A documentação do git-rebase em "Dividindo commits" deve lhe dar uma ideia suficiente para descobrir isso.(Ou alguém pode saber).

De documentação git:

Comece com o commit mais antigo que você deseja manter como está:

git rebase -i <after-this-commit>

Um editor será iniciado com todos os commits em seu branch atual (ignorando os commits de mesclagem), que vêm após o commit fornecido.Você pode reordenar os commits nesta lista como desejar e pode removê-los.A lista é mais ou menos assim:

pick deadbee The oneline of this commit
pick fa1afe1 The oneline of the next commit
...

As descrições on-line são puramente para seu prazer;O git-rebase não irá olhar para eles, mas para os nomes dos commits ("deadbee" e "fa1afe1" neste exemplo), então não exclua ou edite os nomes.

Ao substituir o comando "pick" pelo comando "edit", você pode dizer ao git-rebase para parar após aplicar aquele commit, para que você possa editar os arquivos e/ou a mensagem do commit, alterar o commit e continuar o rebase.

Se você quiser juntar dois ou mais commits em um, substitua o comando "pick" por "squash" para o segundo commit e os subseqüentes.Se os commits tiverem autores diferentes, o commit esmagado será atribuído ao autor do primeiro commit.

Outras dicas

Aqui está uma maneira de remover de forma não interativa um específico <commit-id>, conhecendo apenas o <commit-id> você gostaria de remover:

git rebase --onto <commit-id>^ <commit-id> HEAD

Por este comentário (e verifiquei se isso é verdade), a resposta do rado está muito próxima, mas deixa o git em um estado de cabeça desanexada.Em vez disso, remova HEAD e use isso para remover <commit-id> do branch em que você está:

git rebase --onto <commit-id>^ <commit-id>

Como observado antes git-rebase(1) é seu amigo.Supondo que os commits estejam em seu master ramo, você faria:

git rebase --onto master~3 master~2 master

Antes:

1---2---3---4---5  master

Depois:

1---2---4'---5' master

Do git-rebase(1):

Uma série de começos também pode ser removida com Rebase.Se tivermos a seguinte situação:

E---F---G---H---I---J  topicA

então o comando

git rebase --onto topicA~5 topicA~3 topicA

resultaria na remoção de commits f e g:

E---H'---I'---J'  topicA

Isso é útil se F e G foram falhos de alguma forma ou não devem fazer parte de Topica.Observe que o argumento para --nto e o parâmetro pode ser qualquer commit-ish válido.

Se tudo o que você deseja fazer é remover as alterações feitas na revisão 3, você pode usar git revert.

Git revert simplesmente cria uma nova revisão com alterações que desfazem todas as alterações na revisão que você está revertendo.

O que isso significa é que você retém informações sobre o commit indesejado e o commit que remove essas alterações.

Isso provavelmente será muito mais amigável se for possível que alguém tenha retirado seu repositório nesse meio tempo, já que a reversão é basicamente apenas um commit padrão.

Todas as respostas até agora não abordam a preocupação final:

Existe um método eficiente quando há centenas de revisões após a excluída?

Seguem os passos, mas para referência, vamos assumir o seguinte histórico:

[master] -> [hundreds-of-commits-including-merges] -> [C] -> [R] -> [B]

C:commit apenas seguindo o commit para ser removido (limpo)

R:O commit a ser removido

B:commit logo antes do commit a ser removido (base)

Devido à restrição de "centenas de revisões", estou assumindo as seguintes pré-condições:

  1. há algum commit embaraçoso que você gostaria que nunca existisse
  2. há ZERO commits subsequentes que realmente dependem daquele commit embaraçoso (zero conflitos na reversão)
  3. você não se importa se será listado como o 'Committer' das centenas de commits intervenientes ('Autor' será preservado)
  4. você nunca compartilhou o repositório
    • ou você realmente tem influência suficiente sobre todas as pessoas que já clonaram o histórico com esse commit para convencê-los a usar seu novo histórico
    • e você não me importo sobre reescrevendo a história

Este é um conjunto bastante restritivo de restrições, mas há uma resposta interessante que realmente funciona neste caso específico.

Aqui estão as etapas:

  1. git branch base B
  2. git branch remove-me R
  3. git branch save
  4. git rebase --preserve-merges --onto base remove-me

Se realmente não houver conflitos, então isso deverá prosseguir sem mais interrupções.Se houver conflitos, você pode resolvê-los e rebase --continue ou decidir apenas viver com o constrangimento e rebase --abort.

Agora você deveria estar ligado master que não tem mais commit R iniciar.O save branch aponta para onde você estava antes, caso queira se reconciliar.

Como você deseja organizar a transferência de todos os outros para o seu novo histórico depende de você.Você precisará estar familiarizado stash, reset --hard, e cherry-pick.E você pode excluir o base, remove-me, e save galhos

Então aqui está o cenário que enfrentei e como o resolvi.

[branch-a]

[Hundreds of commits] -> [R] -> [I]

aqui R é o commit que eu precisava ser removido, e I é um único commit que vem depois R

Eu fiz um commit de reversão e os esmaguei

git revert [commit id of R]
git rebase -i HEAD~3

Durante o rebase interativo, esmague os 2 últimos commits.

Eu também caí em uma situação semelhante.Use o rebase interativo usando o comando abaixo e ao selecionar, elimine o terceiro commit.

git rebase -i remote/branch

As respostas de rado e kareem não fazem nada por mim (apenas a mensagem "A filial atual está atualizada." aparece).Possivelmente isso acontece porque o símbolo ‘^’ não funciona no console do Windows.No entanto, de acordo com esse comentário, substituir '^' por '~1' resolve o problema.

git rebase --onto <commit-id>^ <commit-id>

Para remover o histórico de commits antigo do repositório git:

Primeiro execute abaixo do cmd

rm -rf .git

-- recria o repositório do atual

git init                                                                           
git add .                                                  
git commit -m "first commit"

-- push para os repositórios remotos do github

git remote add origin git@github.com<your git mail>   
git push -u --force origin master
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top