Posso recuperar uma ramificação após sua exclusão no Git?

1067

Se eu executar git branch -d XYZ, existe uma maneira de recuperar a ramificação? Existe uma maneira de voltar como se eu não tivesse executado o comando delete branch?

prosseek
fonte
4
Uma observação realmente impressionante a fazer sobre a resposta aceita é que ela funciona mesmo que a ramificação tenha sido excluída na origem! Acabei de recuperar várias ramificações que não tinha mais localmente depois que elas foram excluídas acidentalmente na origem.
theblang

Respostas:

1955

Sim, você deve conseguir git reflogencontrar o SHA1 para o commit na ponta do seu ramo excluído e, em seguida, apenas git checkout [sha]. E quando você estiver nessa submissão, poderá git checkout -b [branchname]recriar a ramificação a partir daí.


Os nossos agradecimentos a @Cascabel por esta versão condensada / one-liner.

Você pode fazer isso em uma etapa:

git checkout -b <branch> <sha>
tfe
fonte
477
Você pode fazê-lo em uma única etapa: git checkout -b <branch> <sha>.
Cascabel
200
Dica rápida - se você acabou de excluir a ramificação, verá algo parecido com isto no seu terminal - "Ramificação excluída <sua filial> (era <sha>)". E então é super fácil - basta usar isso <sha>. Por exemplo, como mencionado acima -git checkout -b <branch> <sha>
Snowcrash
6
sim apenas rolar para cima em seu terminal (a menos que você fez CMD+K)
neaumusic
42
Use git reflog --no-abbrevpara ver o total <sha>que está sendo abreviado por padrão.
Jkulak
5
Para qualquer pessoa como eu, que teve problemas para encontrar o sha do ramo excluído: eu consegui git checkout remotes/origin/deleted_branch.
22417 Jeffrey Irwin
161

Na maioria das vezes, as confirmações inacessíveis estão no reflog. Portanto, a primeira coisa a tentar é olhar para o reflog usando o comando git reflog(que exibe o reflog HEAD).

Talvez algo mais fácil se a cometer fazia parte de um ramo específico ainda existente é usar o comando git reflog name-of-my-branch. Também funciona com um controle remoto, por exemplo, se você forçar o envio (conselhos adicionais: sempre prefira git push --force-with-leaseque evite erros e seja mais recuperável).


Se suas confirmações não estiverem no seu reflog (talvez porque excluídas por uma ferramenta de terceiros que não escreva no reflog), recuperei com êxito uma ramificação redefinindo minha ramificação para o sha da confirmação encontrada usando um comando como esse (ele cria um arquivo com todos os commits dangling):

git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt

Se você deve usá-lo mais de uma vez (ou quiser salvá-lo em algum lugar), também pode criar um alias com esse comando ...

git config --global alias.rescue '!git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt'

e use-o com git rescue

Para investigar confirmações encontradas, você pode exibir cada confirmação usando alguns comandos para procurá-las.

Para exibir os metadados de confirmação (autor, data de criação e mensagem de confirmação):

git cat-file -p 48540dfa438ad8e442b18e57a5a255c0ecad0560

Para ver também as diferenças:

git log -p 48540dfa438ad8e442b18e57a5a255c0ecad0560

Depois de encontrar seu commit, crie um branch nesse commit com:

git branch commit_rescued 48540dfa438ad8e442b18e57a5a255c0ecad0560

Para aqueles que estão no Windows e gostam de GUIs, você pode recuperar facilmente confirmações (e também arquivos temporários não confirmados) com GitExtensions usando o recurso Repository=> Git maintenance=>Recover lost objects...


Um comando semelhante para recuperar facilmente arquivos temporários excluídos: https://stackoverflow.com/a/58853981/717372

Philippe
fonte
2
Ajuda enorme. Eu tinha um commit perdido que nunca estava no meu repositório local. O primeiro comando que você tem lá em cima me ajudou a encontrá-lo no servidor. +1
Sean Adkinson
1
esse apelido de resgate do git é uma dádiva de Deus !!! Muito obrigado por contribuir!
72A12F4E
2
Você salvou minha vida.
Jed Lynch
A resposta de Patrick Koorevaar me ajudou, porque não sei meus últimos commits ramificados excluídos <sha>.
Monir Khan 28/02
@ Monir-Khan e? O que devo concluir? A resposta de Patrick é apenas uma cópia / pasta do meu comando (com um erro: ele esqueceu de filtrar as confirmações) ...
Philippe
45

