Reversão para um commit antigo do Git em um repositório público

802

Como posso reverter para um commit específico no git ?

A melhor resposta que alguém poderia me dar era usar git revertX vezes até atingir o commit desejado.

Então, digamos que eu queira reverter para um commit com 20 commit antigo, eu teria que executá-lo 20 vezes.

Existe uma maneira mais fácil de fazer isso?

Não consigo usar a redefinição porque este repositório é público.

David
fonte
1
git revert <commit> não funciona?
Miku
8
Como afirmado na minha pergunta, isso realmente não me ajuda se eu quiser voltar a algo que há 20 anos.
David
7
Esta questão foi bastante bem respondida aqui stackoverflow.com/questions/4114095/…
user7610
4
Não está claro o que você quer dizer com "retroceder". Isso significa que você deseja alterar temporariamente sua cópia de trabalho para uma revisão específica? Ou você deseja reverter permanentemente o histórico do seu repositório para uma determinada revisão?
1
Você deve aceitar uma resposta e, possivelmente, votar nas outras respostas que desejar.
Nabil Kadimi

Respostas:

1194

Tente o seguinte:

git checkout [revision] .

onde [revision]está o hash de confirmação (por exemplo 12345678901234567890123456789012345678ab:).

Não se esqueça .do final, muito importante. Isso aplicará alterações em toda a árvore. Você deve executar este comando na raiz do projeto git. Se você estiver em qualquer subdiretório, esse comando alterará apenas os arquivos no diretório atual. Então comprometa e você deve ser bom.

Você pode desfazer isso

git reset --hard 

que excluirá todas as modificações do diretório de trabalho e da área de preparação.

Alex Reisner
fonte
7
@AlexReisner Esse período nos pontos finais no diretório em que você está atualmente, que não é necessariamente o projeto git inteiro, correto? Se você quisesse aplicar as mudanças em todo o projeto, você usaria ': /' like em 'git add: /', se você não estava atualmente na raiz do projeto git?
precisa saber é o seguinte
10
nota: se você adicionou novos arquivos ao seu projeto desde então, isso não os excluirá. Portanto, quando você cria (dependendo da sua plataforma), você ainda pode ter erros. Exclua os novos arquivos e pronto.
TheWestIsThe ...
6
@MSpreij Você deve executar este comando na raiz do projeto git. Se você estiver em qualquer subdiretório, esse comando alterará apenas os arquivos no diretório atual.
volatilevar
3
É ótimo quando você pode clonar um projeto em outro diretório e usar o git checkout [revisão]. para voltar a uma revisão específica e compará-la com o mesmo projeto em outro diretório. Economiza muito tempo.
9136 Donato
4
Droga, eu esqueci o "." que dano eu faço no meu repositório?
Owl
196

Para reverter para uma confirmação específica:

git reset --hard commit_sha

Para retroceder 10 confirma novamente:

git reset --hard HEAD~10

Você pode usar "git revert" como na postagem a seguir, se não quiser reescrever o histórico

Como reverter o repositório Git para um commit anterior?

Naga Kiran
fonte
4
única diferença entre essa abordagem e "git checkout [revisão]". é que o último preserva revisões.
deeshank
53
Esta resposta é errado, como OP afirma especificamente "Eu não posso usar reinicialização causa este repo é público"
Yarin
4
Se o repo for público, acho que não há como reverter o commit no repositório público sem usar o force push (git push -f), pois isso afetará as pessoas que realizaram as alterações antes do rollback. Portanto, a redefinição também pode ser usada na sandbox local de um repositório público.
Naga Kiran
4
É ótimo que isso evite uma CABEÇA desapegada! É mesmo o que eu procurava.
cyber-monge
1
No meu caso, isso funcionou, então use 'git pull' para avançar rapidamente depois de testar as regressões, etc.
Peter Quiring
86

