Pergunta

Alguém sabe como é fácil de desfazer um git rebase?

A única maneira que vem à mente é ir para ele manualmente:

  • git checkout o pai comprometer a ambos os ramos
  • em seguida, criar uma filial temporária de lá
  • cherry-pick todas as submissões à mão
  • substituir o ramo em que eu rebased pelo ramo criado manualmente

Na minha situação atual isto vai funcionar porque eu posso facilmente detectar commits de ambos os ramos (um era meu material, o outro era coisa do meu colega).

No entanto a minha abordagem parece-me abaixo do ideal e propenso a erros (digamos que eu tinha acabado de rebased com 2 dos meus próprios ramos).

Todas as idéias?

Esclarecimento: Eu estou falando sobre um rebase durante o qual um bando de commits foram repetidos. Não só um.

Foi útil?

Solução

A maneira mais fácil seria a de encontrar a cabeça cometem do ramo como era imediatamente antes do rebase começou no reflog ...

git reflog

e para redefinir o ramo atual para ele (com as habituais advertências sobre estar absolutamente certo antes zerando com a opção --hard).

Suponha que a idade commit foi HEAD@{5} no log de ref:

git reset --hard HEAD@{5}

No Windows, você pode precisar de citar a referência:

git reset --hard "HEAD@{5}"

Você pode verificar a história da velha cabeça candidato apenas fazendo um git log HEAD@{5} ( Windows: git log "HEAD@{5}").

Se você não tiver desativado por reflogs filiais você deve ser capaz de simplesmente fazer git reflog branchname@{1} como um rebase destaca a cabeça ramo antes recolocar na cabeça final. Eu iria verificar isso, mas como eu não ter verificado isso recentemente.

Por padrão, todos os reflogs são ativados para repositórios não-nuas:

[core]
    logAllRefUpdates = true

Outras dicas

Na verdade, rebase salva o ponto de partida para ORIG_HEAD por isso esta é geralmente tão simples como:

git reset --hard ORIG_HEAD

No entanto, o reset, rebase e merge Tudo Salvar o ponteiro HEAD original em ORIG_HEAD assim, se você tiver feito qualquer um desses comandos desde o rebase você está tentando desfazer então você terá que usar o reflog.

obras resposta de Charles, mas você pode querer fazer isso:

git rebase --abort

para limpar após o reset.

Caso contrário, você pode receber a mensagem “Interactive rebase already started”.

git reflog irá mostrar-lhe todas as mudanças antes e depois da alteração de base, e permitem que você encontrar o caminho certo para repor. Mas eu estou surpreso que ninguém mencionou isso outra maneira super simples aqui ainda:

Rebase deixa o velho estado como ORIG_HEAD, para que possa reverter o último rebase executando:

git reset --hard ORIG_HEAD

A redefinição do ramo para o pendurada cometer objeto de sua velha dica é, naturalmente, a melhor solução, porque restaura o estado anterior sem despender qualquer esforço. Mas se acontecer de você ter perdido esses commits (f.ex. porque você lixo-coletados seu repositório, entretanto, ou este é um clone fresco), você sempre pode rebase o ramo novamente. A chave para isso é a chave --onto.

Vamos dizer que você tinha um ramo tópico imaginativamente chamado topic, que ramificou-se master quando a ponta de master foi o 0deadbeef cometer. Em algum ponto, enquanto no ramo topic, você fez git rebase master. Agora você quer desfazer essa. Veja como:

git rebase --onto 0deadbeef master topic

Isso vai levar todos os commits em topic que não estão na master e reproduzi-los em cima de 0deadbeef.

Com --onto, você pode reorganizar a sua história em praticamente qualquer forma que seja .

se divertir. : -)

Na verdade, eu colocar uma etiqueta de cópia de segurança no ramo antes de eu fazer qualquer operação não trivial (a maioria rebases são triviais, mas eu faria isso se parece em qualquer lugar complexo).

Em seguida, restaurando é tão fácil como git reset --hard BACKUP.

No caso de você tinha empurrado seu ramo para remoto repositório (geralmente de origem) e depois de ter feito um rebase succesfull (sem fusão) (git rebase --abort dá "Não rebase em andamento"), você pode facilmente ramo de reset usando comando:

git redefinir origem --hard / {branchname}

Exemplo:

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is ahead of 'origin/{branchName}' by 135 commits.
  (use "git push" to publish your local commits)

nothing to commit, working directory clean

$ ~/work/projects/{ProjectName} $ git reset --hard origin/{branchName}
HEAD is now at 6df5719 "Commit message".

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is up-to-date with 'origin/{branchName}.

nothing to commit, working directory clean

No caso de você não ter concluído o rebase e no meio dela, os seguintes trabalhos:

git rebase --abort

Usando reflog não trabalho para mim.

O que funcionou para mim foi semelhante ao descrito aqui . Abra o arquivo em .git / logs / refs nomeado após o ramo que foi rebased e encontrar a linha que contém "REBASE finsihed", algo como:

