Como encontrar um arquivo excluído no histórico de confirmação do projeto?

1275

Era uma vez, um arquivo no meu projeto que eu gostaria de obter agora.

O problema é: não tenho idéia de quando o excluí e em que caminho estava.

Como localizo as confirmações deste arquivo quando ele existia?

Pedro Rolo
fonte
Pergunta semelhante aqui: stackoverflow.com/questions/7093602/…
eckes
3
Possível duplicado de Find quando um arquivo foi excluído em Git
Dan Dascalescu
13
As respostas aqui são mais úteis para mim do que as respostas nas duplicatas .
Felipe Alvarez
5
concordou ... independentemente das duplicatas ... elas não apareceram na pesquisa do Google .... esta apareceu ... espero que paremos de perder tempo perseguindo duplicatas ... apenas o tempo e o algoritmo do Google diga qual é a melhor pergunta.
Tim Boland

Respostas:

1601

Se você não souber o caminho exato, poderá usar

git log --all --full-history -- "**/thefile.*"

Se você souber o caminho que o arquivo estava, você pode fazer o seguinte:

git log --all --full-history -- <path-to-file>

Isso deve mostrar uma lista de confirmações em todas as ramificações que tocaram nesse arquivo. Em seguida, você pode encontrar a versão do arquivo que deseja e exibi-la com ...

git show <SHA> -- <path-to-file>

Ou restaure-o na sua cópia de trabalho com:

git checkout <SHA>^ -- <path-to-file>

Observe o símbolo de sinal de intercalação ( ^), que recebe a finalização da compra antes da identificação, porque no momento da <SHA>confirmação do arquivo é excluído, precisamos observar a confirmação anterior para obter o conteúdo do arquivo excluído

Âmbar
fonte
2
Tente usar um caminho relativo em vez de absoluto (se você ainda não estiver).
26611 Amber
63
E se você não souber o caminho exato? Tudo o que você sabe é o nome do arquivo?
priestc
17
O @PedroMorteRolo git log -- <path>não terá saída quando você estiver em uma ramificação na qual o arquivo nunca existiu. Você deve sempre usar git log --all -- <path>, para garantir que não perca as alterações que ocorreram em outros ramos. O comando git log -- <path>pode ser muito perigoso se você tiver mais de um ramo e tender a esquecer caminhos e ramos (como eu) e também será perigoso se você trabalhar com outros desenvolvedores.
hobs
4
@ Amber, considere adicionar --all(obrigado Philip ) à sua git logresposta, para que as pessoas não percam alterações e arquivos em outros ramos. Isso pouparia muita gente esquecida como eu.
HOBs
3
Como indicado na resposta abaixo, a restauração do arquivo deve ser git checkout <SHA>^ -- <path-to-file>(observe o símbolo ^), porque no momento do <SHA> commit o arquivo é excluído, precisamos observar o commit anterior para obter o conteúdo do arquivo excluído
kipelovets
393

Obtenha uma lista dos arquivos excluídos e copie o caminho completo do arquivo excluído

git log --diff-filter=D --summary | grep delete

Execute o próximo comando para encontrar o ID de confirmação dessa confirmação e copie o ID de confirmação

git log --all -- FILEPATH

Mostrar diff do arquivo excluído

git show COMMIT_ID -- FILE_PATH

Lembre-se, você pode gravar a saída em um arquivo usando >como

git show COMMIT_ID -- FILE_PATH > deleted.diff
Fatih Acet
fonte
1
Embora eu encontrei o caminho com a ajuda da primeira etapa, o segundo passo lança este erro: unknown revision or path not in the working tree.
jvannistelrooy
6
Para ver o hashes comprometer, juntamente com as exclusões, você pode fazergit log --diff-filter=D --summary | grep -E 'delete|^commit\s+\S+'
Chris Middleton
1
O passo 2 não retorna nada. Alguma idéia de por que isso pode acontecer? Meu nome de arquivo está correto.
Denis Kniazhev
2
Para encontrar a combinação das três em uma função, adicione-a no seu .bashrc ou .zshrc: git-grep-latest(){ result_path=$(git log --diff-filter=D --summary | grep $1 | head -1 | awk '{print $4;}'); latest_commit=$(git log --all -- $result_path | head -1 | awk '{print $2;}'); git show $latest_commit -- $result_path; }e agora você pode fazer o seguinte:git-grep-latest some_text
randomor
1
@ TylerJones, você pode alimentar qualquer coisa com o Linux usando pipes - google linux pipes.. você vai gostar.
John Hunt
37

Não foi possível editar a resposta aceita, portanto, adicione-a como resposta aqui,

para restaurar o arquivo no git, use o seguinte (observe o sinal '^' logo após o SHA)