Bem, acho que a pergunta é: o que você quer dizer com 'reverter'? Se você não pode, resetporque é público e deseja manter intacto o histórico de consolidação, você quer dizer que apenas deseja que sua cópia de trabalho reflita uma consolidação específica? Use git checkoute o hash de confirmação.

Editar: Como foi indicado nos comentários, o uso git checkoutsem especificar uma ramificação o deixará no estado "sem ramificação". Use git checkout <commit> -b <branchname>para fazer checkout em uma ramificação ou git checkout <commit> .fazer check-out na ramificação atual.

Ben
fonte
Isso não o coloca no estado estranho "Atualmente não está em nenhum ramo"? Como você confirma as alterações para concluir a reversão?
precisa saber é o seguinte
Bem, estou apenas sugerindo o uso de git checkout- ele está livre para verificar em qualquer ramo (atual ou novo) que desejar. Vou atualizar minha resposta para que não seja ambígua.
Ben
2
Eu tentei isso, mas não acho que essa seja a maneira correta de fazê-lo, pois deixa arquivos estagnados. Isso não exclui arquivos que não estavam na última confirmação.
David
3
Se você estiver em um diretório ativo e permanecer no mestre, precisará git resetexcluir esses arquivos, o que você diz que não deseja fazer. Tente fazer isso em um ramo separado:, git checkout <commit> -b <branchname>você não terá arquivos estagnados nesse ramo .
Ben
2
O problema do uso checkouté que ele não excluirá os arquivos adicionados em uma confirmação anterior.
42

O pôster original declara:

A melhor resposta que alguém poderia me dar era usar git revertX vezes até atingir o commit desejado.

Então, digamos que eu queira reverter para um commit com 20 commit antigo, eu teria que executá-lo 20 vezes.

Existe uma maneira mais fácil de fazer isso?

Não consigo usar a redefinição porque este repositório é público.

Não é necessário usar git revertX vezes. git revertpode aceitar um intervalo de confirmação como argumento, portanto, você só precisa usá-lo uma vez para reverter um intervalo de confirmações. Por exemplo, se você deseja reverter as últimas 20 confirmações:

git revert --no-edit HEAD~20..

O comprometer gama HEAD~20..é curto para HEAD~20..HEAD, e significa "começar a partir da 20 ª pai da cabeça submeter, e reverter todos os commits depois até a cabeça".

Isso reverterá os últimos 20 confirmados, assumindo que nenhum deles seja confirmado por mesclagem. Se houver confirmações de mesclagem, não será possível revertê-las todas em um comando, será necessário revertê-las individualmente com

git revert -m 1 <merge-commit>

Observe também que eu testei usando um intervalo com o git revertuso da versão 1.9.0 do git. Se você estiver usando uma versão mais antiga do git, usar um intervalo com git revertpode ou não funcionar.

Nesse caso, git reverté preferível a git checkout.

Observe que, diferentemente da resposta que diz para usargit checkout , git revert na verdade, os arquivos adicionados em qualquer consolidação que você está revertendo serão removidos , o que torna a maneira correta de reverter uma série de revisões.

Documentação

railgun
fonte
Nota : isso cria uma nova confirmação com as alterações revertidas. Perfeito para a pergunta do OP. Mas certifique-se de que é isso que você deseja. (Os exemplos no documento do git-revert vinculado a acima são excelentes.) Se você deseja investigar confirmações anteriores (ou seja, antes de escolher o que reverter), use a opção de checkout mencionada em outras respostas, tendo em mente os comentários de outras pessoas. feito sobre arquivos excluídos.
precisa saber é o seguinte
@SherylHohman A reversão para um commit anterior não cria um novo commit. Não consigo imaginar o que você quer dizer aqui.
27

Etapa 1: buscar a lista de confirmações:

git log

Você receberá uma lista como neste exemplo:

