Как найти удаленный файл в истории коммитов проекта?


1275

Когда-то в моем проекте был файл, который я бы хотел получить.

Проблема: я понятия не имею, когда я удалил это и по какому пути это было.

Как я могу найти коммиты этого файла, когда он существовал?


Подобный вопрос здесь: stackoverflow.com/questions/7093602/…
— eckes


13
Ответы здесь более полезны для меня, чем ответы в дубликатах .
— Фелипе Альварес

5
согласился ... независимо от дубликатов ... они не появлялись в поиске Google ... этот сделал ... надеюсь, мы перестанем тратить время на погоню за дубликатами ... только время и алгоритм Google будет скажи какой вопрос самый лучший.
— Тим Боланд,

Ответы:


1601

Если вы не знаете точный путь, который вы можете использовать

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

Если вы знаете путь к файлу, вы можете сделать это:

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

Это должно показать список коммитов во всех ветвях, которые касались этого файла. Затем вы можете найти версию файла, который вы хотите, и отобразить его с ...

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

Или восстановите его в рабочую копию с помощью:

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

Обратите внимание на символ вставки ( ^), который получает извлечение до идентифицированного, потому что в момент <SHA>фиксации файл удаляется, нам нужно посмотреть предыдущий коммит, чтобы получить содержимое удаленного файла.


2
Попробуйте использовать относительный путь вместо абсолютного (если вы еще этого не сделали).
— Янтарная

63
Что делать, если вы не знаете точный путь? Все, что вы знаете, это имя файла?
— priestc

17
@PedroMorteRolo не git log -- <path>будет выводить, когда вы находитесь на ветке, в которой файл никогда не существовал. Вы должны всегда использовать git log --all -- <path>, чтобы убедиться, что вы не пропустите изменения, которые произошли в других ветках. Команда git log -- <path>может быть очень опасной, если у вас более одной ветви и вы склонны забывать пути и ветви (как я), а также опасно, если вы работаете с другими разработчиками.
— варенье

4
@Amber, подумайте над добавлением --all(спасибо Филиппу ) к вашему git logответу, чтобы люди не пропустили изменения и файлы в других ветках. Это спасло бы забывчивых людей, таких как я, от горя.
— вар

3
Как указано в ответе ниже, восстановление файла должно быть git checkout <SHA>^ -- <path-to-file>(обратите внимание на символ ^), потому что в момент фиксации <SHA> файл удаляется, нам нужно посмотреть предыдущий коммит, чтобы получить содержимое удаленного файла
— kipelovets

393

Получить список удаленных файлов и скопировать полный путь к удаленному файлу

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

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

git log --all -- FILEPATH

Показать разницу удаленного файла

git show COMMIT_ID -- FILE_PATH

Помните, что вы можете записать вывод в файл, используя >как

git show COMMIT_ID -- FILE_PATH > deleted.diff

1
Хотя я нашел путь с помощью первого шага, второй шаг выдает эту ошибку: unknown revision or path not in the working tree.
— jvannistelrooy

6
Чтобы увидеть хеши коммитов вместе с удалениями, вы можете сделатьgit log --diff-filter=D --summary | grep -E 'delete|^commit\s+\S+'
— Крис Миддлтон

1
Шаг 2 ничего не возвращает. Есть идеи, почему это может произойти? Мое имя файла правильное.
— Денис Княжев

2
Чтобы найти объединение трех в одну функцию, добавьте это в ваш .bashrc или .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; }и теперь вы можете просто сделать:git-grep-latest some_text
— randomor

1
@TylerJones, вы можете кормить что угодно с помощью Linux с помощью каналов - Google linux pipes... вам понравится.
— Джон Хант

37

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

чтобы восстановить файл в git, используйте следующее (обратите внимание на знак '^' сразу после SHA)

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

Я не понимаю, почему вы хотите ^. Файл находится в коммите с этим SHA ... почему вы хотите оттуда откатить еще один коммит?
— Тони К.

19
Он находится в коммите с этим sha как «удаленный», что означает, что он все еще не существует. Вы должны пойти на коммит до этого, чтобы получить его обратно.
— tandrewnichols

6
@tandrewnichols, что просто означает, что вы используете неверный коммит SHA - вы хотите коммит для той версии файла, которую вы хотите ... которая, вероятно, не та версия, в которой файл был удален.
— Янтарь

6
@Amber и коммит, который вы хотите, вероятно, самый последний, до того как он был удален, отсюда и этот ответ.
— Сэм Холдер

1
@AlexR: <SHA>~1должно работать так же, без необходимости заключать его в кавычки.
— CodeManX

37

Предположим, вы хотите восстановить файл с именем MyFile, но не знаете его путь (или его расширение):

Prelim .: Избегайте путаницы, перейдя к корню git

Нетривиальный проект может иметь несколько каталогов с одинаковыми или одинаковыми именами.

> cd <project-root>
  1. Найди полный путь

    git log --diff-filter = D --summary | grep удалить | grep MyFile

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

full/path/to/MyFile.js путь и файл, который вы ищете.

  1. Определите все коммиты, которые повлияли на этот файл

    git log --oneline --follow - полный / путь / к / 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. Оформить заказ

Если вы выберете первый в списке коммит (последний в хронологическом порядке, здесь bd8374c), файл не будет найден, так как он был удален в этом коммите.

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

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

Просто выберите предыдущий (добавить каретку) коммит:

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

3
Это намного яснее, чем принятый ответ
— Пуян Ходабахш

для консоли Windows (cmd), используйте find вместо grep в шаге 2: git log --diff-filter=D --summary | find "delete" | find "MyFile"И шаг 3 , обратите внимание на кавычки вокруг хеша:git checkout "bd8374c^" -- full/path/to/MyFile.js
— user5542121

30

@ Янтарь дал правильный ответ! Еще одно дополнение, если вы не знаете точный путь к файлу, вы можете использовать подстановочные знаки! Это сработало для меня.

git log --all -- **/thefile.*

4
@PedroMorteRolo Хм. Я не знаю, что я думаю о копировании существующего ответа в голосующий сверху: / Этот ответ тоже был полезен сам по себе; upvote, возможно, было достаточно?
— Clément

1
Это не находит файл, если он находится в корне проекта (протестировано в Cygwin).
— Вортварт

19

Ниже приведена простая команда, в которой пользователь dev или git может передать имя удаленного файла из корневого каталога репозитория и получить историю:

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

Если кто-нибудь, может улучшить команду, пожалуйста, сделайте.


1
Круто, спасибо! Похоже, мой файл вообще никогда не существовал, но это отдельная проблема, гораздо более

убедитесь, что вы запускаете это из корневого каталога репозитория, если ваш файл кажется «отсутствующим»
— samaspin

Спасибо @samaspin обновил ответ.
— Джейсон

18

Попробуйте использовать одно из средств просмотра, например, gitkчтобы вы могли просмотреть историю, чтобы найти этот наполовину запомненный файл. (используйте gitk --allпри необходимости для всех филиалов)


4
Этот --allвариант важен как для вашего ответа, так и для принятого ответа.
— варочные панели

3
Просмотр истории займет у большинства проектов необычайно много времени.
— mikemaccana

5

Резюме:

  1. Шаг 1

Вы ищете полный путь к файлу в истории удаленных файлов. git log --diff-filter=D --summary | grep filename

  1. Шаг 2

Вы восстанавливаете свой файл из коммита до того, как он был удален

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.