Esta questão está mal definida. Ela não diz explicitamente que o autor quer 1-2- (3 + 4) -5 ou 1-2-4-5
RandyTek
14
Bem, oito anos depois, não sei dizer exatamente qual problema estava tentando resolver. Mas no git sempre há muitas maneiras de fazer algo, e há muitas respostas que várias pessoas gostaram, então acho que a ambiguidade não está causando muita dificuldade para muitas pessoas
1800 Information
1
git rebase --onto 2 3 HEADpraticamente significa rebase para 2, com confirmações entre 3 e HEAD (HEAD é opcional, ou 5 neste caso)
neaumusic
Respostas:
76
Para combinar as revisões 3 e 4 em uma única revisão, você pode usar o git rebase. Se você deseja remover as alterações na revisão 3, use o comando de edição no modo de rebase interativo. Se você deseja combinar as alterações em uma única revisão, use squash.
Eu usei com sucesso essa técnica de squash, mas nunca precisei remover uma revisão antes. A documentação do git-rebase em "Dividir confirmações" deve fornecer uma idéia suficiente para você descobrir. (Ou alguém pode saber).
Inicie-o com o commit mais antigo que você deseja manter como está:
git rebase -i <after-this-commit>
Um editor será acionado com todas as confirmações em sua ramificação atual (ignorando as confirmações de mesclagem), que vêm após a confirmação fornecida. Você pode reordenar os commits nesta lista para o conteúdo do seu coração e pode removê-los. A lista é mais ou menos assim:
pick deadbee O on-line desse commit
pick fa1afe1 O on-line do próximo commit
...
As descrições on-line são puramente para seu prazer; O git-rebase não olha para eles, mas para os nomes de confirmação ("deadbee" e "fa1afe1" neste exemplo), portanto, não exclua ou edite os nomes.
Substituindo o comando "pick" pelo comando "edit", você pode dizer ao git-rebase para parar após aplicar esse commit, para que você possa editar os arquivos e / ou a mensagem de commit, alterar o commit e continuar com o rebasing.
Se você deseja dobrar duas ou mais confirmações em uma, substitua o comando "pick" por "squash" para a segunda e subsequente confirmação. Se os commits tiverem autores diferentes, ele atribuirá o commit compactado ao autor do primeiro commit.
-1 A pergunta está bem definida, mas esta resposta não é tão clara. O autor não diz qual é a solução exata.
Aleksandr Levchuk 03/04/19
1
Esta é uma pista errada. A seção SPLITTING COMMITS não é a correta. Você quer ler muito mais alto no manual - veja a resposta de @Rares Vernica.
Aleksandr Levchuk 03/04
1
@AleksandrLevchuk A questão não está bem definida: não está claro pela maneira como a questão é declarada se o conjunto de alterações em 3 deve ser mantido ou descartado. Concordo que, se as alterações forem descartadas, as outras respostas oferecerão uma abordagem mais fácil. Se as alterações forem mantidas, no entanto, isso seria uma operação puramente cosmética. Ambas as abordagens reescrevem a história de maneiras perigosas se outras pessoas basearem o trabalho no topo da história defeituosa; se for esse o caso, a limpeza cosmética não deve ser feita e a exclusão da alteração seria melhor via git revert.
Theodore Murdock
124
Por esse comentário (e eu verifiquei que isso é verdade), a resposta do rado é muito próxima, mas deixa o git em um estado principal desanexado. Em vez disso, remova HEADe use-o para remover <commit-id>da ramificação em que está:
Trabalhou para mim também. Btw, o que o operador ^ faz? Significa o próximo commit após o especificado?
hopia
3
@hopia significa o (primeiro) pai do commit especificado. Veja "revisões da ajuda do git"
Emil Styrke 28/03
12
Veja a recomendação de @ kareem em sua resposta para omitir HEAD, a fim de evitar uma cabeça desapegada.
precisa
1
Muito mais fácil do que ter que descobrir quantas confirmações retornam à pesquisa.
Dana Woodman
1
isso é incrível, mas e se eu quiser remover o primeiro commit da história? (que é por isso que eu vim aqui: P)
Sterling Camden
76
Como observado antes, o git-rebase (1) é seu amigo. Supondo que os commits estejam em sua masterfilial, você faria:
git rebase --onto master~3 master~2 master
Antes:
1---2---3---4---5 master
Depois de:
1---2---4'---5' master
Do git-rebase (1):
Um intervalo de confirmações também pode ser removido 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 dos commits F e G:
E---H'---I'---J' topicA
Isso é útil se F e G foram defeituosos de alguma forma ou não deveriam fazer parte do tópico A. Observe que o argumento para --onto e o parâmetro podem ser qualquer commit-ish válido.
Se tudo o que você deseja fazer é remover as alterações feitas na revisão 3, convém usar o git revert.
O Git revert simplesmente cria uma nova revisão com alterações que desfaz todas as alterações na revisão que você está revertendo.
O que isso significa é que você retém informações sobre a confirmação indesejada e a confirmação que remove essas alterações.
Isso provavelmente é muito mais amigável se for possível que alguém tenha saído do seu repositório nesse meio tempo, já que a reversão é basicamente apenas uma confirmação padrão.
Infelizmente, não é uma boa solução para mim, porque alguém acidentalmente comprometeu 100 MB de lixo no repositório, ampliando o tamanho e tornando a interface da Web lenta.
Stephen Smith
18
Até agora, todas as respostas não abordam a preocupação final:
Existe um método eficiente quando existem centenas de revisões após a exclusão?
As etapas a seguir, mas para referência, vamos assumir o seguinte histórico:
C : confirmar apenas após a confirmação a ser removida (limpa)
R : O commit a ser removido
B : confirmar imediatamente antes da confirmação a ser removida (base)
Devido à restrição de "centenas de revisões", estou assumindo as seguintes pré-condições:
existe algum comprometimento embaraçoso que você deseja que nunca exista
há ZERO confirmações subsequentes que realmente dependem dessa confirmação embaraçosa (zero conflito ao reverter)
você não se importa em ser listado como o 'Committer' das centenas de commits intermediários ('Author' será preservado)
você nunca compartilhou o repositório
ou você realmente tem influência suficiente sobre todas as pessoas que já clonaram a história com esse comprometimento para convencê-las a usar sua nova história
Este é um conjunto bastante restritivo de restrições, mas há uma resposta interessante que realmente funciona nesse caso de canto.
Aqui estão os passos:
git branch base B
git branch remove-me R
git branch save
git rebase --preserve-merges --onto base remove-me
Se realmente não houver conflitos, isso deve prosseguir sem mais interrupções. Se houver conflitos, você poderá resolvê-los e / rebase --continueou decidir apenas viver com o constrangimento erebase --abort .
Agora você deve estar em masterque não possui mais commit R nele. osave ramificação aponta para onde você estava antes, caso deseje se reconciliar.
Você decide como deseja organizar a transferência de todos para o seu novo histórico. Você precisará estar familiarizado com stash, reset --harde cherry-pick. E você pode excluir os base, remove-mee saveramos
As respostas do rado e do kareem não fazem nada para mim (apenas a mensagem "O ramo atual está atualizado." Aparece). Possivelmente isso acontece porque o símbolo '^' não funciona no console do Windows. No entanto, de acordo com este comentário, substituir '^' por '~ 1' resolve o problema.
git rebase --onto 2 3 HEAD
praticamente significa rebase para 2, com confirmações entre 3 e HEAD (HEAD é opcional, ou 5 neste caso)Respostas:
Para combinar as revisões 3 e 4 em uma única revisão, você pode usar o git rebase. Se você deseja remover as alterações na revisão 3, use o comando de edição no modo de rebase interativo. Se você deseja combinar as alterações em uma única revisão, use squash.
Eu usei com sucesso essa técnica de squash, mas nunca precisei remover uma revisão antes. A documentação do git-rebase em "Dividir confirmações" deve fornecer uma idéia suficiente para você descobrir. (Ou alguém pode saber).
Na documentação do git :
fonte
Por esse comentário (e eu verifiquei que isso é verdade), a resposta do rado é muito próxima, mas deixa o git em um estado principal desanexado. Em vez disso, remova
HEAD
e use-o para remover<commit-id>
da ramificação em que está:fonte
^
para~1
fazê-lo funcionar.--strategy-option theirs
no final.Aqui está uma maneira de remover de maneira não interativa um específico
<commit-id>
, sabendo apenas o que<commit-id>
você deseja remover:fonte
HEAD
, a fim de evitar uma cabeça desapegada.Como observado antes, o git-rebase (1) é seu amigo. Supondo que os commits estejam em sua
master
filial, você faria:Antes:
Depois de:
Do git-rebase (1):
fonte
--onto master~3 master~1
?MERGE CONFLICT
erro. Usei o cenário mencionado em stackoverflow.com/questions/2938301/remove-specific-commit e não consigo remover o segundo commit nesse exemplo.Se tudo o que você deseja fazer é remover as alterações feitas na revisão 3, convém usar o git revert.
O Git revert simplesmente cria uma nova revisão com alterações que desfaz todas as alterações na revisão que você está revertendo.
O que isso significa é que você retém informações sobre a confirmação indesejada e a confirmação que remove essas alterações.
Isso provavelmente é muito mais amigável se for possível que alguém tenha saído do seu repositório nesse meio tempo, já que a reversão é basicamente apenas uma confirmação padrão.
fonte
Até agora, todas as respostas não abordam a preocupação final:
As etapas a seguir, mas para referência, vamos assumir o seguinte histórico:
C : confirmar apenas após a confirmação a ser removida (limpa)
R : O commit a ser removido
B : confirmar imediatamente antes da confirmação a ser removida (base)
Devido à restrição de "centenas de revisões", estou assumindo as seguintes pré-condições:
Este é um conjunto bastante restritivo de restrições, mas há uma resposta interessante que realmente funciona nesse caso de canto.
Aqui estão os passos:
git branch base B
git branch remove-me R
git branch save
git rebase --preserve-merges --onto base remove-me
Se realmente não houver conflitos, isso deve prosseguir sem mais interrupções. Se houver conflitos, você poderá resolvê-los e /
rebase --continue
ou decidir apenas viver com o constrangimento erebase --abort
.Agora você deve estar em
master
que não possui mais commit R nele. osave
ramificação aponta para onde você estava antes, caso deseje se reconciliar.Você decide como deseja organizar a transferência de todos para o seu novo histórico. Você precisará estar familiarizado com
stash
,reset --hard
echerry-pick
. E você pode excluir osbase
,remove-me
esave
ramosfonte
Eu também aterrei em uma situação semelhante. Use o rebase interativo usando o comando abaixo e, ao selecionar, solte o terceiro commit.
fonte
Então, aqui está o cenário que eu enfrentei e como o resolvi.
aqui
R
está o commit que eu precisava ser removido eI
é um único commit que vem depoisR
Fiz um commit reverso e os esmaguei juntos
Durante o squash de rebase interativo, os 2 últimos commits.
fonte
As respostas do rado e do kareem não fazem nada para mim (apenas a mensagem "O ramo atual está atualizado." Aparece). Possivelmente isso acontece porque o símbolo '^' não funciona no console do Windows. No entanto, de acordo com este comentário, substituir '^' por '~ 1' resolve o problema.
fonte