Se você gosta de usar uma GUI, pode executar toda a operação com o gitk.

gitk --reflog

Isso permitirá que você veja o histórico de consolidação do ramo como se o ramo não tivesse sido excluído. Agora, basta clicar com o botão direito do mouse no commit mais recente do ramo e selecionar a opção de menu Create new branch.

nobar
fonte
28

A melhor solução votada realmente é mais do que o solicitado:

git checkout <sha>
git checkout -b <branch>

ou

git checkout -b <branch> <sha>

mova você para o novo ramo junto com todas as alterações recentes que você pode ter esquecido de confirmar. Esta pode não ser a sua intenção, especialmente quando está no "modo de pânico" depois de perder o ramo.

Uma solução mais limpa (e mais simples) parece ser a única opção (depois que você encontrou o <sha>com git reflog):

git branch <branch> <sha>

Agora, nem sua ramificação atual nem as alterações não confirmadas são afetadas. Em vez disso, apenas uma nova ramificação será criada até o <sha>.

Se não for a dica, ainda funcionará e você obterá uma ramificação mais curta, e poderá tentar novamente com o novo <sha>e o novo nome da ramificação até acertar.

Por fim, você pode renomear o ramo restaurado com sucesso para o que foi nomeado ou qualquer outra coisa:

git branch -m <restored branch> <final branch>

Escusado será dizer que a chave para o sucesso foi encontrar o commit certo <sha>, então nomeie seus commits com sabedoria :)

Dmitri Zaitsev
fonte
14

Somando-se TFE resposta : há também a git-resurrect.sh script na contrib/área das fontes do Git (em repositório git.git), o que pode ajudá-lo.

git-resurrect <name>tenta encontrar traços de uma ponta de ramificação chamada <name>e tenta ressuscitá-la. Atualmente, o reflog é pesquisado por mensagens de checkout e -rtambém com mensagens de mesclagem. Com -me -t, o histórico de todas as refs é verificado para Merge <name> into other/ Merge <other> into <name>(respectivamente) confirmar assuntos, o que é bastante lento, mas permite ressuscitar ramificações de tópicos de outras pessoas.