[Comp:Folder User$ git log
commit 54b11d42e12dc6e9f070a8b5095a4492216d5320
Author: author <[email protected]>
Date:   Fri Jul 8 23:42:22 2016 +0300

This is last commit message

commit fd6cb176297acca4dbc69d15d6b7f78a2463482f
Author: author <[email protected]>
Date:   Fri Jun 24 20:20:24 2016 +0300

This is previous commit message

commit ab0de062136da650ffc27cfb57febac8efb84b8d
Author: author <[email protected]>
Date:   Thu Jun 23 00:41:55 2016 +0300

This is previous previous commit message
...

Etapa 2: copie o hash de confirmação necessário e cole-o para checkout:

git checkout fd6cb176297acca4dbc69d15d6b7f78a2463482f

Isso é tudo.

Igor
fonte
11
git read-tree -um @ $commit_to_revert_to

vai fazer isso. É "git checkout", mas sem atualizar o HEAD.

Você pode obter o mesmo efeito com

git checkout $commit_to_revert_to
git reset --soft @{1}

se você preferir encadear comandos de conveniência juntos.

Isso deixa você com sua árvore de trabalho e índice no estado desejado, basta git commitfinalizar.

jthill
fonte
Esta é a única abordagem direta que funcionou como um encanto! Fiz o check-out do início, executei este comando e ele removeu com êxito os arquivos adicionados que introduzimos e revertemos todas as alterações. Excelente.
Kamranicus 16/0318
6

Deseja o modo desconectado HEAD?

Se você deseja reverter o tempo X para um determinado commit com um DETACHED HEAD (o que significa que você não pode estragar nada), então, por todos os meios, use o seguinte:

(substitua X por quantas confirmações você deseja voltar)

git checkout HEAD~X

IE para voltar um commit:

git checkout HEAD~1
Karl Morrison
fonte
1
Eu removeria a parte com ... difícil de acreditar ... Parece pessoal, e também alguém mencionou isso em um comentário acima, e no @ken também em sua resposta.
meJustAndrew
@meJustAndrew É, tantas respostas no SO que apenas confundem as pessoas, é bastante irritante.
Karl Morrison
Que resposta simples e direta.
Ammad
2

Digamos que você trabalhe em um projeto e depois de um dia ou mais. Você percebe que um recurso ainda está apresentando erros. Mas você não sabe que alteração você fez que causou o erro. Então você tem que pescar commits de trabalho anteriores. Para reverter para um commit específico:

git checkout 8a0fe5191b7dfc6a81833bfb61220d7204e6b0a9 .

Ok, para que o commit funcione para você. Não há mais erro. Você identificou o problema. Agora você pode voltar ao último commit:

git checkout 792d9294f652d753514dc2033a04d742decb82a5 .

E faça o checkout de um arquivo específico antes que ele tenha causado o erro (no meu caso, uso o exemplo Gemfile.lock):

git checkout 8a0fe5191b7dfc6a81833bfb61220d7204e6b0a9 -- /projects/myproject/Gemfile.lock

E essa é uma maneira de lidar com os erros que você criou nas confirmações sem perceber os erros até mais tarde.

Donato
fonte
2

Você pode encontrar o ID de confirmação relacionado a cada confirmação na seção de confirmações do GitHub / BitBucket / Gitlab. É muito simples, suponha que seu ID de confirmação seja 5889575; se você quiser voltar a esta parte do seu código, basta digitar

git checkout 5889575 .

Isso levará você a esse ponto do tempo no seu código.

Naved Ahmad
fonte
1

Eu não tenho certeza o que mudou, mas eu sou incapaz de fazer o checkout de um commit específico sem a opção --detach. O comando completo que funcionou para mim foi: git checkout --detach [commit hash]

Para voltar do estado desanexado, tive que fazer checkout da minha filial local: git checkout master

ken
fonte
Verificando masterresolve o problema de permanecer individual, ao fazer git reset --hardou git checkout -- .que funcionou, mas permaneceu isolada
DarkCygnus
0

Aqui está um exemplo para fazer isso

    cd /yourprojects/project-acme 


    git checkout efc11170c78 .
mcvkr
fonte