Поиск и восстановление удаленного файла в репозитории Git

скажем, я в репозитории Git. Я удаляю файл и фиксирую это изменение. Я продолжаю работать и делаю еще несколько обязательств. Затем я обнаружил, что мне нужно восстановить этот файл.

Я знаю, что могу проверить файл с помощью git checkout HEAD^ foo.bar, но я действительно не знаю, когда этот файл был удален.

  1. каков был бы самый быстрый способ найти фиксацию, которая удалила данное имя файла?
  2. каков был бы самый простой способ вернуть этот файл в мою работу копия?

Я надеюсь, что мне не придется вручную просматривать мои журналы, проверять весь проект для данного SHA, а затем вручную копировать этот файл в мою исходную проверку проекта.

19 ответов


найти последнюю фиксацию, которая повлияла на данный путь. Поскольку файл не находится в фиксации HEAD, эта фиксация должна была удалить его.

git rev-list -n 1 HEAD -- <file_path>

затем проверьте версию на фиксации раньше, используя курсор (^) символов:

git checkout <deleting_commit>^ -- <file_path>

или в одной команде, если $file это файл, о котором идет речь.

git checkout $(git rev-list -n 1 HEAD -- "$file")^ -- "$file"

если вы используете zsh и опция EXTENDED_GLOB включена, символ курсора не будет работать. Вы можете использовать ~1 вместо.

git checkout $(git rev-list -n 1 HEAD -- "$file")~1 -- "$file"

  1. использовать git log --diff-filter=D --summary чтобы получить все коммиты, которые удалили файлы и файлы удалены;
  2. использовать git checkout $commit~1 filename для восстановления удаленного файла.

здесь $commit значение фиксации вы нашли на шаге 1, например,e4cf499627


чтобы восстановить все удаленные файлы в папку, введите следующую команду.

git ls-files -d | xargs git checkout --

Я пришел к этому вопросу, чтобы восстановить файл, который я только что удалил, но я еще не совершил изменения. На всякий случай, если вы окажетесь в такой ситуации, все, что вам нужно сделать, это следующее:

git checkout HEAD -- path/to/file.ext


если вы сумасшедший, используйте git-bisect. Вот что нужно сделать:

git bisect start
git bisect bad
git bisect good <some commit where you know the file existed>

теперь пришло время запустить автоматический тест. Команда оболочки '[ -e foo.bar ]' вернет 0, если , и 1 в противном случае. Команда "выполнить" команды git-bisect будет использовать двоичный поиск, чтобы автоматически найти первую фиксацию, где тест терпит неудачу. Он начинается на полпути через заданный диапазон (от хорошего до плохого) и разрезает его пополам на основе результата указанного теста.

git bisect run '[ -e foo.bar ]'

теперь вы находитесь в фиксации, которая удалила его. Отсюда вы можете вернуться в будущее и использовать git-revert чтобы отменить изменение,

git bisect reset
git revert <the offending commit>

или вы можете вернуться на одну фиксацию и вручную проверить повреждение:

git checkout HEAD^
cp foo.bar /tmp
git bisect reset
cp /tmp/foo.bar .

мой новый любимый псевдоним, основанный на bonyiii ' s ответ (upvoted), и мой собственный ответ о "передайте аргумент команде псевдонима Git":

git config alias.restore '!f() { git checkout $(git rev-list -n 1 HEAD -- )~1 -- $(git diff --name-status $(git rev-list -n 1 HEAD -- )~1 | grep '^D' | cut -f 2); }; f'

Я потерял файл, удаленный по ошибке несколько коммитов назад?
Быстро:

git restore my_deleted_file

кризис миновал.


Роберт Дэйли предлагает в комментариях следующие псевдонимы:

restore-file = !git checkout $(git rev-list -n 1 HEAD -- "")^ -- ""

и jegan добавляет в комментариях:

для установки псевдонима из командной строки я использовал следующую команду:

git config --global alias.restore "\!git checkout $(git rev-list -n 1 HEAD -- \"$1\")^ -- \"$1\"" 

Если вы знаете имя файла, это простой способ с помощью основных команд:

перечислите все коммиты для этого файла.

git log -- path/to/file

последняя фиксация (самая верхняя) - это та, которая удалила файл. Таким образом, вам нужно восстановить Второй до последнего фиксации.

git checkout {second to last commit} -- path/to/file

чтобы восстановить удаленный и введенный файл:

git reset HEAD some/path
git checkout -- some/path

Он был протестирован на Git версии 1.7.5.4.


Если вы только внесли изменения и удалили файл, но не зафиксировали его, и теперь вы расстались с вашими изменениями

git checkout -- .

но удаленные файлы не возвращаются, вы просто выполняете следующую команду:

git checkout <file_path>

и presto, ваш файл вернулся.