Jakub Narębski
fonte
1
Agora funcionou para mim, embora eu tenha que adicionar / usr / lib / git-core / ao meu PATH. Mas não executou o milagre que eu estava esperando :(
AmanicA
10

Eu usei os seguintes comandos para encontrar e recuperar minha ramificação excluída. Os primeiros passos são da descrição do gcb.

$ git fsck --full --no-reflogs --unreachable --lost-found > lost
$ cat lost | cut -d\  -f3 > commits
$ cat commits | xargs -n 1 git log -n 1 --pretty=oneline

Agora procure o ID de confirmação do git (GIT-SHA) com base nos comentários de confirmação e use-o no comando abaixo. Faça o checkout de uma nova filial chamada NEW-BRANCH com o GIT-SHA encontrado anteriormente:

$ git checkout -b NEW-BRANCH GIT-SHA
Patrick Koorevaar
fonte
Muito obrigado. Demorou um pouco para procurar o nome, mas o tempo valeu a pena. Se houver uma maneira de pesquisar também na sequência de mensagens de confirmação, seria muito melhor.
Monir Khan 28/02
9

Se você não tem um reflog, por exemplo. porque você está trabalhando em um repositório vazio que não tem o reflog ativado e a confirmação que você deseja recuperar foi criada recentemente, outra opção é encontrar objetos de confirmação criados recentemente e examiná-los.

De dentro do .git/objectsdiretório, execute:

find . -ctime -12h -type f | sed 's/[./]//g' | git cat-file --batch-check | grep commit

Ele localiza todos os objetos (confirmações, arquivos, tags etc.) criados nas últimas 12 horas e os filtra para mostrar apenas confirmações. Verificá-las é um processo rápido.

Eu tentaria o script git-ressurect.sh mencionado na resposta de Jakub primeiro.

Robert Knight
fonte
1
Boa ideia alternativa! Seu comando gera um erro. O problema está na parte "12h" (na verdade o "h"). Depois que eu removi o "h", tudo funcionou bem. De man find: "-ctime n - o status do arquivo foi alterado pela última vez há * 24 horas." Portanto, também devemos mudar de 12 para 0,5 para ter o comportamento esperado das últimas 12 horas.
Paginuca
1
Estou usando o OS X 10.8 aqui, então os sinalizadores 'find' acima são baseados na versão fornecida.
Robert Knight
1
Sim, com certeza o problema está nas versões! Por isso votei sua resposta em primeiro lugar! Acabei de comentar para que as pessoas percebam que os parâmetros podem ser diferentes.
Paginuca
9

Para usuários do GitHub sem o Git instalado:

Se você quiser restaurá-lo no site do GitHub , poderá usar a API deles para obter uma lista de eventos relacionados a repo:

Primeiro

  • encontre esses SHAs (confirmar hashes):

    curl -i https://api.github.com/repos/PublicUser/PublicRepo/events

    ... ou para acordos privados:

    curl -su YourUserName https://api.github.com/repos/YourUserName/YourProject/events

    (será solicitada a senha do GitHub)

    • (Se o repositório exigir autenticação de dois fatores, consulte os comentários sobre esta resposta abaixo.)

Próximo

  • acesse o GitHub e crie um novo ramo temporário que será excluído para sempre (o Chrome é preferível).

   • Vá para as ramificações e exclua essa.

   •   Na mesma página, sem recarregar , abra o DevTools, painel Rede. Agora prepare ...

   • Clique em restaurar. Você notará uma nova "linha". Clique com o botão direito do mouse e selecione "Copiar como cURL" e salve este texto em algum editor.

   • Anexar ao final da linha copiada de código, um presente: -H "Cookie=".

Agora você deve obter algo como:

    curl 'https://github.com/UserName/ProjectName/branches?branch=BranchSHA&name=BranchName' -H 'Cookie:' -H 'Origin: https://github.com' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: en-US' -H 'User-Agent: User-Agent' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'Accept: */*' -H 'Referer: https://github.com/UserName/ProjectName/branches' -H 'X-Requested-With: XMLHttpRequest' -H 'Connection: keep-alive' --data 'utf8=%E2%9C%93&authenticity_token=token' --compressed

Passo final

  • substitua "BranchSHA" pelo seu SHA-hash e BranchName pelo nome desejado (BTW, é ótimo hackear o nome da ramificação da Web). Se você não for muito lento, precisará fazer essa solicitação de qualquer maneira. Por exemplo, basta copiar e colar em um terminal.

PS

Sei que essa pode não ser a "solução mais simples" ou a "certa", mas é oferecida no caso de alguém achar útil.

Maxim Mazurok
fonte
1
O acima é um dos poucos por aí que não depende git refloge, portanto, foi útil, por exemplo, ao excluir uma ramificação remota e perder o acesso ao computador que foi feito, para que não seja possível obter nada útil a frio reflog. Observe que ao usar a autenticação OAuth ou de dois fatores no Github, o curlcomando fica no formato: curl -u username:token https://api.github.com/useroucurl -H "Authorization: token TOKEN" https://api.github.com/repos/USER_OR_ORG_NAME/REPO_NAME/events
TT-- 18/04/19
@ TT-- uau, estou feliz que ajudou! e obrigado pela sua contribuição em relação auth token de :)
Maxim Mazurok
8

Pelo meu entendimento, se o ramo a ser excluído pode ser alcançado por outro ramo, você pode excluí-lo com segurança usando

git branch -d [branch]

e seu trabalho não está perdido. Lembre-se de que um ramo não é um instantâneo, mas um ponteiro para um. Então, quando você exclui uma ramificação, exclui um ponteiro.

Você nem perderá o trabalho se excluir um ramo que não pode ser alcançado por outro. É claro que não será tão fácil quanto verificar o hash de confirmação, mas você ainda pode fazê-lo. É por isso que o Git não consegue excluir um ramo que não pode ser alcançado usando -d. Em vez disso, você tem que usar

git branch -D [branch]

Isso faz parte de um vídeo obrigatório de Scott Chacon sobre o Git. Verifique o minuto 58:00 quando ele fala sobre galhos e como excluí-los.

Introdução ao Git com Scott Chacon do GitHub

fabiopagoti
fonte
7
Como isso está ajudando a responder à pergunta?
Dmitri Zaitsev
6
Dizer ao solicitante que as ramificações não contêm conteúdo, mas na verdade são indicadores. Você não precisa ter medo de excluir ramificações .. você pode criar novas apontando para o mesmo commit que o excluído .... Uau! Ainda me lembro de quando fiz essa pergunta. Bons tempos desde 2012!
Fabiopagoti
1
Teve que rolar três telas para, pelo menos, encontrar uma resposta que resolvesse o problema: excluir uma ramificação é excluir um mero ponteiro. Nenhuma situação de perda de dados aqui, a única coisa a recuperar é para onde estava apontando. As respostas enviadas diretamente reflogsão apenas um exagero.
RomainValeri 18/01/19
5

Certifique-se de executar tudo isso localmente e confirme se o seu repositório está no estado desejado antes de enviar para o Bitbucket Cloud. Também pode ser uma boa ideia clonar seu repo atual e testar essas soluções primeiro.

  1. Se você acabou de excluir a ramificação, verá algo assim no seu terminal:
    Deleted branch <your-branch> (was <sha>)

2.Para restaurar a ramificação, use:

    git checkout -b <branch> <sha>

Se você não conhece o 'sha' no topo da sua cabeça, pode:

  1. Encontre o 'sha' para o commit na ponta do seu ramo excluído usando:
    git reflog
  1. Para restaurar a ramificação, use:
    git checkout -b <branch> <sha>

Se seus commits não estão no seu reflog:

  1. Você pode tentar recuperar uma ramificação redefinindo sua ramificação para o sha da confirmação encontrada usando um comando como:
    git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt

2. Você pode exibir cada confirmação usando um destes:

    git log -p <commit>
    git cat-file -p <commit>
uyghurbeg
fonte
4

Para recuperar uma ramificação excluída, primeiro passe pelo histórico de reflog,

git reflog -n 60

Onde n se refere ao último n confirma. Em seguida, encontre a cabeça adequada e crie um galho com essa cabeça.

git branch testbranch HEAD@{30}
sajin tm
fonte
4

Eu refiz uma ramificação do controle remoto para tentar limpar alguns commits que eu não queria e iria escolher os que eu queria. Claro que escrevi os SHAs errado ...

Aqui está como os encontrei (principalmente uma interface / interação mais fácil com base nas respostas aqui):

Primeiro, gere uma lista de confirmações soltas no seu log. Faça isso o mais rápido possível e pare de trabalhar, pois esses podem ser despejados pelo coletor de lixo.

git fsck --full --no-reflogs --unreachable --lost-found > lost

Isso cria um lostarquivo com todas as confirmações que você precisará examinar. Para simplificar nossa vida, vamos cortar apenas o SHA:

cat lost | cut -d\  -f3 > commits

Agora você tem um commitsarquivo com todas as confirmações que precisa procurar.

Supondo que você esteja usando o Bash, a etapa final:

for c in `cat commits`; do  git show $c; read; done

Isso mostrará as informações diff e commit de cada um deles. E espere você pressionar Enter. Agora anote todos os que você deseja e, em seguida, escolha-os. Depois de terminar, basta pressionar Ctrl-C.

gcb
fonte
1

Primeiro, vá para git batch, a mudança para o seu projeto, como:

cd android studio project
cd Myproject
then type :
git reflog

Todos vocês têm uma lista das alterações e o número de referência recebe o número de referência e, em seguida, efetua o checkout
no android studio ou no git betcha. outra solução, pegue o número de referência e vá para o android studio, clique em git branches e clique na etiqueta de checkout ou na revisão após o número de referência.

FAHAD HAMMAD ALOTAIBI
fonte
1

Adicionando à resposta do tfe, você pode se recuperar com esse processo mencionado, a menos que os commit não sejam coletados como lixo. A ramificação Git é simplesmente um ponteiro para um commit específico na árvore de commit. Mas se você excluir o ponteiro e as confirmações nesse ramo não forem mescladas com outro ramo existente, o git o tratará como confirmações pendentes e os removerá durante a coleta de lixo, que pode ser executada automaticamente periodicamente.

Se sua ramificação não foi mesclada a uma ramificação existente e se foi coletada com lixo, você perderá todas as confirmações até o ponto em que a ramificação foi bifurcada em uma ramificação existente.

Rajeshwar Agrawal
fonte
1

Um problema relacionado: cheguei a esta página depois de pesquisar "como saber o que são ramificações excluídas".

Ao excluir muitos ramos antigos, senti que excluí por engano um dos ramos mais novos, mas não sabia o nome para recuperá-lo.

Para saber quais ramificações foram excluídas recentemente, faça o seguinte:

Se você for ao seu URL do Git, será algo assim:

https://your-website-name/orgs/your-org-name/dashboard

Então você pode ver o feed do que é excluído e por quem, no passado recente.

Manohar Reddy Poreddy
fonte
Certo. A resposta acima é para o GitHub. Instalamos o GitHub localmente. Obrigado por fazer a pergunta.
Manohar Reddy Poreddy
1

Eu fiz isso no computador que eu excluo o ramo:

git reflog

resposta:

74b2383 (develope) HEAD@{1}: checkout: moving from master to develope
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{2}: checkout: moving from develope to master
74b2383 (develope) HEAD@{3}: checkout: moving from master to develope
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{4}: reset: moving to HEAD
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{5}: clone: from http://LOCALGITSERVER/myBigProject/Android.git

e eu recupero o ramo com este comando:

git checkout -b newBranchName 74b2383

Ammar Bozorgvar
fonte
0

Apenas usando git reflognão retornou o shapara mim. Apenas o commit id(que tem 8 caracteres e um sha é muito mais longo)

Então eu usei git reflog --no-abbrev

E então faça o mesmo como mencionado acima: git checkout -b <branch> <sha>

MarvinVK
fonte
você sempre pode usar o sha de 8 caracteres abreviados, você não tem que usar o sha completo
Michael Dreher
0

SE você estiver usando o VSCode ... e você sincronizou sua filial com o servidor em algum momento antes de excluí-lo ...

Observe que git branch delete exclui apenas a cópia local, não a cópia no servidor. Primeiro, no painel Git (ícone git na barra de ferramentas esquerda), examine as ramificações e veja se sua ramificação ainda está lá em "origin / your_branch_name". Nesse caso, basta selecionar isso e você deverá recuperar seu código (sugira que você copie / cole / salve imediatamente localmente em outro lugar).

Se você não viu uma "origin / your_branch_name", instale a extensão GitLens. Isso permite que você vasculhe visualmente os repositórios do servidor e localize a cópia que sincronizou com o servidor. Se você possui vários repositórios, observe que pode ser necessário ter pelo menos um arquivo aberto no repositório desejado para fazer com que o repositório apareça no GitLens. Então:

  1. Abra o painel GitLens

  2. Expanda o repositório

  3. Você deve ver uma lista de categorias: Ramos / Contribuintes / Remotos / Stashes / etc

Você deve encontrar YourLostTreasure em "Ramos" ou possivelmente em "Remotos -> Origens". Felizmente, você verá uma ramificação com o nome desejado - se você a expandir, deverá ver os arquivos alterados nessa ramificação. Clique duas vezes nos nomes dos arquivos para abri-los e faça backup imediato desse código.

Se você não vir imediatamente seu ramo perdido, dê uma olhada e, se encontrar algo promissor, abra-o imediatamente e pegue o código. Eu tive que bisbilhotar um pouco até encontrar TheGoldenBranch, e mesmo assim o código estava faltando nos últimos um ou dois salvos (possivelmente porque eu não sincronizei com o servidor antes de tentar fazer uma mesclagem de filial, mas clicar acidentalmente) Branch-Delete). Minha pesquisa foi desnecessariamente prolongada porque, quando eu encontrei o ramo pela primeira vez, não tinha certeza absoluta de que o nome estava correto, então continuei procurando, e levou algum tempo para encontrar esse primeiro ramo. (Assim, Carpe Carpum e depois continue procurando.)

cssyphus
fonte