Найти и восстановить удаленный файл в репозитории Git - PullRequest
2618 голосов
/ 05 июня 2009

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

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

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

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

Ответы [ 22 ]

2967 голосов
/ 11 июля 2009

Найти последний коммит, который затронул данный путь. Поскольку файл не находится в коммите 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"
809 голосов
/ 05 июня 2009
  1. Используйте git log --diff-filter=D --summary, чтобы получить все коммиты, которые удалили файлы и файлы удалены;
  2. Используйте git checkout $commit~1 path/to/file.ext для восстановления удаленного файла.

Где $commit - это значение коммита, которое вы нашли на шаге 1, например e4cf499627

307 голосов
/ 02 декабря 2010

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

git ls-files -d | xargs git checkout --
117 голосов
/ 10 апреля 2014

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

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

89 голосов
/ 05 июня 2009

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

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

Теперь пришло время запустить автоматический тест. Команда оболочки '[ -e foo.bar ]' вернет 0, если foo.bar существует, и 1 в противном случае. Команда "run" 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 .
71 голосов
/ 17 февраля 2013

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

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

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

git restore my_deleted_file

Кризис предотвращен.


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

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

И Джеган добавляет в комментарии :

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

git config --global alias.restore "\!git checkout \$(git rev-list -n 1 HEAD -- \"\$1\")^ -- \"\$1\"" 
45 голосов
/ 27 февраля 2016

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

Список всех коммитов для этого файла.

git log -- path/to/file

Последний коммит (самый верхний) - это тот, который удалил файл. Поэтому вам нужно восстановить второй до последнего коммита.

git checkout {second to last commit} -- path/to/file
29 голосов
/ 04 июля 2012

Чтобы восстановить удаленный и зафиксированный файл:

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

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

24 голосов
/ 02 сентября 2016

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

git checkout -- .

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

git checkout <file_path>

И до того, ваш файл вернулся.

23 голосов
/ 01 марта 2012

У меня есть это решение .

  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

commit 3ea4e3af253ac6fd1691ff6bb89c964f54802302 Автор: Александр Орлова Дата: чт 12 мая 22:10:22 2011 + 0200

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

git checkout bfe68bd117e1091c96d2976c99b3bcc8310bebe7^1 yourDeletedFile.java

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

...