у меня есть данное решение.

  1. получить идентификатор коммита, где файл был удален, используя один из способов ниже.

    • git log --grep=*word*
    • git log -Sword
    • git log | grep --context=5 *word*
    • git log --stat | grep --context=5 *word* # рекомендуется, если вы вряд ли вспомните что-нибудь
  2. вы должны получить что-то вроде:

commit bfe68bd117e1091c96d2976c99b3bcc8310bebe7 Автор: Александр Орлов Дата: Чт 12 Мая 23: 44: 27 2011 +0200

replaced deprecated GWT class
- gwtI18nKeySync.sh, an outdated (?, replaced by a Maven goal) I18n generation script

совершить 3ea4e3af253ac6fd1691ff6bb89c964f54802302 Автор: Александр Орлов Дата: Чт 12 Мая 22:10: 22 2011 +0200

3. Теперь, используя идентификатор фиксации bfe68bd117e1091c96d2976c99b3bcc8310bebe7 do:

git checkout bfe68bd117e1091c96d2976c99b3bcc8310bebe7^1 yourDeletedFile.java

поскольку идентификатор фиксации ссылается на фиксацию, где файл уже был удален, вам нужно ссылаться фиксация перед bfe68b что можно сделать путем добавления ^1. Это означает: дайте мне совершить перед bfe68b.


git checkout /path/to/deleted.file

во многих случаях может быть полезно использовать coreutils (grep, sed, etc.) совместно с Git. Я уже знаю эти инструменты довольно хорошо,но Git меньше. Если бы я хотел выполнить поиск удаленного файла, я бы сделал следующее:

git log --raw | grep -B 30 $'D\t.*deleted_file.c'

когда я нахожу ревизию/фиксацию:

git checkout <rev>^ -- path/to/refound/deleted_file.c

Как уже сказали до меня.

теперь файл будет восстановлен до состояния, в котором он был до удаления. Не забудьте повторно посвятить его работе дерево, если хочешь, чтобы оно было рядом.


git undelete path/to/file.ext

  1. положите это в свой .bash_profile (или другой соответствующий файл, который загружается при открытии командной оболочки):

    git config --global alias.undelete '!sh -c "git checkout $(git rev-list -n 1 HEAD -- )^ -- " -'
    
  2. затем использовать:

    git undelete path/to/file.ext
    

этот псевдоним сначала проверяет, чтобы найти последнюю фиксацию, где этот файл существовал, а затем делает проверку git этого пути файла из этого последнего фиксации, где этот файл существовал. источник


поэтому мне пришлось восстановить кучу удаленных файлов из определенной фиксации, и я справился с ней двумя командами:

git show <rev> --diff-filter=D --summary --name-only --no-commit-id | xargs git checkout <rev>^ -- 
git show <rev> --diff-filter=D --summary --name-only --no-commit-id | xargs git reset HEAD 

(обратите внимание на пробел в конце каждой команды.)

файлы были добавлены .файл gitignore, а затем очищен с помощью git rm, мне нужно было восстановить файлы, но затем распаковать их. У меня были сотни файлов для восстановления, ввод вручную для каждого файла, как и в других примерах, будет слишком медленным.


user@bsd:~/work/git$ rm slides.tex
user@bsd:~/work/git$ git pull 
Already up-to-date.
user@bsd:~/work/git$ ls slides.tex
ls: slides.tex: No such file or directory

восстановить удаленный файл:

user@bsd:~/work/git$ git checkout
D       .slides.tex.swp
D       slides.tex
user@bsd:~/work/git$ git checkout slides.tex 
user@bsd:~/work/git$ ls slides.tex
slides.tex

у меня был тот же вопрос. Сам того не зная, я создал болтается commit.

список свесив совершает

git fsck --lost-found

проверить каждый болтающийся фиксации

git reset --hard <commit id>

мои файлы снова появились, когда я перешел к болтающейся фиксации.

git status по причине:

“HEAD detached from <commit id where it detached>”


в нашем случае мы случайно удалили файлы в фиксации, а некоторые фиксации позже мы поняли нашу ошибку и хотели вернуть все файлы, которые были удалены, но не те, которые были изменены.

основываясь на превосходном ответе Чарльза Бейли, вот мой один лайнер:

git co $(git rev-list -n 1 HEAD -- <file_path>)~1 -- $(git diff --name-status $(git rev-list -n 1 HEAD -- <file_path>)~1 head | grep '^D' | cut -f 2)

Если вы знаете фиксацию, которая удалила файл(ы), выполните эту команду, где <SHA1_deletion> - это фиксация, которая удалила файл:

git diff --diff-filter=D --name-only <SHA1_deletion>~1 <SHA1_deletion> | xargs git checkout <SHA1_deletion>~1 --

в части перед каналом перечислены все файлы, которые были удалены в фиксации; все они извлекаются из предыдущей фиксации для их восстановления.


$ git log --diff-filter=D --summary  | grep "delete" | sort