git checkout <SHA>^ -- /path/to/file
Akshay Agarwal
fonte
Eu não entendo por que você iria querer o ^. O arquivo está no commit com esse SHA ... por que você deseja retornar outro commit a partir daí?
Tony K.
19
Está no commit com esse sha como "deletado", o que significa que ele ainda não existirá. Você precisa ir ao commit antes disso para recuperá-lo.
precisa saber é o seguinte
6
@tandrewnichols, o que significa que você está usando o SHA de confirmação errado - você deseja o commit para a versão do arquivo que deseja ... o que provavelmente não é a versão em que o arquivo é excluído.
Âmbar
6
@ Amber e o commit que você deseja provavelmente é o mais recente antes de ser excluído, portanto, esta resposta.
Sam Titular
1
@AlexR: <SHA>~1deve funcionar da mesma forma sem a necessidade de envolvê-lo com aspas.
CodeManX 15/06
37

Suponha que você queira recuperar um arquivo chamado MyFile, mas não tenha certeza de seu caminho (ou extensão):

Prelim .: Evite confusão, pisando na raiz do git

Um projeto não trivial pode ter vários diretórios com nomes semelhantes ou idênticos.

> cd <project-root>
  1. Encontre o caminho completo

    git log --diff-filter = D - resumo | grep delete | grep MyFile

    delete mode 100644 full/path/to/MyFile.js

full/path/to/MyFile.js é o caminho e o arquivo que você está procurando.

  1. Determine todas as confirmações que afetaram esse arquivo

    git log --oneline --follow - completo / caminho / para / MyFile.js

    bd8374c Some helpful commit message

    ba8d20e Another prior commit message affecting that file

    cfea812 The first message for a commit in which that file appeared.

  2. Finalize o arquivo

Se você escolher o primeiro commit listado (o último cronologicamente, aqui bd8374c), o arquivo não será encontrado, pois foi excluído nesse commit.

> git checkout bd8374c -- full/path/to/MyFile.js

`error: pathspec 'full/path/to/MyFile.js' did not match any file(s) known to git.`

Basta selecionar o commit anterior (acrescentar um sinal de intercalação):

> git checkout bd8374c^ -- full/path/to/MyFile.js
Calaf
fonte
3
Este é muito mais clara do que a resposta aceita
Pouyan Khodabakhsh
para console do Windows (cmd), use find em vez de grep na etapa 2: git log --diff-filter=D --summary | find "delete" | find "MyFile"e na step3, observe as aspas ao redor do hash:git checkout "bd8374c^" -- full/path/to/MyFile.js
user5542121
30

@ Amber deu a resposta correta! Apenas mais uma adição, se você não souber o caminho exato do arquivo, poderá usar curingas! Isso funcionou para mim.

git log --all -- **/thefile.*
Petur Subev
fonte
4
@PedroMorteRolo Hmm. Não sei como me sinto ao copiar uma resposta existente para a mais votada: / Essa resposta também foi útil por si só; um voto positivo pode ter sido suficiente?
Clément
1
Isso não encontra o arquivo se ele estiver na raiz do projeto (testado no Cygwin).
Wortwart #
19

Abaixo está um comando simples, no qual um usuário dev ou git pode passar um nome de arquivo excluído do diretório raiz do repositório e obter o histórico:

git log --diff-filter=D --summary | grep filename | awk '{print $4; exit}' | xargs git log --all -- 

Se alguém puder melhorar o comando, faça.

Jason
fonte
1
Incrível, obrigado! Looks como meu arquivo nunca existiu em tudo, mas isso é uma questão mais peludo separado e muito mais ...
certifique-se de executar este a partir do diretório raiz do repositório se o arquivo parece ser 'desaparecidos'
samaspin
Obrigado @samaspin atualizou a resposta.
18719 Jason
18

Tente usar um dos visualizadores, como gitkpara que você possa navegar pelo histórico para encontrar o arquivo meio lembrado. (use gitk --allse necessário para todos os ramos)

Philip Oakley
fonte
4
Essa --allopção é crítica para sua resposta e a resposta aceita.
hobs
3
Navegar pelo histórico levará uma quantidade extraordinária de tempo para a maioria dos projetos.
Mikemaccana 23/05
5

Resumo:

  1. Passo 1

Você pesquisa o caminho completo do arquivo no histórico de arquivos excluídos git log --diff-filter=D --summary | grep filename

  1. Passo 2

Você restaura seu arquivo da confirmação antes de ser excluído

restore () {
  filepath="$@"
  last_commit=$(git log --all --full-history -- $filepath | grep commit | head -1 | awk '{print $2; exit}')
  echo "Restoring file from commit before $last_commit"
  git checkout $last_commit^ -- $filepath
}

restore my/file_path
srghma
fonte
0

Aqui está a minha solução:

git log --all --full-history --oneline -- <RELATIVE_FILE_PATH>
git checkout <COMMIT_SHA>^ -- <RELATIVE_FILE_PATH>
Antonio Petricca
fonte