Digamos I'm em um repositório Git. Eu apago um arquivo e submeto essa alteração. Eu continuo trabalhando e faço mais alguns commits. Então, acho que preciso restaurar esse arquivo.
Eu sei que posso fazer checkout de um arquivo usando git checkout HEAD^ foo.bar
, mas eu não'não sei realmente quando esse arquivo foi apagado.
I'espero não ter que navegar manualmente pelos meus logs, fazer checkout de todo o projecto para um determinado SHA e depois copiar manualmente esse ficheiro para o meu checkout original do projecto.
Encontre o último compromisso que afetou o caminho dado. Como o ficheiro não está no HEAD commit, este commit deve tê-lo apagado.
git rev-list -n 1 HEAD -- <file_path>
Depois verifique a versão no commit antes, utilizando o símbolo do caret (^
):
git checkout <deleting_commit>^ -- <file_path>
Ou em um comando, se $file
é o arquivo em questão.
git checkout $(git rev-list -n 1 HEAD -- "$file")^ -- "$file"
Se você estiver usando zsh e tiver a opção EXTENDED_GLOB ativada, o símbolo do carpete não vai funcionar. Você pode utilizar ~1
em vez disso.
git checkout $(git rev-list -n 1 HEAD -- "$file")~1 -- "$file"
git log --diff-filter=D --summary
para obter todos os commits que apagaram ficheiros e os ficheiros apagados;git checkout $commit~1 path/to/file.ext
para restaurar o ficheiro apagado.Onde $commit
é o valor do commit que você encontrou no passo 1, por exemplo e4cf499627
.
Se você estiver louco, use git-bisect. Aqui está o que fazer:
git bisect start
git bisect bad
git bisect good <some commit where you know the file existed>
Agora é hora de fazer o teste automático. O comando shell '[ -e foo.bar ]'
retornará 0 se foo.bar
existir, e 1 caso contrário. O comando "run" do git-bisect
utilizará a busca binária para encontrar automaticamente o primeiro commit onde o teste falhar. Ele inicia pela metade do intervalo dado (de bom para ruim) e o corta pela metade com base no resultado do teste especificado.
git bisect run '[ -e foo.bar ]'
Agora estás no compromisso que o apagou. Daqui, você pode pular de volta para o futuro e usar git-revert
para desfazer a mudança,
git bisect reset
git revert <the offending commit>
ou você poderia voltar atrás e inspecionar manualmente os danos:
git checkout HEAD^
cp foo.bar /tmp
git bisect reset
cp /tmp/foo.bar .