Найти и восстановить удаленный файл в репозитории Git

2634

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

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

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

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

  • 37
    обратите внимание, что предыдущий комментарий отвечает на вопрос в заголовке, а не в теле - это включает в себя выяснение, когда файл был удален.
  • 8
    Чтобы найти фиксацию, файл был удален в: git log --diff-filter=D -- path/to/file
Показать ещё 5 комментариев
Теги:
file-io
git-checkout

22 ответа

2990
Лучший ответ

Найдите последний коммит, который затронул данный путь. Поскольку файл не находится в коммите 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"
  • 89
    Сложнее всего проверить коммит ДО, используя суффикс ^. Благодарю.
  • 4
    По некоторым причинам, это не будет работать в Zsh. ± git checkout $(git rev-list -n 1 HEAD "spec/Sporkfile_example.rb")^ -- "spec/Sporkfile_example.rb" zsh: no matches found: b71c152d8f38dcd23ad7600a93f261a7252c59e9^ Я перешел на bash, но он работал нормально.
Показать ещё 18 комментариев
798
  1. Используйте git log --diff-filter=D --summary чтобы получить все коммиты, которые удалили файлы и файлы удалены;
  2. Используйте git checkout $commit~1 path/to/file.ext для восстановления удаленного файла.

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

  • 5
    Любопытно, что означает ~ 1?
  • 5
    @tommy - спецификация тильды даст вам n-го внука именованного коммита. Смотрите book.git-scm.com/4_git_treeishes.html для получения более подробной информации.
Показать ещё 8 комментариев
320

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

git ls-files -d | xargs git checkout --
  • 1
    Куда попадают файлы? Я не вижу изменений.
  • 19
    Это, наверное, самый простой способ. Его извращенное, как трудный git сделал даже самую простую задачу.
Показать ещё 3 комментария
111

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

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

91

Если вы безумны, используйте 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 .
  • 2
    Не могли бы вы рассказать о git bisect run '[ -e foo.bar ]' ?
  • 0
    Вы также можете использовать хорошее и плохое вручную, если это не может быть проверено автоматически. Смотрите справочную страницу.
Показать ещё 1 комментарий
69

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

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"

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

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

git config --global alias.restore "\!git checkout \$(git rev-list -n 1 HEAD -- \"\$1\")^ -- \"\$1\"" 
  • 7
    Это восстанавливает весь коммит, а не только запрошенный файл.
  • 5
    Вот мой псевдоним, чудесно работает: restore-file = !git checkout $(git rev-list -n 1 HEAD -- "$1")^ -- "$1"
Показать ещё 9 комментариев
44

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

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

git log -- path/to/file

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

git checkout {second to last commit} -- path/to/file
  • 0
    Просто использовал это решение, и не было никакого коммита для удаления. Мне удалось восстановить файл с использованием самого последнего идентификатора коммита.
  • 0
    +10 за second to last commit комментирования!
Показать ещё 3 комментария
27

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

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

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

  • 1
    Это не сработало для меня. После извлечения я получил error: pathspec 'foo' did not match any file(s) known to git. Я убедился, что имя файла было правильным. Git версия 2.7.0
  • 0
    -1; это не верно. Эти команды отменят удаление, которое еще не было зафиксировано (первая снимает этап с удаления, если он был подготовлен, а вторая отменяет внесенные без изменений в файл), но вы утверждаете, что они восстановят зафиксированный удаление файла, которое просто не соответствует действительности и завершится с ошибкой, подобной той, что была в комментарии @ wisbucky выше.
Показать ещё 1 комментарий
23

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

git checkout -- .

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

git checkout <file_path>

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

21

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

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

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

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 Автор: Alexander Орлов Дата: Чт май 12 22:10:22 2011 +0200

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

git checkout bfe68bd117e1091c96d2976c99b3bcc8310bebe7^1 yourDeletedFile.java

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

  • 0
    Это тот же подход, что и принятый ответ, но есть еще несколько способов найти коммит удаления. Мне все еще нравится подход, принятый в принятом ответе, но это хорошие альтернативы. Спасибо!
  • 0
    Я предполагаю, что сначала проверка удаленного файла, а затем (без изменения) его фиксация не создает копию файла. Правильно? (Мне нужно сделать это с изображениями, а копии сделают хранилище больше)
14
git checkout /path/to/deleted.file
  • 7
    Не будет работать с момента удаления.
  • 0
    Этот для моей ситуации (удален непреднамеренно) был самым простым решением.
10

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

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

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

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

Точно так же, как другие заявили передо мной.

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

9

git undelete path/to/file.ext

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

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

    git undelete path/to/file.ext
    

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

6

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

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, мне нужно было восстановить файлы, но затем отключить их. У меня было сотни файлов для восстановления, запись вручную для каждого файла, так как в других примерах было слишком медленно.

4

На самом деле, этот вопрос касается непосредственно Git, но кто-то вроде меня работает с такими инструментами с графическим интерфейсом, как WebStorm VCS, кроме знания команд git cli.

Я щелкаю правой кнопкой мыши путь, содержащий удаленный файл, затем перехожу в Git и затем нажимаю " Show History.

Изображение 7481

Инструменты VCS показывают все изменения, и я вижу все изменения и изменения каждого из них.

Изображение 7482

Затем я выбираю коммиты, чтобы мой друг удалил файл PostAd.js. теперь смотрите ниже:

Изображение 7483

И теперь я вижу свое желание удалить удаленный файл. Я просто дважды щелкаю по имени файла, и оно восстанавливается.

Изображение 7484

Я знаю, что мой ответ - не команды Git но он быстрый, надежный и простой для начинающих и профессиональных разработчиков. Инструменты Webstorm VCS великолепны и идеально подходят для работы с Git и не нуждаются ни в каком другом плагине или инструментах.

  • 0
    Это круто! Спасибо. Определенно более простое решение для тех, кто использует любую из сред JetBrains.
4

У меня такой же вопрос. Не зная этого, я создал оборванный коммит.

Список свисающих коммитов

git fsck --lost-found

Осмотрите каждый висячий коммит

git reset --hard <commit id>

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

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

"HEAD detached from <commit id where it detached>"

4
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
  • 2
    Вопрос был о восстановлении файла после того, как он был удален и изменение было зафиксировано. Этот ответ о восстановлении файла, который был удален только в рабочем каталоге.
  • 0
    Это правда, и это было то, что я искал.
3

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

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

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

3

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

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

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)
1

Простой и precise-

Прежде всего, получите последний стабильный коммит, в котором у вас есть этот файл:

git log 

Допустим, вы нашли $ commitid 1234567..., затем

git checkout <$commitid> $fileName

Это восстановит версию файла, которая была в этом коммите.

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

Если вы столкнулись с этой проблемой чаще, и вы готовы использовать инструмент Git GUI, посмотрите DeepGit и используйте Файл | Поиск.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню