Como posso desfazer facilmente uma rebase do git?
Minhas idéias atuais são apenas abordagens manuais:
git checkout
no pai de confirmação para os dois ramos- Crie uma ramificação temporária a partir daí
git cherry-pick
tudo confirma manualmente- substituir a ramificação na qual refiz a nova ramificação criada manualmente
Na minha situação atual, isso funcionaria porque eu posso identificar facilmente commits de ambos os ramos (um era o meu material, o outro era o material do meu colega).
No entanto, minha abordagem me parece subótima e propensa a erros (digamos que eu acabei de fazer uma nova redefinição com duas de minhas próprias ramificações).
Esclarecimento : Estou falando de uma re-avaliação durante a qual um monte de confirmações foram repetidas. Não é só um.
git
rebase
git-rebase
undo
webmat
fonte
fonte
Respostas:
A maneira mais fácil seria encontrar o commit principal do ramo, como era imediatamente antes do rebase começar no reflog ...
e redefinir a ramificação atual (com as advertências usuais sobre ter certeza absoluta antes de redefinir com a
--hard
opção).Suponha que o commit antigo estivesse
HEAD@{5}
no log ref:No Windows, pode ser necessário citar a referência:
Você pode verificar o histórico do candidato antigo, basta fazer um
git log HEAD@{5}
( Windowsgit log "HEAD@{5}"
:).Se você não desabilitou os reflogs de ramificação, poderá fazer isso simplesmente
git reflog branchname@{1}
como uma rebase desanexa a cabeça da ramificação antes de recolocá-la na cabeça final. Gostaria de verificar isso novamente, embora não tenha verificado isso recentemente.Por padrão, todos os reflogs são ativados para repositórios não bare:
fonte
git log -g
(dica do progit.org/book de Scott Chacon ).git rebase --abort
(-i
não faz sentido--abort
) é para abandonar uma rebase que não foi concluída - seja porque houve conflitos ou porque foi interativa ou ambas; não se trata de desfazer uma rebase bem-sucedida, que é a questão. Você usariarebase --abort
oureset --hard
dependendo da situação em que estava. Não precisa fazer as duas coisas.git tag BACKUP
. Você pode retornar a ele se algo der errado:git reset --hard BACKUP
commit:
ao contráriorebase:
. Parece óbvio, mas isso me confundiu um pouco.git reset --hard ORIG_HEAD
truque também não seria feito imediatamente após a recuperação acidental?Na verdade, o rebase salva seu ponto de partida para
ORIG_HEAD
que, geralmente, seja tão simples quanto:No entanto, o
reset
,rebase
emerge
todos salvam oHEAD
ponteiro original paraORIG_HEAD
que, se você executou algum desses comandos desde o rebase que está tentando desfazer, precisará usar o reflog.fonte
ORIG_HEAD
não seja mais útil, você também pode usar abranchName@{n}
sintaxe, onden
é a enésima posição anterior do ponteiro de ramificação. Portanto, por exemplo, se você redefinir afeatureA
ramificação para suamaster
ramificação, mas não gostar do resultado dagit reset --hard featureA@{1}
redefinição , você pode simplesmente redefinir a ramificação exatamente para onde estava antes da redefinição. Você pode ler mais sobre a sintaxe branch @ {n} nos documentos oficiais do Git para revisões .git rebase --abort
pensamento.git 2.17.0
.git reset --hard ORIG_HEAD
pode usar repetidamente para reverter repetidamente. Digamos que, se A --- rebase para --- --- B rebase para --- C, agora eu estou em C, eu posso voltar a uma usando duas vezesgit reset --hard ORIG_HEAD
git rebase --abort
?A resposta de Charles funciona, mas você pode fazer o seguinte:
para limpar após o
reset
.Caso contrário, você poderá receber a mensagem “
Interactive rebase already started
”.fonte
Redefinir a ramificação para o objeto de confirmação pendente de sua dica antiga é obviamente a melhor solução, pois restaura o estado anterior sem fazer nenhum esforço. Mas se você perdeu esses commits (por exemplo, porque você coletou lixo no repositório enquanto isso, ou este é um novo clone), sempre é possível refazer a ramificação novamente. A chave para isso é o
--onto
interruptor.Digamos que você tenha um ramo de tópico chamado imaginativamente
topic
, que você tenha ramificadomaster
quando a dicamaster
era o0deadbeef
commit. Em algum momento enquanto estava notopic
galho, você o fezgit rebase master
. Agora você quer desfazer isso. Aqui está como:Isso levará todos os commits
topic
que não estiveremmaster
ativados e os reproduzirá em cima de0deadbeef
.Com
--onto
, você pode reorganizar sua história em praticamente qualquer forma .Diverta-se. :-)
fonte
--onto
e-i
você pode reorganizar sua história em praticamente qualquer forma. Use gitk (ou gitx no mac) para ver as formas que você cria :-).Na verdade, eu coloquei uma tag de backup na ramificação antes de executar qualquer operação não trivial (a maioria das rebotes é trivial, mas eu faria isso se parecer complexa).
Então, restaurar é tão fácil quanto
git reset --hard BACKUP
.fonte
branchName@{n}
sintaxe. Aquin
está a enésima posição anterior do ponteiro da ramificação. Assim, por exemplo, se você redefinir afeatureA
ramificação para suamaster
ramificação, mas não gostar do resultado dagit reset --hard featureA@{1}
redefinição , você pode simplesmente redefinir a ramificação exatamente para onde estava antes de fazer a redefinição. Você pode ler mais sobre abranch@{n}
sintaxe nos documentos oficiais do Git para revisões .HEAD
do ramo é temporariamente armazenadoORIG_HEAD
. Mas a técnica de usar um rótulo de ramificação de backup também funciona, são apenas mais etapas.Caso você tenha enviado sua ramificação para o repositório remoto (geralmente a origem) e depois tenha feito uma nova recuperação bem-sucedida (sem mesclagem) (
git rebase --abort
fornece "Nenhuma recuperação em andamento"), é possível redefinir facilmente a ramificação usando o comando:Exemplo:
fonte
Usar
reflog
não funcionou para mim.O que funcionou para mim foi semelhante ao descrito aqui . Abra o arquivo em .git / logs / refs com o nome da ramificação que foi rebatizada e localize a linha que contém "rebase finihed", algo como:
Faça o checkout do segundo commit listado na linha.
Uma vez confirmado que isso continha minhas mudanças perdidas, eu me ramifiquei e soltei um suspiro de alívio.
fonte
Para várias confirmações, lembre-se de que qualquer confirmação faz referência a todo o histórico que antecede essa confirmação. Portanto, na resposta de Charles, leia "o antigo commit" como "o mais novo do antigo commit". Se você redefinir para esse commit, todo o histórico que antecedeu esse commit reaparecerá. Isso deve fazer o que você quiser.
fonte
Seguindo a solução de @Allan e @Zearin, eu gostaria de poder simplesmente fazer um comentário, mas não tenho reputação suficiente, então usei o seguinte comando:
Em vez de fazer
git rebase -i --abort
(observe o -i ), eu tinha que simplesmente fazergit rebase --abort
( sem o -i ).Usando ambos
-i
e--abort
ao mesmo tempo faz com que o Git me mostre uma lista de opções / uso.Portanto, meu status de filial anterior e atual com esta solução é:
fonte
Se você reprovou com êxito contra a filial remota e
git rebase --abort
ainda não pode, pode fazer alguns truques para salvar seu trabalho e não possui impulsos forçados. Suponha que sua ramificação atual que foi rebatizada por engano seja chamadayour-branch
e esteja rastreandoorigin/your-branch
git branch -m your-branch-rebased
# renomear ramificação atualgit checkout origin/your-branch
# checkout para o estado mais recente conhecido por sua origemgit checkout -b your-branch
git log your-branch-rebased
, comparargit log your-branch
e definir confirmações ausentes doyour-branch
git cherry-pick COMMIT_HASH
para cada confirmação emyour-branch-rebased
remote/your-branch
e você deve enviar apenasyour-branch
fonte
Digamos que eu refiz o master para o meu ramo de recursos e recebo 30 novos commits que quebram algo. Descobri que muitas vezes é mais fácil remover os commits ruins.
Rebase interativo para os últimos 31 commits (não dói se você escolher muitos).
Simplesmente aceite os commits dos quais você deseja se livrar e marque-os com "d" em vez de "pick". Agora, as confirmações são excluídas efetivamente, desfazendo a rebase (se você remover apenas as confirmações que acabou de obter ao rebasear).
fonte
Para iniciantes / qualquer pessoa com muito medo de fazer uma redefinição forçada, você pode retirar o commit do reflog e salvá-lo como um novo ramo.
Encontre o commit antes de começar a rebasear. Pode ser necessário rolar mais para baixo para encontrá-lo (pressione Enter ou PageDown). Anote o número HEAD e substitua 57:
Revise a ramificação / confirmações, se parecer bom, crie uma nova ramificação usando este HEAD:
fonte
Se você estiver em uma filial, poderá usar:
Não há apenas um log de referência para HEAD (obtido por
git reflog
), também há reflogs para cada ramo (obtido porgit reflog <branch>
). Portanto, se você estiver ligadomaster
,git reflog master
listará todas as alterações nesse ramo. Você pode referir-se que as mudanças pormaster@{1}
,master@{2}
etc.git rebase
normalmente mudará HEAD várias vezes, mas a ramificação atual será atualizada apenas uma vez.@{1}
é simplesmente um atalho para a ramificação atual ; portanto, é igual amaster@{1}
se você estiver ativadomaster
.git reset --hard ORIG_HEAD
não funcionará se você tiver usadogit reset
durante uma interaçãorebase
.fonte
O que eu costumo fazer é
git reset #commit_hash
até o último commit, onde acho que rebase não teve efeito.
então
git pull
Agora sua ramificação deve corresponder exatamente como mestre e confirmações rebased não devem estar nela.
Agora pode-se escolher os commits neste ramo.
fonte
Tentei todas as sugestões com redefinição e reflog sem sucesso. A restauração do histórico local do IntelliJ resolveu o problema de arquivos perdidos
fonte
git reset --hard origem / {branchName}
é a solução correta para redefinir todas as alterações locais feitas por rebase.
fonte
origin/branch
você, poderá perder as alterações entre HEAD e esse ponto. Você não quer isso de um modo geral.Se você estragar alguma coisa dentro de uma rebase do git, por exemplo
git rebase --abort
, enquanto você tiver arquivos não confirmados, eles serão perdidos egit reflog
não ajudarão. Isso aconteceu comigo e você precisará pensar fora da caixa aqui. Se você tiver sorte como eu e usar o IntelliJ Webstorm, poderáright-click->local history
e poderá reverter para um estado anterior de seus arquivos / pastas, independentemente dos erros cometidos com o software de controle de versão. É sempre bom ter outro à prova de falhas em execução.fonte
git rebase --abort
interrompe uma rebase ativa, não desfaz uma rebase. Além disso, usar dois VCS ao mesmo tempo é uma má ideia. É um recurso interessante no software Jetbrains, mas você não deve usar os dois. É melhor apenas aprender o Git, principalmente ao responder a perguntas no Stack Overflow sobre o Git.