5fce6b51 88552c8f Kris Leech <me@example.com> 1329744625 +0000  rebase finished: refs/heads/integrate onto 9e460878

Checkout o segundo commit listado na linha.

git checkout 88552c8f

Uma vez confirmada esta continha as minhas alterações perdidos I ramificada e soltou um suspiro de alívio.

git log
git checkout -b lost_changes

Para vários commits, lembre-se que qualquer cometer referências toda a história que conduz a que cometer. Assim, em resposta Charles', deve ler 'o velho comprometer' como 'o mais novo dos antigos commits'. Se você redefinir a que cometer, em seguida, toda a história que conduz a que cometem reaparecerá. Isso deve fazer o que quiser.

Após a solução de @Allan e @Zearin, eu desejo que eu poderia simplesmente fazer um comentário embora, mas eu não faço reputação suficiente, então eu usei o seguinte comando:

Em vez de fazer git rebase -i --abort (note o -i ) eu tive que simplesmente fazer git rebase --abort ( sem -i ).

Usando tanto -i e --abort ao mesmo tempo faz com que o Git para me mostrar uma lista de uso / opções.

Então, o meu status de ramo anterior e atual com esta solução é:

matbhz@myPc /my/project/environment (branch-123|REBASE-i)
$ git rebase --abort

matbhz@myPc /my/project/environment (branch-123)
$

Se você rebased com sucesso contra filial remota e não pode git rebase --abort você ainda pode fazer alguns truques para salvar seu trabalho e não têm empurra forçados. Suponha que a sua filial atual que foi rebased por engano é chamado your-branch e está rastreando origin/your-branch

  • git branch -m your-branch-rebased # renomeação ramificação actual
  • git checkout origin/your-branch # checkout para último estado que é conhecido por origem
  • git checkout -b your-branch
  • verificação git log your-branch-rebased, comparar com git log your-branch e definir commits que estão faltando your-branch
  • git cherry-pick COMMIT_HASH para cada commit em your-branch-rebased
  • empurrar as alterações. Por favor, ciente de que dois ramos locais estão associados com remote/your-branch e você deve empurrar única your-branch

Vamos dizer que eu rebase mestre para o meu ramo de recurso e eu recebo 30 novos commits que algo quebra. Descobri que muitas vezes é mais fácil apenas remover os commits ruins.

git rebase -i HEAD~31

rebase interativo para os últimos 31 commits (não faz mal se você escolher a forma como muitos).

Basta tomar os commits que você quiser se livrar de e marcá-los com "d" em vez de "pegar". Agora os commits são excluídos efetivamente desfazendo o rebase (se você remover apenas os commits você só tem quando rebasing).

Se você estiver em um ramo que você pode usar:

git reset --hard @{1}

Não existe apenas um registro de referência para a cabeça (obtido por git reflog), há também reflogs para cada ramo (obtido por git reflog <branch>). Então, se você estiver em master então git reflog master irá listar todas as alterações a esse ramo. Você pode referir-se que as mudanças por master@{1}, master@{2}, etc.

git rebase normalmente irá mudar CABEÇA várias vezes, mas a ramificação atual será atualizada apenas uma vez.

@{1} é simplesmente um atalho para o ramo atual , por isso é igual para master@{1} se você estiver em master.

git reset --hard ORIG_HEAD não vai funcionar se você usou git reset durante uma rebase interativo.

Para iniciantes / alguém com muito medo de fazer um hard reset, você pode fazer o checkout da cometem do reflog, e depois salvá-lo como um novo ramo.

git reflog

Encontre o commit antes de você começou rebasing. Você pode precisar rolar ainda mais para baixo para encontrá-lo (pressione Enter ou PageDown). Tome nota do número CABEÇA e substituí-57:

git checkout HEAD@{57}

Revisão do ramo / commits, se parece bom criar um novo ramo usando este CABEÇA:

git checkout -b new_branch_name

git redefinir origem --hard / {branchname}

é a solução correta para repor as suas alterações locais feitas por rebase.

O que eu costumo fazer é git reset #commit_hash

para a última confirmação onde eu acho que rebase não teve nenhum efeito.

então git pull

Agora, o seu ramo deve corresponder exatamente como mestre e commits rebased não deveria estar nele.

Agora pode-se apenas a cereja-escolher os commits neste ramo.

Se você estragar algo dentro de um rebase git, por exemplo, git rebase --abort, enquanto você tem arquivos não confirmadas, eles serão perdidos e git reflog não vai ajudar. Isso aconteceu comigo e você terá que pensar fora da caixa aqui. Se você tiver sorte como eu e usar IntelliJ WebStorm pode right-click->local history e pode reverter para um estado anterior do seu arquivo / pastas não importa o que erros você tem feito com versão. É sempre bom ter uma outra prova de falhas em execução.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top